Merge master.kernel.org:/home/rmk/linux-2.6-arm

* master.kernel.org:/home/rmk/linux-2.6-arm:
  [ARM] 3424/2: ixp23xx: fix uncompress.h for recent CRLF decompressor change
  [ARM] 3434/1: pxa i2s amsl define
  [ARM] 3425/1: xsc3: need to include pgtable-hwdef.h
  [ARM] Allow un-muxed syscalls to be available for everyone
  [ARM] 3420/1: Missing clobber in example code
  [ARM] nommu: fixups for the exception vectors
  [ARM] nommu: add nommu specific Kconfig and MMUEXT variable in Makefile
  [ARM] nommu: start-up code
  [ARM] nommu: MPU support in boot/compressed/head.S
diff --git a/CREDITS b/CREDITS
index c6d69bf..0bf31ea 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1127,8 +1127,10 @@
 S: USA
 
 N: Philip Gladstone
-E: philip@raptor.com
+E: philip@gladstonefamily.net
 D: Kernel / timekeeping stuff
+S: Carlisle, MA 01741
+S: USA
   
 N: Jan-Benedict Glaw
 E: jbglaw@lug-owl.de
@@ -3741,10 +3743,11 @@
 D: Miscellaneous kernel fixes
 
 N: Alessandro Zummo
-E: azummo@ita.flashnet.it
-W: http://freepage.logicom.it/azummo/
+E: a.zummo@towertech.it
 D: CMI8330 support is sb_card.c
 D: ISAPnP fixes in sb_card.c
+D: ZyXEL omni.net lcd plus driver
+D: RTC subsystem
 S: Italy
 
 N: Marc Zyngier
diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
index 6845574..ee4bb73 100644
--- a/Documentation/DMA-mapping.txt
+++ b/Documentation/DMA-mapping.txt
@@ -199,6 +199,8 @@
 		       "mydev: 24-bit DMA addressing not available.\n");
 		goto ignore_this_device;
 	}
+[Better use DMA_24BIT_MASK instead of 0x00ffffff.
+See linux/include/dma-mapping.h for reference.]
 
 When pci_set_dma_mask() is successful, and returns zero, the PCI layer
 saves away this mask you have provided.  The PCI layer will use this
diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
index d260d92..5bcbb6e 100644
--- a/Documentation/DocBook/libata.tmpl
+++ b/Documentation/DocBook/libata.tmpl
@@ -120,14 +120,27 @@
 	<programlisting>
 void (*set_piomode) (struct ata_port *, struct ata_device *);
 void (*set_dmamode) (struct ata_port *, struct ata_device *);
-void (*post_set_mode) (struct ata_port *ap);
+void (*post_set_mode) (struct ata_port *);
+unsigned int (*mode_filter) (struct ata_port *, struct ata_device *, unsigned int);
 	</programlisting>
 
 	<para>
 	Hooks called prior to the issue of SET FEATURES - XFER MODE
-	command.  dev->pio_mode is guaranteed to be valid when
-	->set_piomode() is called, and dev->dma_mode is guaranteed to be
-	valid when ->set_dmamode() is called.  ->post_set_mode() is
+	command.  The optional ->mode_filter() hook is called when libata
+	has built a mask of the possible modes. This is passed to the 
+	->mode_filter() function which should return a mask of valid modes
+	after filtering those unsuitable due to hardware limits. It is not
+	valid to use this interface to add modes.
+	</para>
+	<para>
+	dev->pio_mode and dev->dma_mode are guaranteed to be valid when
+	->set_piomode() and when ->set_dmamode() is called. The timings for
+	any other drive sharing the cable will also be valid at this point.
+	That is the library records the decisions for the modes of each
+	drive on a channel before it attempts to set any of them.
+	</para>
+	<para>
+	->post_set_mode() is
 	called unconditionally, after the SET FEATURES - XFER MODE
 	command completes successfully.
 	</para>
@@ -230,6 +243,32 @@
 
 	</sect2>
 
+	<sect2><title>Private tuning method</title>
+	<programlisting>
+void (*set_mode) (struct ata_port *ap);
+	</programlisting>
+
+	<para>
+	By default libata performs drive and controller tuning in
+	accordance with the ATA timing rules and also applies blacklists
+	and cable limits. Some controllers need special handling and have
+	custom tuning rules, typically raid controllers that use ATA
+	commands but do not actually do drive timing.
+	</para>
+
+	<warning>
+	<para>
+	This hook should not be used to replace the standard controller
+	tuning logic when a controller has quirks. Replacing the default
+	tuning logic in that case would bypass handling for drive and
+	bridge quirks that may be important to data reliability. If a
+	controller needs to filter the mode selection it should use the
+	mode_filter hook instead.
+	</para>
+	</warning>
+
+	</sect2>
+
 	<sect2><title>Reset ATA bus</title>
 	<programlisting>
 void (*phy_reset) (struct ata_port *ap);
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index b4ea51a..07cb93b 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -605,7 +605,7 @@
 	{
 		int cpu;
 
-		for_each_cpu(cpu)
+		for_each_possible_cpu(cpu)
 			run_on(cpu);
 	}
 
diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
index 8e63831..f989a9e 100644
--- a/Documentation/block/biodoc.txt
+++ b/Documentation/block/biodoc.txt
@@ -132,8 +132,18 @@
 		limit. No highmem default.
 
 	blk_queue_max_sectors(q, max_sectors)
-		Maximum size request you can handle in units of 512 byte
-		sectors. 255 default.
+		Sets two variables that limit the size of the request.
+
+		- The request queue's max_sectors, which is a soft size in
+		in units of 512 byte sectors, and could be dynamically varied
+		by the core kernel.
+
+		- The request queue's max_hw_sectors, which is a hard limit
+		and reflects the maximum size request a driver can handle
+		in units of 512 byte sectors.
+
+		The default for both max_sectors and max_hw_sectors is
+		255. The upper limit of max_sectors is 1024.
 
 	blk_queue_max_phys_segments(q, max_segments)
 		Maximum physical segments you can handle in a request. 128
diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt
index 4ae41888..53245c4 100644
--- a/Documentation/cachetlb.txt
+++ b/Documentation/cachetlb.txt
@@ -362,6 +362,27 @@
 	likely that you will need to flush the instruction cache
 	for copy_to_user_page().
 
+  void flush_anon_page(struct page *page, unsigned long vmaddr)
+  	When the kernel needs to access the contents of an anonymous
+	page, it calls this function (currently only
+	get_user_pages()).  Note: flush_dcache_page() deliberately
+	doesn't work for an anonymous page.  The default
+	implementation is a nop (and should remain so for all coherent
+	architectures).  For incoherent architectures, it should flush
+	the cache of the page at vmaddr in the current user process.
+
+  void flush_kernel_dcache_page(struct page *page)
+	When the kernel needs to modify a user page is has obtained
+	with kmap, it calls this function after all modifications are
+	complete (but before kunmapping it) to bring the underlying
+	page up to date.  It is assumed here that the user has no
+	incoherent cached copies (i.e. the original page was obtained
+	from a mechanism like get_user_pages()).  The default
+	implementation is a nop and should remain so on all coherent
+	architectures.  On incoherent architectures, this should flush
+	the kernel cache for page (using page_address(page)).
+
+
   void flush_icache_range(unsigned long start, unsigned long end)
   	When the kernel stores into addresses that it will execute
 	out of (eg when loading modules), this function is called.
diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
index 57a09f9..1bcf699 100644
--- a/Documentation/cpu-hotplug.txt
+++ b/Documentation/cpu-hotplug.txt
@@ -97,13 +97,13 @@
 
 You really dont need to manipulate any of the system cpu maps. They should
 be read-only for most use. When setting up per-cpu resources almost always use
-cpu_possible_map/for_each_cpu() to iterate.
+cpu_possible_map/for_each_possible_cpu() to iterate.
 
 Never use anything other than cpumask_t to represent bitmap of CPUs.
 
 #include <linux/cpumask.h>
 
-for_each_cpu              - Iterate over cpu_possible_map
+for_each_possible_cpu     - Iterate over cpu_possible_map
 for_each_online_cpu       - Iterate over cpu_online_map
 for_each_present_cpu      - Iterate over cpu_present_map
 for_each_cpu_mask(x,mask) - Iterate over some random collection of cpu mask.
diff --git a/Documentation/cputopology.txt b/Documentation/cputopology.txt
index ff280e2..2b28e9e 100644
--- a/Documentation/cputopology.txt
+++ b/Documentation/cputopology.txt
@@ -1,5 +1,5 @@
 
-Export cpu topology info by sysfs. Items (attributes) are similar
+Export cpu topology info via sysfs. Items (attributes) are similar
 to /proc/cpuinfo.
 
 1) /sys/devices/system/cpu/cpuX/topology/physical_package_id:
@@ -12,7 +12,7 @@
 represent the thread siblings to cpu X in the same physical package;
 
 To implement it in an architecture-neutral way, a new source file,
-driver/base/topology.c, is to export the 5 attributes.
+drivers/base/topology.c, is to export the 4 attributes.
 
 If one architecture wants to support this feature, it just needs to
 implement 4 defines, typically in file include/asm-XXX/topology.h.
diff --git a/Documentation/drivers/edac/edac.txt b/Documentation/drivers/edac/edac.txt
index d37191f..70d96a6 100644
--- a/Documentation/drivers/edac/edac.txt
+++ b/Documentation/drivers/edac/edac.txt
@@ -21,7 +21,7 @@
 
 Detecting CE events, then harvesting those events and reporting them,
 CAN be a predictor of future UE events.  With CE events, the system can
-continue to operate, but with less safety. Preventive maintainence and
+continue to operate, but with less safety. Preventive maintenance and
 proactive part replacement of memory DIMMs exhibiting CEs can reduce
 the likelihood of the dreaded UE events and system 'panics'.
 
@@ -29,13 +29,13 @@
 In addition, PCI Bus Parity and SERR Errors are scanned for on PCI devices
 in order to determine if errors are occurring on data transfers.
 The presence of PCI Parity errors must be examined with a grain of salt.
-There are several addin adapters that do NOT follow the PCI specification
+There are several add-in adapters that do NOT follow the PCI specification
 with regards to Parity generation and reporting. The specification says
 the vendor should tie the parity status bits to 0 if they do not intend
 to generate parity.  Some vendors do not do this, and thus the parity bit
 can "float" giving false positives.
 
-The PCI Parity EDAC device has the ability to "skip" known flakey
+The PCI Parity EDAC device has the ability to "skip" known flaky
 cards during the parity scan. These are set by the parity "blacklist"
 interface in the sysfs for PCI Parity. (See the PCI section in the sysfs
 section below.) There is also a parity "whitelist" which is used as
@@ -101,7 +101,7 @@
 
 First a background on the memory controller's model abstracted in EDAC.
 Each mc device controls a set of DIMM memory modules. These modules are
-layed out in a Chip-Select Row (csrowX) and Channel table (chX). There can
+laid out in a Chip-Select Row (csrowX) and Channel table (chX). There can
 be multiple csrows and two channels.
 
 Memory controllers allow for several csrows, with 8 csrows being a typical value.
@@ -131,7 +131,7 @@
 	DIMM_B1
 
 Labels for these slots are usually silk screened on the motherboard. Slots
-labeled 'A' are channel 0 in this example. Slots labled 'B'
+labeled 'A' are channel 0 in this example. Slots labeled 'B'
 are channel 1. Notice that there are two csrows possible on a
 physical DIMM. These csrows are allocated their csrow assignment
 based on the slot into which the memory DIMM is placed. Thus, when 1 DIMM
@@ -140,7 +140,7 @@
 Memory DIMMs come single or dual "ranked". A rank is a populated csrow.
 Thus, 2 single ranked DIMMs, placed in slots DIMM_A0 and DIMM_B0 above
 will have 1 csrow, csrow0. csrow1 will be empty. On the other hand,
-when 2 dual ranked DIMMs are similiaryly placed, then both csrow0 and
+when 2 dual ranked DIMMs are similarly placed, then both csrow0 and
 csrow1 will be populated. The pattern repeats itself for csrow2 and
 csrow3.
 
@@ -246,7 +246,7 @@
 
 	'mc_version'
 
-	The EDAC CORE modules's version and compile date are shown here to
+	The EDAC CORE module's version and compile date are shown here to
 	indicate what EDAC is running.
 
 
@@ -423,7 +423,7 @@
 	'size_mb'
 
 	This attribute file displays, in count of megabytes, of memory
-	that this csrow contatins.
+	that this csrow contains.
 
 
 Memory Type attribute file:
@@ -557,7 +557,7 @@
 for any parity error regardless of whether Parity is enabled on the
 device.  (The spec indicates parity is generated in some cases).
 On Header Type 01 bridges, the secondary status register is also
-looked at to see if parity ocurred on the bus on the other side of
+looked at to see if parity occurred on the bus on the other side of
 the bridge.
 
 
@@ -588,7 +588,7 @@
 	'panic_on_pci_parity'
 
 
-	This control files enables or disables panic'ing when a parity
+	This control files enables or disables panicking when a parity
 	error has been detected.
 
 
@@ -616,12 +616,12 @@
 
 	This control file allows for an explicit list of PCI devices to be
 	scanned for parity errors. Only devices found on this list will
-	be examined.  The list is a line of hexadecimel VENDOR and DEVICE
+	be examined.  The list is a line of hexadecimal VENDOR and DEVICE
 	ID tuples:
 
 	1022:7450,1434:16a6
 
-	One or more can be inserted, seperated by a comma.
+	One or more can be inserted, separated by a comma.
 
 	To write the above list doing the following as one command line:
 
@@ -639,11 +639,11 @@
 
 	This control file allows for a list of PCI devices to be
 	skipped for scanning.
-	The list is a line of hexadecimel VENDOR and DEVICE ID tuples:
+	The list is a line of hexadecimal VENDOR and DEVICE ID tuples:
 
 	1022:7450,1434:16a6
 
-	One or more can be inserted, seperated by a comma.
+	One or more can be inserted, separated by a comma.
 
 	To write the above list doing the following as one command line:
 
@@ -651,14 +651,14 @@
 		> /sys/devices/system/edac/pci/pci_parity_blacklist
 
 
-	To display what the whitelist current contatins,
+	To display what the whitelist currently contains,
 	simply 'cat' the same file.
 
 =======================================================================
 
 PCI Vendor and Devices IDs can be obtained with the lspci command. Using
 the -n option lspci will display the vendor and device IDs. The system
-adminstrator will have to determine which devices should be scanned or
+administrator will have to determine which devices should be scanned or
 skipped.
 
 
@@ -669,5 +669,5 @@
 
 	echo > /sys/devices/system/edac/pci/pci_parity_whitelist
 
-and any previous blacklist will be utililzed.
+and any previous blacklist will be utilized.
 
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 495858b..59d0c74 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -127,13 +127,6 @@
 
 ---------------------------
 
-What:	EXPORT_SYMBOL(lookup_hash)
-When:	January 2006
-Why:	Too low-level interface.  Use lookup_one_len or lookup_create instead.
-Who:	Christoph Hellwig <hch@lst.de>
-
----------------------------
-
 What:	CONFIG_FORCED_INLINING
 When:	June 2006
 Why:	Config option is there to see if gcc is good enough. (in january
@@ -241,3 +234,15 @@
 Who:	Greg Kroah-Hartman <gregkh@suse.de>
 
 ---------------------------
+
+What:	find_trylock_page
+When:	January 2007
+Why:	The interface no longer has any callers left in the kernel. It
+	is an odd interface (compared with other find_*_page functions), in
+	that it does not take a refcount to the page, only the page lock.
+	It should be replaced with find_get_page or find_lock_page if possible.
+	This feature removal can be reevaluated if users of the interface
+	cannot cleanly use something else.
+Who:	Nick Piggin <npiggin@suse.de>
+
+---------------------------
diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX
index 74052d2..66fdc07 100644
--- a/Documentation/filesystems/00-INDEX
+++ b/Documentation/filesystems/00-INDEX
@@ -1,27 +1,47 @@
 00-INDEX
 	- this file (info on some of the filesystems supported by linux).
+Exporting
+	- explanation of how to make filesystems exportable.
 Locking
 	- info on locking rules as they pertain to Linux VFS.
 adfs.txt
 	- info and mount options for the Acorn Advanced Disc Filing System.
+afs.txt
+	- info and examples for the distributed AFS (Andrew File System) fs.
 affs.txt
 	- info and mount options for the Amiga Fast File System.
+automount-support.txt
+	- information about filesystem automount support.
+befs.txt
+	- information about the BeOS filesystem for Linux.
 bfs.txt
 	- info for the SCO UnixWare Boot Filesystem (BFS).
 cifs.txt
-	- description of the CIFS filesystem
+	- description of the CIFS filesystem.
 coda.txt
 	- description of the CODA filesystem.
 configfs/
 	- directory containing configfs documentation and example code.
 cramfs.txt
-	- info on the cram filesystem for small storage (ROMs etc)
+	- info on the cram filesystem for small storage (ROMs etc).
+dentry-locking.txt
+	- info on the RCU-based dcache locking model.
 devfs/
 	- directory containing devfs documentation.
+directory-locking
+	- info about the locking scheme used for directory operations.
 dlmfs.txt
 	- info on the userspace interface to the OCFS2 DLM.
 ext2.txt
 	- info, mount options and specifications for the Ext2 filesystem.
+ext3.txt
+	- info, mount options and specifications for the Ext3 filesystem.
+files.txt
+	- info on file management in the Linux kernel.
+fuse.txt
+	- info on the Filesystem in User SpacE including mount options.
+hfs.txt
+	- info on the Macintosh HFS Filesystem for Linux.
 hpfs.txt
 	- info and mount options for the OS/2 HPFS.
 isofs.txt
@@ -32,23 +52,43 @@
 	- info on Novell Netware(tm) filesystem using NCP protocol.
 ntfs.txt
 	- info and mount options for the NTFS filesystem (Windows NT).
-proc.txt
-	- info on Linux's /proc filesystem.
 ocfs2.txt
 	- info and mount options for the OCFS2 clustered filesystem.
+porting
+	- various information on filesystem porting.
+proc.txt
+	- info on Linux's /proc filesystem.
+ramfs-rootfs-initramfs.txt
+	- info on the 'in memory' filesystems ramfs, rootfs and initramfs.
+reiser4.txt
+	- info on the Reiser4 filesystem based on dancing tree algorithms.
+relayfs.txt
+	- info on relayfs, for efficient streaming from kernel to user space.
 romfs.txt
-	- Description of the ROMFS filesystem.
+	- description of the ROMFS filesystem.
 smbfs.txt
-	- info on using filesystems with the SMB protocol (Windows 3.11 and NT)
+	- info on using filesystems with the SMB protocol (Win 3.11 and NT).
+spufs.txt
+	- info and mount options for the SPU filesystem used on Cell.
+sysfs-pci.txt
+	- info on accessing PCI device resources through sysfs.
+sysfs.txt
+	- info on sysfs, a ram-based filesystem for exporting kernel objects.
 sysv-fs.txt
 	- info on the SystemV/V7/Xenix/Coherent filesystem.
+tmpfs.txt
+	- info on tmpfs, a filesystem that holds all files in virtual memory.
 udf.txt
 	- info and mount options for the UDF filesystem.
 ufs.txt
 	- info on the ufs filesystem.
+v9fs.txt
+	- v9fs is a Unix implementation of the Plan 9 9p remote fs protocol.
 vfat.txt
 	- info on using the VFAT filesystem used in Windows NT and Windows 95
 vfs.txt
-	- Overview of the Virtual File System
+	- overview of the Virtual File System
 xfs.txt
 	- info and mount options for the XFS filesystem.
+xip.txt
+	- info on execute-in-place for file mappings.
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
index aa7ba00..171a44e 100644
--- a/Documentation/ioctl-number.txt
+++ b/Documentation/ioctl-number.txt
@@ -78,8 +78,6 @@
 '#'	00-3F	IEEE 1394 Subsystem	Block for the entire subsystem
 '1'	00-1F	<linux/timepps.h>	PPS kit from Ulrich Windl
 					<ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
-'6'	00-10	<asm-i386/processor.h>	Intel IA32 microcode update driver
-					<mailto:tigran@veritas.com>
 '8'	all				SNP8023 advanced NIC card
 					<mailto:mcr@solidum.com>
 'A'	00-1F	linux/apm_bios.h
diff --git a/Documentation/leds-class.txt b/Documentation/leds-class.txt
new file mode 100644
index 0000000..8c35c04
--- /dev/null
+++ b/Documentation/leds-class.txt
@@ -0,0 +1,71 @@
+LED handling under Linux
+========================
+
+If you're reading this and thinking about keyboard leds, these are
+handled by the input subsystem and the led class is *not* needed.
+
+In its simplest form, the LED class just allows control of LEDs from
+userspace. LEDs appear in /sys/class/leds/. The brightness file will
+set the brightness of the LED (taking a value 0-255). Most LEDs don't
+have hardware brightness support so will just be turned on for non-zero
+brightness settings.
+
+The class also introduces the optional concept of an LED trigger. A trigger
+is a kernel based source of led events. Triggers can either be simple or
+complex. A simple trigger isn't configurable and is designed to slot into
+existing subsystems with minimal additional code. Examples are the ide-disk,
+nand-disk and sharpsl-charge triggers. With led triggers disabled, the code
+optimises away.
+
+Complex triggers whilst available to all LEDs have LED specific
+parameters and work on a per LED basis. The timer trigger is an example.
+
+You can change triggers in a similar manner to the way an IO scheduler
+is chosen (via /sys/class/leds/<device>/trigger). Trigger specific
+parameters can appear in /sys/class/leds/<device> once a given trigger is
+selected.
+
+
+Design Philosophy
+=================
+
+The underlying design philosophy is simplicity. LEDs are simple devices
+and the aim is to keep a small amount of code giving as much functionality
+as possible.  Please keep this in mind when suggesting enhancements.
+
+
+LED Device Naming
+=================
+
+Is currently of the form:
+
+"devicename:colour"
+
+There have been calls for LED properties such as colour to be exported as
+individual led class attributes. As a solution which doesn't incur as much
+overhead, I suggest these become part of the device name. The naming scheme
+above leaves scope for further attributes should they be needed.
+
+
+Known Issues
+============
+
+The LED Trigger core cannot be a module as the simple trigger functions
+would cause nightmare dependency issues. I see this as a minor issue
+compared to the benefits the simple trigger functionality brings. The
+rest of the LED subsystem can be modular.
+
+Some leds can be programmed to flash in hardware. As this isn't a generic
+LED device property, this should be exported as a device specific sysfs
+attribute rather than part of the class if this functionality is required.
+
+
+Future Development
+==================
+
+At the moment, a trigger can't be created specifically for a single LED.
+There are a number of cases where a trigger might only be mappable to a
+particular LED (ACPI?). The addition of triggers provided by the LED driver
+should cover this option and be possible to add without breaking the
+current interface.
+
diff --git a/Documentation/m68k/README.buddha b/Documentation/m68k/README.buddha
index bf802ff..ef484a7 100644
--- a/Documentation/m68k/README.buddha
+++ b/Documentation/m68k/README.buddha
@@ -29,7 +29,7 @@
 $48, while it doesn't matter how often you're writing to $4a
 as  long as $48 is not touched.  After $48 has been written,
 the  whole card disappears from $e8 and is mapped to the new
-address just written.  Make shure $4a is written before $48,
+address just written.  Make sure $4a is written before $48,
 otherwise your chance is only 1:16 to find the board :-).
 
 The local memory-map is even active when mapped to $e8:
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
new file mode 100644
index 0000000..f855031
--- /dev/null
+++ b/Documentation/memory-barriers.txt
@@ -0,0 +1,1913 @@
+			 ============================
+			 LINUX KERNEL MEMORY BARRIERS
+			 ============================
+
+By: David Howells <dhowells@redhat.com>
+
+Contents:
+
+ (*) Abstract memory access model.
+
+     - Device operations.
+     - Guarantees.
+
+ (*) What are memory barriers?
+
+     - Varieties of memory barrier.
+     - What may not be assumed about memory barriers?
+     - Data dependency barriers.
+     - Control dependencies.
+     - SMP barrier pairing.
+     - Examples of memory barrier sequences.
+
+ (*) Explicit kernel barriers.
+
+     - Compiler barrier.
+     - The CPU memory barriers.
+     - MMIO write barrier.
+
+ (*) Implicit kernel memory barriers.
+
+     - Locking functions.
+     - Interrupt disabling functions.
+     - Miscellaneous functions.
+
+ (*) Inter-CPU locking barrier effects.
+
+     - Locks vs memory accesses.
+     - Locks vs I/O accesses.
+
+ (*) Where are memory barriers needed?
+
+     - Interprocessor interaction.
+     - Atomic operations.
+     - Accessing devices.
+     - Interrupts.
+
+ (*) Kernel I/O barrier effects.
+
+ (*) Assumed minimum execution ordering model.
+
+ (*) The effects of the cpu cache.
+
+     - Cache coherency.
+     - Cache coherency vs DMA.
+     - Cache coherency vs MMIO.
+
+ (*) The things CPUs get up to.
+
+     - And then there's the Alpha.
+
+ (*) References.
+
+
+============================
+ABSTRACT MEMORY ACCESS MODEL
+============================
+
+Consider the following abstract model of the system:
+
+		            :                :
+		            :                :
+		            :                :
+		+-------+   :   +--------+   :   +-------+
+		|       |   :   |        |   :   |       |
+		|       |   :   |        |   :   |       |
+		| CPU 1 |<----->| Memory |<----->| CPU 2 |
+		|       |   :   |        |   :   |       |
+		|       |   :   |        |   :   |       |
+		+-------+   :   +--------+   :   +-------+
+		    ^       :       ^        :       ^
+		    |       :       |        :       |
+		    |       :       |        :       |
+		    |       :       v        :       |
+		    |       :   +--------+   :       |
+		    |       :   |        |   :       |
+		    |       :   |        |   :       |
+		    +---------->| Device |<----------+
+		            :   |        |   :
+		            :   |        |   :
+		            :   +--------+   :
+		            :                :
+
+Each CPU executes a program that generates memory access operations.  In the
+abstract CPU, memory operation ordering is very relaxed, and a CPU may actually
+perform the memory operations in any order it likes, provided program causality
+appears to be maintained.  Similarly, the compiler may also arrange the
+instructions it emits in any order it likes, provided it doesn't affect the
+apparent operation of the program.
+
+So in the above diagram, the effects of the memory operations performed by a
+CPU are perceived by the rest of the system as the operations cross the
+interface between the CPU and rest of the system (the dotted lines).
+
+
+For example, consider the following sequence of events:
+
+	CPU 1		CPU 2
+	===============	===============
+	{ A == 1; B == 2 }
+	A = 3;		x = A;
+	B = 4;		y = B;
+
+The set of accesses as seen by the memory system in the middle can be arranged
+in 24 different combinations:
+
+	STORE A=3,	STORE B=4,	x=LOAD A->3,	y=LOAD B->4
+	STORE A=3,	STORE B=4,	y=LOAD B->4,	x=LOAD A->3
+	STORE A=3,	x=LOAD A->3,	STORE B=4,	y=LOAD B->4
+	STORE A=3,	x=LOAD A->3,	y=LOAD B->2,	STORE B=4
+	STORE A=3,	y=LOAD B->2,	STORE B=4,	x=LOAD A->3
+	STORE A=3,	y=LOAD B->2,	x=LOAD A->3,	STORE B=4
+	STORE B=4,	STORE A=3,	x=LOAD A->3,	y=LOAD B->4
+	STORE B=4, ...
+	...
+
+and can thus result in four different combinations of values:
+
+	x == 1, y == 2
+	x == 1, y == 4
+	x == 3, y == 2
+	x == 3, y == 4
+
+
+Furthermore, the stores committed by a CPU to the memory system may not be
+perceived by the loads made by another CPU in the same order as the stores were
+committed.
+
+
+As a further example, consider this sequence of events:
+
+	CPU 1		CPU 2
+	===============	===============
+	{ A == 1, B == 2, C = 3, P == &A, Q == &C }
+	B = 4;		Q = P;
+	P = &B		D = *Q;
+
+There is an obvious data dependency here, as the value loaded into D depends on
+the address retrieved from P by CPU 2.  At the end of the sequence, any of the
+following results are possible:
+
+	(Q == &A) and (D == 1)
+	(Q == &B) and (D == 2)
+	(Q == &B) and (D == 4)
+
+Note that CPU 2 will never try and load C into D because the CPU will load P
+into Q before issuing the load of *Q.
+
+
+DEVICE OPERATIONS
+-----------------
+
+Some devices present their control interfaces as collections of memory
+locations, but the order in which the control registers are accessed is very
+important.  For instance, imagine an ethernet card with a set of internal
+registers that are accessed through an address port register (A) and a data
+port register (D).  To read internal register 5, the following code might then
+be used:
+
+	*A = 5;
+	x = *D;
+
+but this might show up as either of the following two sequences:
+
+	STORE *A = 5, x = LOAD *D
+	x = LOAD *D, STORE *A = 5
+
+the second of which will almost certainly result in a malfunction, since it set
+the address _after_ attempting to read the register.
+
+
+GUARANTEES
+----------
+
+There are some minimal guarantees that may be expected of a CPU:
+
+ (*) On any given CPU, dependent memory accesses will be issued in order, with
+     respect to itself.  This means that for:
+
+	Q = P; D = *Q;
+
+     the CPU will issue the following memory operations:
+
+	Q = LOAD P, D = LOAD *Q
+
+     and always in that order.
+
+ (*) Overlapping loads and stores within a particular CPU will appear to be
+     ordered within that CPU.  This means that for:
+
+	a = *X; *X = b;
+
+     the CPU will only issue the following sequence of memory operations:
+
+	a = LOAD *X, STORE *X = b
+
+     And for:
+
+	*X = c; d = *X;
+
+     the CPU will only issue:
+
+	STORE *X = c, d = LOAD *X
+
+     (Loads and stores overlap if they are targetted at overlapping pieces of
+     memory).
+
+And there are a number of things that _must_ or _must_not_ be assumed:
+
+ (*) It _must_not_ be assumed that independent loads and stores will be issued
+     in the order given.  This means that for:
+
+	X = *A; Y = *B; *D = Z;
+
+     we may get any of the following sequences:
+
+	X = LOAD *A,  Y = LOAD *B,  STORE *D = Z
+	X = LOAD *A,  STORE *D = Z, Y = LOAD *B
+	Y = LOAD *B,  X = LOAD *A,  STORE *D = Z
+	Y = LOAD *B,  STORE *D = Z, X = LOAD *A
+	STORE *D = Z, X = LOAD *A,  Y = LOAD *B
+	STORE *D = Z, Y = LOAD *B,  X = LOAD *A
+
+ (*) It _must_ be assumed that overlapping memory accesses may be merged or
+     discarded.  This means that for:
+
+	X = *A; Y = *(A + 4);
+
+     we may get any one of the following sequences:
+
+	X = LOAD *A; Y = LOAD *(A + 4);
+	Y = LOAD *(A + 4); X = LOAD *A;
+	{X, Y} = LOAD {*A, *(A + 4) };
+
+     And for:
+
+	*A = X; Y = *A;
+
+     we may get either of:
+
+	STORE *A = X; Y = LOAD *A;
+	STORE *A = Y;
+
+
+=========================
+WHAT ARE MEMORY BARRIERS?
+=========================
+
+As can be seen above, independent memory operations are effectively performed
+in random order, but this can be a problem for CPU-CPU interaction and for I/O.
+What is required is some way of intervening to instruct the compiler and the
+CPU to restrict the order.
+
+Memory barriers are such interventions.  They impose a perceived partial
+ordering between the memory operations specified on either side of the barrier.
+They request that the sequence of memory events generated appears to other
+parts of the system as if the barrier is effective on that CPU.
+
+
+VARIETIES OF MEMORY BARRIER
+---------------------------
+
+Memory barriers come in four basic varieties:
+
+ (1) Write (or store) memory barriers.
+
+     A write memory barrier gives a guarantee that all the STORE operations
+     specified before the barrier will appear to happen before all the STORE
+     operations specified after the barrier with respect to the other
+     components of the system.
+
+     A write barrier is a partial ordering on stores only; it is not required
+     to have any effect on loads.
+
+     A CPU can be viewed as as commiting a sequence of store operations to the
+     memory system as time progresses.  All stores before a write barrier will
+     occur in the sequence _before_ all the stores after the write barrier.
+
+     [!] Note that write barriers should normally be paired with read or data
+     dependency barriers; see the "SMP barrier pairing" subsection.
+
+
+ (2) Data dependency barriers.
+
+     A data dependency barrier is a weaker form of read barrier.  In the case
+     where two loads are performed such that the second depends on the result
+     of the first (eg: the first load retrieves the address to which the second
+     load will be directed), a data dependency barrier would be required to
+     make sure that the target of the second load is updated before the address
+     obtained by the first load is accessed.
+
+     A data dependency barrier is a partial ordering on interdependent loads
+     only; it is not required to have any effect on stores, independent loads
+     or overlapping loads.
+
+     As mentioned in (1), the other CPUs in the system can be viewed as
+     committing sequences of stores to the memory system that the CPU being
+     considered can then perceive.  A data dependency barrier issued by the CPU
+     under consideration guarantees that for any load preceding it, if that
+     load touches one of a sequence of stores from another CPU, then by the
+     time the barrier completes, the effects of all the stores prior to that
+     touched by the load will be perceptible to any loads issued after the data
+     dependency barrier.
+
+     See the "Examples of memory barrier sequences" subsection for diagrams
+     showing the ordering constraints.
+
+     [!] Note that the first load really has to have a _data_ dependency and
+     not a control dependency.  If the address for the second load is dependent
+     on the first load, but the dependency is through a conditional rather than
+     actually loading the address itself, then it's a _control_ dependency and
+     a full read barrier or better is required.  See the "Control dependencies"
+     subsection for more information.
+
+     [!] Note that data dependency barriers should normally be paired with
+     write barriers; see the "SMP barrier pairing" subsection.
+
+
+ (3) Read (or load) memory barriers.
+
+     A read barrier is a data dependency barrier plus a guarantee that all the
+     LOAD operations specified before the barrier will appear to happen before
+     all the LOAD operations specified after the barrier with respect to the
+     other components of the system.
+
+     A read barrier is a partial ordering on loads only; it is not required to
+     have any effect on stores.
+
+     Read memory barriers imply data dependency barriers, and so can substitute
+     for them.
+
+     [!] Note that read barriers should normally be paired with write barriers;
+     see the "SMP barrier pairing" subsection.
+
+
+ (4) General memory barriers.
+
+     A general memory barrier is a combination of both a read memory barrier
+     and a write memory barrier.  It is a partial ordering over both loads and
+     stores.
+
+     General memory barriers imply both read and write memory barriers, and so
+     can substitute for either.
+
+
+And a couple of implicit varieties:
+
+ (5) LOCK operations.
+
+     This acts as a one-way permeable barrier.  It guarantees that all memory
+     operations after the LOCK operation will appear to happen after the LOCK
+     operation with respect to the other components of the system.
+
+     Memory operations that occur before a LOCK operation may appear to happen
+     after it completes.
+
+     A LOCK operation should almost always be paired with an UNLOCK operation.
+
+
+ (6) UNLOCK operations.
+
+     This also acts as a one-way permeable barrier.  It guarantees that all
+     memory operations before the UNLOCK operation will appear to happen before
+     the UNLOCK operation with respect to the other components of the system.
+
+     Memory operations that occur after an UNLOCK operation may appear to
+     happen before it completes.
+
+     LOCK and UNLOCK operations are guaranteed to appear with respect to each
+     other strictly in the order specified.
+
+     The use of LOCK and UNLOCK operations generally precludes the need for
+     other sorts of memory barrier (but note the exceptions mentioned in the
+     subsection "MMIO write barrier").
+
+
+Memory barriers are only required where there's a possibility of interaction
+between two CPUs or between a CPU and a device.  If it can be guaranteed that
+there won't be any such interaction in any particular piece of code, then
+memory barriers are unnecessary in that piece of code.
+
+
+Note that these are the _minimum_ guarantees.  Different architectures may give
+more substantial guarantees, but they may _not_ be relied upon outside of arch
+specific code.
+
+
+WHAT MAY NOT BE ASSUMED ABOUT MEMORY BARRIERS?
+----------------------------------------------
+
+There are certain things that the Linux kernel memory barriers do not guarantee:
+
+ (*) There is no guarantee that any of the memory accesses specified before a
+     memory barrier will be _complete_ by the completion of a memory barrier
+     instruction; the barrier can be considered to draw a line in that CPU's
+     access queue that accesses of the appropriate type may not cross.
+
+ (*) There is no guarantee that issuing a memory barrier on one CPU will have
+     any direct effect on another CPU or any other hardware in the system.  The
+     indirect effect will be the order in which the second CPU sees the effects
+     of the first CPU's accesses occur, but see the next point:
+
+ (*) There is no guarantee that the a CPU will see the correct order of effects
+     from a second CPU's accesses, even _if_ the second CPU uses a memory
+     barrier, unless the first CPU _also_ uses a matching memory barrier (see
+     the subsection on "SMP Barrier Pairing").
+
+ (*) There is no guarantee that some intervening piece of off-the-CPU
+     hardware[*] will not reorder the memory accesses.  CPU cache coherency
+     mechanisms should propagate the indirect effects of a memory barrier
+     between CPUs, but might not do so in order.
+
+	[*] For information on bus mastering DMA and coherency please read:
+
+	    Documentation/pci.txt
+	    Documentation/DMA-mapping.txt
+	    Documentation/DMA-API.txt
+
+
+DATA DEPENDENCY BARRIERS
+------------------------
+
+The usage requirements of data dependency barriers are a little subtle, and
+it's not always obvious that they're needed.  To illustrate, consider the
+following sequence of events:
+
+	CPU 1		CPU 2
+	===============	===============
+	{ A == 1, B == 2, C = 3, P == &A, Q == &C }
+	B = 4;
+	<write barrier>
+	P = &B
+			Q = P;
+			D = *Q;
+
+There's a clear data dependency here, and it would seem that by the end of the
+sequence, Q must be either &A or &B, and that:
+
+	(Q == &A) implies (D == 1)
+	(Q == &B) implies (D == 4)
+
+But! CPU 2's perception of P may be updated _before_ its perception of B, thus
+leading to the following situation:
+
+	(Q == &B) and (D == 2) ????
+
+Whilst this may seem like a failure of coherency or causality maintenance, it
+isn't, and this behaviour can be observed on certain real CPUs (such as the DEC
+Alpha).
+
+To deal with this, a data dependency barrier must be inserted between the
+address load and the data load:
+
+	CPU 1		CPU 2
+	===============	===============
+	{ A == 1, B == 2, C = 3, P == &A, Q == &C }
+	B = 4;
+	<write barrier>
+	P = &B
+			Q = P;
+			<data dependency barrier>
+			D = *Q;
+
+This enforces the occurrence of one of the two implications, and prevents the
+third possibility from arising.
+
+[!] Note that this extremely counterintuitive situation arises most easily on
+machines with split caches, so that, for example, one cache bank processes
+even-numbered cache lines and the other bank processes odd-numbered cache
+lines.  The pointer P might be stored in an odd-numbered cache line, and the
+variable B might be stored in an even-numbered cache line.  Then, if the
+even-numbered bank of the reading CPU's cache is extremely busy while the
+odd-numbered bank is idle, one can see the new value of the pointer P (&B),
+but the old value of the variable B (1).
+
+
+Another example of where data dependency barriers might by required is where a
+number is read from memory and then used to calculate the index for an array
+access:
+
+	CPU 1		CPU 2
+	===============	===============
+	{ M[0] == 1, M[1] == 2, M[3] = 3, P == 0, Q == 3 }
+	M[1] = 4;
+	<write barrier>
+	P = 1
+			Q = P;
+			<data dependency barrier>
+			D = M[Q];
+
+
+The data dependency barrier is very important to the RCU system, for example.
+See rcu_dereference() in include/linux/rcupdate.h.  This permits the current
+target of an RCU'd pointer to be replaced with a new modified target, without
+the replacement target appearing to be incompletely initialised.
+
+See also the subsection on "Cache Coherency" for a more thorough example.
+
+
+CONTROL DEPENDENCIES
+--------------------
+
+A control dependency requires a full read memory barrier, not simply a data
+dependency barrier to make it work correctly.  Consider the following bit of
+code:
+
+	q = &a;
+	if (p)
+		q = &b;
+	<data dependency barrier>
+	x = *q;
+
+This will not have the desired effect because there is no actual data
+dependency, but rather a control dependency that the CPU may short-circuit by
+attempting to predict the outcome in advance.  In such a case what's actually
+required is:
+
+	q = &a;
+	if (p)
+		q = &b;
+	<read barrier>
+	x = *q;
+
+
+SMP BARRIER PAIRING
+-------------------
+
+When dealing with CPU-CPU interactions, certain types of memory barrier should
+always be paired.  A lack of appropriate pairing is almost certainly an error.
+
+A write barrier should always be paired with a data dependency barrier or read
+barrier, though a general barrier would also be viable.  Similarly a read
+barrier or a data dependency barrier should always be paired with at least an
+write barrier, though, again, a general barrier is viable:
+
+	CPU 1		CPU 2
+	===============	===============
+	a = 1;
+	<write barrier>
+	b = 2;		x = a;
+			<read barrier>
+			y = b;
+
+Or:
+
+	CPU 1		CPU 2
+	===============	===============================
+	a = 1;
+	<write barrier>
+	b = &a;		x = b;
+			<data dependency barrier>
+			y = *x;
+
+Basically, the read barrier always has to be there, even though it can be of
+the "weaker" type.
+
+
+EXAMPLES OF MEMORY BARRIER SEQUENCES
+------------------------------------
+
+Firstly, write barriers act as a partial orderings on store operations.
+Consider the following sequence of events:
+
+	CPU 1
+	=======================
+	STORE A = 1
+	STORE B = 2
+	STORE C = 3
+	<write barrier>
+	STORE D = 4
+	STORE E = 5
+
+This sequence of events is committed to the memory coherence system in an order
+that the rest of the system might perceive as the unordered set of { STORE A,
+STORE B, STORE C } all occuring before the unordered set of { STORE D, STORE E
+}:
+
+	+-------+       :      :
+	|       |       +------+
+	|       |------>| C=3  |     }     /\
+	|       |  :    +------+     }-----  \  -----> Events perceptible
+	|       |  :    | A=1  |     }        \/       to rest of system
+	|       |  :    +------+     }
+	| CPU 1 |  :    | B=2  |     }
+	|       |       +------+     }
+	|       |   wwwwwwwwwwwwwwww }   <--- At this point the write barrier
+	|       |       +------+     }        requires all stores prior to the
+	|       |  :    | E=5  |     }        barrier to be committed before
+	|       |  :    +------+     }        further stores may be take place.
+	|       |------>| D=4  |     }
+	|       |       +------+
+	+-------+       :      :
+	                   |
+	                   | Sequence in which stores committed to memory system
+	                   | by CPU 1
+	                   V
+
+
+Secondly, data dependency barriers act as a partial orderings on data-dependent
+loads.  Consider the following sequence of events:
+
+	CPU 1			CPU 2
+	=======================	=======================
+	STORE A = 1
+	STORE B = 2
+	<write barrier>
+	STORE C = &B		LOAD X
+	STORE D = 4		LOAD C (gets &B)
+				LOAD *C (reads B)
+
+Without intervention, CPU 2 may perceive the events on CPU 1 in some
+effectively random order, despite the write barrier issued by CPU 1:
+
+	+-------+       :      :                :       :
+	|       |       +------+                +-------+  | Sequence of update
+	|       |------>| B=2  |-----       --->| Y->8  |  | of perception on
+	|       |  :    +------+     \          +-------+  | CPU 2
+	| CPU 1 |  :    | A=1  |      \     --->| C->&Y |  V
+	|       |       +------+       |        +-------+
+	|       |   wwwwwwwwwwwwwwww   |        :       :
+	|       |       +------+       |        :       :
+	|       |  :    | C=&B |---    |        :       :       +-------+
+	|       |  :    +------+   \   |        +-------+       |       |
+	|       |------>| D=4  |    ----------->| C->&B |------>|       |
+	|       |       +------+       |        +-------+       |       |
+	+-------+       :      :       |        :       :       |       |
+	                               |        :       :       |       |
+	                               |        :       :       | CPU 2 |
+	                               |        +-------+       |       |
+	    Apparently incorrect --->  |        | B->7  |------>|       |
+	    perception of B (!)        |        +-------+       |       |
+	                               |        :       :       |       |
+	                               |        +-------+       |       |
+	    The load of X holds --->    \       | X->9  |------>|       |
+	    up the maintenance           \      +-------+       |       |
+	    of coherence of B             ----->| B->2  |       +-------+
+	                                        +-------+
+	                                        :       :
+
+
+In the above example, CPU 2 perceives that B is 7, despite the load of *C
+(which would be B) coming after the the LOAD of C.
+
+If, however, a data dependency barrier were to be placed between the load of C
+and the load of *C (ie: B) on CPU 2, then the following will occur:
+
+	+-------+       :      :                :       :
+	|       |       +------+                +-------+
+	|       |------>| B=2  |-----       --->| Y->8  |
+	|       |  :    +------+     \          +-------+
+	| CPU 1 |  :    | A=1  |      \     --->| C->&Y |
+	|       |       +------+       |        +-------+
+	|       |   wwwwwwwwwwwwwwww   |        :       :
+	|       |       +------+       |        :       :
+	|       |  :    | C=&B |---    |        :       :       +-------+
+	|       |  :    +------+   \   |        +-------+       |       |
+	|       |------>| D=4  |    ----------->| C->&B |------>|       |
+	|       |       +------+       |        +-------+       |       |
+	+-------+       :      :       |        :       :       |       |
+	                               |        :       :       |       |
+	                               |        :       :       | CPU 2 |
+	                               |        +-------+       |       |
+	                                \       | X->9  |------>|       |
+	                                 \      +-------+       |       |
+	                                  ----->| B->2  |       |       |
+	                                        +-------+       |       |
+	     Makes sure all effects --->    ddddddddddddddddd   |       |
+	     prior to the store of C            +-------+       |       |
+	     are perceptible to                 | B->2  |------>|       |
+	     successive loads                   +-------+       |       |
+	                                        :       :       +-------+
+
+
+And thirdly, a read barrier acts as a partial order on loads.  Consider the
+following sequence of events:
+
+	CPU 1			CPU 2
+	=======================	=======================
+	STORE A=1
+	STORE B=2
+	STORE C=3
+	<write barrier>
+	STORE D=4
+	STORE E=5
+				LOAD A
+				LOAD B
+				LOAD C
+				LOAD D
+				LOAD E
+
+Without intervention, CPU 2 may then choose to perceive the events on CPU 1 in
+some effectively random order, despite the write barrier issued by CPU 1:
+
+	+-------+       :      :
+	|       |       +------+
+	|       |------>| C=3  | }
+	|       |  :    +------+ }
+	|       |  :    | A=1  | }
+	|       |  :    +------+ }
+	| CPU 1 |  :    | B=2  | }---
+	|       |       +------+ }   \
+	|       |   wwwwwwwwwwwww}    \
+	|       |       +------+ }     \          :       :       +-------+
+	|       |  :    | E=5  | }      \         +-------+       |       |
+	|       |  :    +------+ }       \      { | C->3  |------>|       |
+	|       |------>| D=4  | }        \     { +-------+    :  |       |
+	|       |       +------+           \    { | E->5  |    :  |       |
+	+-------+       :      :            \   { +-------+    :  |       |
+	                           Transfer  -->{ | A->1  |    :  | CPU 2 |
+	                          from CPU 1    { +-------+    :  |       |
+	                           to CPU 2     { | D->4  |    :  |       |
+	                                        { +-------+    :  |       |
+	                                        { | B->2  |------>|       |
+	                                          +-------+       |       |
+	                                          :       :       +-------+
+
+
+If, however, a read barrier were to be placed between the load of C and the
+load of D on CPU 2, then the partial ordering imposed by CPU 1 will be
+perceived correctly by CPU 2.
+
+	+-------+       :      :
+	|       |       +------+
+	|       |------>| C=3  | }
+	|       |  :    +------+ }
+	|       |  :    | A=1  | }---
+	|       |  :    +------+ }   \
+	| CPU 1 |  :    | B=2  | }    \
+	|       |       +------+       \
+	|       |   wwwwwwwwwwwwwwww    \
+	|       |       +------+         \        :       :       +-------+
+	|       |  :    | E=5  | }        \       +-------+       |       |
+	|       |  :    +------+ }---      \    { | C->3  |------>|       |
+	|       |------>| D=4  | }   \      \   { +-------+    :  |       |
+	|       |       +------+      \      -->{ | B->2  |    :  |       |
+	+-------+       :      :       \        { +-------+    :  |       |
+	                                \       { | A->1  |    :  | CPU 2 |
+	                                 \        +-------+       |       |
+	   At this point the read ---->   \   rrrrrrrrrrrrrrrrr   |       |
+	   barrier causes all effects      \      +-------+       |       |
+	   prior to the storage of C        \   { | E->5  |    :  |       |
+	   to be perceptible to CPU 2        -->{ +-------+    :  |       |
+	                                        { | D->4  |------>|       |
+	                                          +-------+       |       |
+	                                          :       :       +-------+
+
+
+========================
+EXPLICIT KERNEL BARRIERS
+========================
+
+The Linux kernel has a variety of different barriers that act at different
+levels:
+
+  (*) Compiler barrier.
+
+  (*) CPU memory barriers.
+
+  (*) MMIO write barrier.
+
+
+COMPILER BARRIER
+----------------
+
+The Linux kernel has an explicit compiler barrier function that prevents the
+compiler from moving the memory accesses either side of it to the other side:
+
+	barrier();
+
+This a general barrier - lesser varieties of compiler barrier do not exist.
+
+The compiler barrier has no direct effect on the CPU, which may then reorder
+things however it wishes.
+
+
+CPU MEMORY BARRIERS
+-------------------
+
+The Linux kernel has eight basic CPU memory barriers:
+
+	TYPE		MANDATORY		SMP CONDITIONAL
+	===============	=======================	===========================
+	GENERAL		mb()			smp_mb()
+	WRITE		wmb()			smp_wmb()
+	READ		rmb()			smp_rmb()
+	DATA DEPENDENCY	read_barrier_depends()	smp_read_barrier_depends()
+
+
+All CPU memory barriers unconditionally imply compiler barriers.
+
+SMP memory barriers are reduced to compiler barriers on uniprocessor compiled
+systems because it is assumed that a CPU will be appear to be self-consistent,
+and will order overlapping accesses correctly with respect to itself.
+
+[!] Note that SMP memory barriers _must_ be used to control the ordering of
+references to shared memory on SMP systems, though the use of locking instead
+is sufficient.
+
+Mandatory barriers should not be used to control SMP effects, since mandatory
+barriers unnecessarily impose overhead on UP systems. They may, however, be
+used to control MMIO effects on accesses through relaxed memory I/O windows.
+These are required even on non-SMP systems as they affect the order in which
+memory operations appear to a device by prohibiting both the compiler and the
+CPU from reordering them.
+
+
+There are some more advanced barrier functions:
+
+ (*) set_mb(var, value)
+ (*) set_wmb(var, value)
+
+     These assign the value to the variable and then insert at least a write
+     barrier after it, depending on the function.  They aren't guaranteed to
+     insert anything more than a compiler barrier in a UP compilation.
+
+
+ (*) smp_mb__before_atomic_dec();
+ (*) smp_mb__after_atomic_dec();
+ (*) smp_mb__before_atomic_inc();
+ (*) smp_mb__after_atomic_inc();
+
+     These are for use with atomic add, subtract, increment and decrement
+     functions, especially when used for reference counting.  These functions
+     do not imply memory barriers.
+
+     As an example, consider a piece of code that marks an object as being dead
+     and then decrements the object's reference count:
+
+	obj->dead = 1;
+	smp_mb__before_atomic_dec();
+	atomic_dec(&obj->ref_count);
+
+     This makes sure that the death mark on the object is perceived to be set
+     *before* the reference counter is decremented.
+
+     See Documentation/atomic_ops.txt for more information.  See the "Atomic
+     operations" subsection for information on where to use these.
+
+
+ (*) smp_mb__before_clear_bit(void);
+ (*) smp_mb__after_clear_bit(void);
+
+     These are for use similar to the atomic inc/dec barriers.  These are
+     typically used for bitwise unlocking operations, so care must be taken as
+     there are no implicit memory barriers here either.
+
+     Consider implementing an unlock operation of some nature by clearing a
+     locking bit.  The clear_bit() would then need to be barriered like this:
+
+	smp_mb__before_clear_bit();
+	clear_bit( ... );
+
+     This prevents memory operations before the clear leaking to after it.  See
+     the subsection on "Locking Functions" with reference to UNLOCK operation
+     implications.
+
+     See Documentation/atomic_ops.txt for more information.  See the "Atomic
+     operations" subsection for information on where to use these.
+
+
+MMIO WRITE BARRIER
+------------------
+
+The Linux kernel also has a special barrier for use with memory-mapped I/O
+writes:
+
+	mmiowb();
+
+This is a variation on the mandatory write barrier that causes writes to weakly
+ordered I/O regions to be partially ordered.  Its effects may go beyond the
+CPU->Hardware interface and actually affect the hardware at some level.
+
+See the subsection "Locks vs I/O accesses" for more information.
+
+
+===============================
+IMPLICIT KERNEL MEMORY BARRIERS
+===============================
+
+Some of the other functions in the linux kernel imply memory barriers, amongst
+which are locking, scheduling and memory allocation functions.
+
+This specification is a _minimum_ guarantee; any particular architecture may
+provide more substantial guarantees, but these may not be relied upon outside
+of arch specific code.
+
+
+LOCKING FUNCTIONS
+-----------------
+
+The Linux kernel has a number of locking constructs:
+
+ (*) spin locks
+ (*) R/W spin locks
+ (*) mutexes
+ (*) semaphores
+ (*) R/W semaphores
+ (*) RCU
+
+In all cases there are variants on "LOCK" operations and "UNLOCK" operations
+for each construct.  These operations all imply certain barriers:
+
+ (1) LOCK operation implication:
+
+     Memory operations issued after the LOCK will be completed after the LOCK
+     operation has completed.
+
+     Memory operations issued before the LOCK may be completed after the LOCK
+     operation has completed.
+
+ (2) UNLOCK operation implication:
+
+     Memory operations issued before the UNLOCK will be completed before the
+     UNLOCK operation has completed.
+
+     Memory operations issued after the UNLOCK may be completed before the
+     UNLOCK operation has completed.
+
+ (3) LOCK vs LOCK implication:
+
+     All LOCK operations issued before another LOCK operation will be completed
+     before that LOCK operation.
+
+ (4) LOCK vs UNLOCK implication:
+
+     All LOCK operations issued before an UNLOCK operation will be completed
+     before the UNLOCK operation.
+
+     All UNLOCK operations issued before a LOCK operation will be completed
+     before the LOCK operation.
+
+ (5) Failed conditional LOCK implication:
+
+     Certain variants of the LOCK operation may fail, either due to being
+     unable to get the lock immediately, or due to receiving an unblocked
+     signal whilst asleep waiting for the lock to become available.  Failed
+     locks do not imply any sort of barrier.
+
+Therefore, from (1), (2) and (4) an UNLOCK followed by an unconditional LOCK is
+equivalent to a full barrier, but a LOCK followed by an UNLOCK is not.
+
+[!] Note: one of the consequence of LOCKs and UNLOCKs being only one-way
+    barriers is that the effects instructions outside of a critical section may
+    seep into the inside of the critical section.
+
+Locks and semaphores may not provide any guarantee of ordering on UP compiled
+systems, and so cannot be counted on in such a situation to actually achieve
+anything at all - especially with respect to I/O accesses - unless combined
+with interrupt disabling operations.
+
+See also the section on "Inter-CPU locking barrier effects".
+
+
+As an example, consider the following:
+
+	*A = a;
+	*B = b;
+	LOCK
+	*C = c;
+	*D = d;
+	UNLOCK
+	*E = e;
+	*F = f;
+
+The following sequence of events is acceptable:
+
+	LOCK, {*F,*A}, *E, {*C,*D}, *B, UNLOCK
+
+	[+] Note that {*F,*A} indicates a combined access.
+
+But none of the following are:
+
+	{*F,*A}, *B,	LOCK, *C, *D,	UNLOCK, *E
+	*A, *B, *C,	LOCK, *D,	UNLOCK, *E, *F
+	*A, *B,		LOCK, *C,	UNLOCK, *D, *E, *F
+	*B,		LOCK, *C, *D,	UNLOCK, {*F,*A}, *E
+
+
+
+INTERRUPT DISABLING FUNCTIONS
+-----------------------------
+
+Functions that disable interrupts (LOCK equivalent) and enable interrupts
+(UNLOCK equivalent) will act as compiler barriers only.  So if memory or I/O
+barriers are required in such a situation, they must be provided from some
+other means.
+
+
+MISCELLANEOUS FUNCTIONS
+-----------------------
+
+Other functions that imply barriers:
+
+ (*) schedule() and similar imply full memory barriers.
+
+ (*) Memory allocation and release functions imply full memory barriers.
+
+
+=================================
+INTER-CPU LOCKING BARRIER EFFECTS
+=================================
+
+On SMP systems locking primitives give a more substantial form of barrier: one
+that does affect memory access ordering on other CPUs, within the context of
+conflict on any particular lock.
+
+
+LOCKS VS MEMORY ACCESSES
+------------------------
+
+Consider the following: the system has a pair of spinlocks (N) and (Q), and
+three CPUs; then should the following sequence of events occur:
+
+	CPU 1				CPU 2
+	===============================	===============================
+	*A = a;				*E = e;
+	LOCK M				LOCK Q
+	*B = b;				*F = f;
+	*C = c;				*G = g;
+	UNLOCK M			UNLOCK Q
+	*D = d;				*H = h;
+
+Then there is no guarantee as to what order CPU #3 will see the accesses to *A
+through *H occur in, other than the constraints imposed by the separate locks
+on the separate CPUs. It might, for example, see:
+
+	*E, LOCK M, LOCK Q, *G, *C, *F, *A, *B, UNLOCK Q, *D, *H, UNLOCK M
+
+But it won't see any of:
+
+	*B, *C or *D preceding LOCK M
+	*A, *B or *C following UNLOCK M
+	*F, *G or *H preceding LOCK Q
+	*E, *F or *G following UNLOCK Q
+
+
+However, if the following occurs:
+
+	CPU 1				CPU 2
+	===============================	===============================
+	*A = a;
+	LOCK M		[1]
+	*B = b;
+	*C = c;
+	UNLOCK M	[1]
+	*D = d;				*E = e;
+					LOCK M		[2]
+					*F = f;
+					*G = g;
+					UNLOCK M	[2]
+					*H = h;
+
+CPU #3 might see:
+
+	*E, LOCK M [1], *C, *B, *A, UNLOCK M [1],
+		LOCK M [2], *H, *F, *G, UNLOCK M [2], *D
+
+But assuming CPU #1 gets the lock first, it won't see any of:
+
+	*B, *C, *D, *F, *G or *H preceding LOCK M [1]
+	*A, *B or *C following UNLOCK M [1]
+	*F, *G or *H preceding LOCK M [2]
+	*A, *B, *C, *E, *F or *G following UNLOCK M [2]
+
+
+LOCKS VS I/O ACCESSES
+---------------------
+
+Under certain circumstances (especially involving NUMA), I/O accesses within
+two spinlocked sections on two different CPUs may be seen as interleaved by the
+PCI bridge, because the PCI bridge does not necessarily participate in the
+cache-coherence protocol, and is therefore incapable of issuing the required
+read memory barriers.
+
+For example:
+
+	CPU 1				CPU 2
+	===============================	===============================
+	spin_lock(Q)
+	writel(0, ADDR)
+	writel(1, DATA);
+	spin_unlock(Q);
+					spin_lock(Q);
+					writel(4, ADDR);
+					writel(5, DATA);
+					spin_unlock(Q);
+
+may be seen by the PCI bridge as follows:
+
+	STORE *ADDR = 0, STORE *ADDR = 4, STORE *DATA = 1, STORE *DATA = 5
+
+which would probably cause the hardware to malfunction.
+
+
+What is necessary here is to intervene with an mmiowb() before dropping the
+spinlock, for example:
+
+	CPU 1				CPU 2
+	===============================	===============================
+	spin_lock(Q)
+	writel(0, ADDR)
+	writel(1, DATA);
+	mmiowb();
+	spin_unlock(Q);
+					spin_lock(Q);
+					writel(4, ADDR);
+					writel(5, DATA);
+					mmiowb();
+					spin_unlock(Q);
+
+this will ensure that the two stores issued on CPU #1 appear at the PCI bridge
+before either of the stores issued on CPU #2.
+
+
+Furthermore, following a store by a load to the same device obviates the need
+for an mmiowb(), because the load forces the store to complete before the load
+is performed:
+
+	CPU 1				CPU 2
+	===============================	===============================
+	spin_lock(Q)
+	writel(0, ADDR)
+	a = readl(DATA);
+	spin_unlock(Q);
+					spin_lock(Q);
+					writel(4, ADDR);
+					b = readl(DATA);
+					spin_unlock(Q);
+
+
+See Documentation/DocBook/deviceiobook.tmpl for more information.
+
+
+=================================
+WHERE ARE MEMORY BARRIERS NEEDED?
+=================================
+
+Under normal operation, memory operation reordering is generally not going to
+be a problem as a single-threaded linear piece of code will still appear to
+work correctly, even if it's in an SMP kernel.  There are, however, three
+circumstances in which reordering definitely _could_ be a problem:
+
+ (*) Interprocessor interaction.
+
+ (*) Atomic operations.
+
+ (*) Accessing devices (I/O).
+
+ (*) Interrupts.
+
+
+INTERPROCESSOR INTERACTION
+--------------------------
+
+When there's a system with more than one processor, more than one CPU in the
+system may be working on the same data set at the same time.  This can cause
+synchronisation problems, and the usual way of dealing with them is to use
+locks.  Locks, however, are quite expensive, and so it may be preferable to
+operate without the use of a lock if at all possible.  In such a case
+operations that affect both CPUs may have to be carefully ordered to prevent
+a malfunction.
+
+Consider, for example, the R/W semaphore slow path.  Here a waiting process is
+queued on the semaphore, by virtue of it having a piece of its stack linked to
+the semaphore's list of waiting processes:
+
+	struct rw_semaphore {
+		...
+		spinlock_t lock;
+		struct list_head waiters;
+	};
+
+	struct rwsem_waiter {
+		struct list_head list;
+		struct task_struct *task;
+	};
+
+To wake up a particular waiter, the up_read() or up_write() functions have to:
+
+ (1) read the next pointer from this waiter's record to know as to where the
+     next waiter record is;
+
+ (4) read the pointer to the waiter's task structure;
+
+ (3) clear the task pointer to tell the waiter it has been given the semaphore;
+
+ (4) call wake_up_process() on the task; and
+
+ (5) release the reference held on the waiter's task struct.
+
+In otherwords, it has to perform this sequence of events:
+
+	LOAD waiter->list.next;
+	LOAD waiter->task;
+	STORE waiter->task;
+	CALL wakeup
+	RELEASE task
+
+and if any of these steps occur out of order, then the whole thing may
+malfunction.
+
+Once it has queued itself and dropped the semaphore lock, the waiter does not
+get the lock again; it instead just waits for its task pointer to be cleared
+before proceeding.  Since the record is on the waiter's stack, this means that
+if the task pointer is cleared _before_ the next pointer in the list is read,
+another CPU might start processing the waiter and might clobber the waiter's
+stack before the up*() function has a chance to read the next pointer.
+
+Consider then what might happen to the above sequence of events:
+
+	CPU 1				CPU 2
+	===============================	===============================
+					down_xxx()
+					Queue waiter
+					Sleep
+	up_yyy()
+	LOAD waiter->task;
+	STORE waiter->task;
+					Woken up by other event
+	<preempt>
+					Resume processing
+					down_xxx() returns
+					call foo()
+					foo() clobbers *waiter
+	</preempt>
+	LOAD waiter->list.next;
+	--- OOPS ---
+
+This could be dealt with using the semaphore lock, but then the down_xxx()
+function has to needlessly get the spinlock again after being woken up.
+
+The way to deal with this is to insert a general SMP memory barrier:
+
+	LOAD waiter->list.next;
+	LOAD waiter->task;
+	smp_mb();
+	STORE waiter->task;
+	CALL wakeup
+	RELEASE task
+
+In this case, the barrier makes a guarantee that all memory accesses before the
+barrier will appear to happen before all the memory accesses after the barrier
+with respect to the other CPUs on the system.  It does _not_ guarantee that all
+the memory accesses before the barrier will be complete by the time the barrier
+instruction itself is complete.
+
+On a UP system - where this wouldn't be a problem - the smp_mb() is just a
+compiler barrier, thus making sure the compiler emits the instructions in the
+right order without actually intervening in the CPU.  Since there there's only
+one CPU, that CPU's dependency ordering logic will take care of everything
+else.
+
+
+ATOMIC OPERATIONS
+-----------------
+
+Though they are technically interprocessor interaction considerations, atomic
+operations are noted specially as they do _not_ generally imply memory
+barriers.  The possible offenders include:
+
+	xchg();
+	cmpxchg();
+	test_and_set_bit();
+	test_and_clear_bit();
+	test_and_change_bit();
+	atomic_cmpxchg();
+	atomic_inc_return();
+	atomic_dec_return();
+	atomic_add_return();
+	atomic_sub_return();
+	atomic_inc_and_test();
+	atomic_dec_and_test();
+	atomic_sub_and_test();
+	atomic_add_negative();
+	atomic_add_unless();
+
+These may be used for such things as implementing LOCK operations or controlling
+the lifetime of objects by decreasing their reference counts.  In such cases
+they need preceding memory barriers.
+
+The following may also be possible offenders as they may be used as UNLOCK
+operations.
+
+	set_bit();
+	clear_bit();
+	change_bit();
+	atomic_set();
+
+
+The following are a little tricky:
+
+	atomic_add();
+	atomic_sub();
+	atomic_inc();
+	atomic_dec();
+
+If they're used for statistics generation, then they probably don't need memory
+barriers, unless there's a coupling between statistical data.
+
+If they're used for reference counting on an object to control its lifetime,
+they probably don't need memory barriers because either the reference count
+will be adjusted inside a locked section, or the caller will already hold
+sufficient references to make the lock, and thus a memory barrier unnecessary.
+
+If they're used for constructing a lock of some description, then they probably
+do need memory barriers as a lock primitive generally has to do things in a
+specific order.
+
+
+Basically, each usage case has to be carefully considered as to whether memory
+barriers are needed or not.  The simplest rule is probably: if the atomic
+operation is protected by a lock, then it does not require a barrier unless
+there's another operation within the critical section with respect to which an
+ordering must be maintained.
+
+See Documentation/atomic_ops.txt for more information.
+
+
+ACCESSING DEVICES
+-----------------
+
+Many devices can be memory mapped, and so appear to the CPU as if they're just
+a set of memory locations.  To control such a device, the driver usually has to
+make the right memory accesses in exactly the right order.
+
+However, having a clever CPU or a clever compiler creates a potential problem
+in that the carefully sequenced accesses in the driver code won't reach the
+device in the requisite order if the CPU or the compiler thinks it is more
+efficient to reorder, combine or merge accesses - something that would cause
+the device to malfunction.
+
+Inside of the Linux kernel, I/O should be done through the appropriate accessor
+routines - such as inb() or writel() - which know how to make such accesses
+appropriately sequential.  Whilst this, for the most part, renders the explicit
+use of memory barriers unnecessary, there are a couple of situations where they
+might be needed:
+
+ (1) On some systems, I/O stores are not strongly ordered across all CPUs, and
+     so for _all_ general drivers locks should be used and mmiowb() must be
+     issued prior to unlocking the critical section.
+
+ (2) If the accessor functions are used to refer to an I/O memory window with
+     relaxed memory access properties, then _mandatory_ memory barriers are
+     required to enforce ordering.
+
+See Documentation/DocBook/deviceiobook.tmpl for more information.
+
+
+INTERRUPTS
+----------
+
+A driver may be interrupted by its own interrupt service routine, and thus the
+two parts of the driver may interfere with each other's attempts to control or
+access the device.
+
+This may be alleviated - at least in part - by disabling local interrupts (a
+form of locking), such that the critical operations are all contained within
+the interrupt-disabled section in the driver.  Whilst the driver's interrupt
+routine is executing, the driver's core may not run on the same CPU, and its
+interrupt is not permitted to happen again until the current interrupt has been
+handled, thus the interrupt handler does not need to lock against that.
+
+However, consider a driver that was talking to an ethernet card that sports an
+address register and a data register.  If that driver's core talks to the card
+under interrupt-disablement and then the driver's interrupt handler is invoked:
+
+	LOCAL IRQ DISABLE
+	writew(ADDR, 3);
+	writew(DATA, y);
+	LOCAL IRQ ENABLE
+	<interrupt>
+	writew(ADDR, 4);
+	q = readw(DATA);
+	</interrupt>
+
+The store to the data register might happen after the second store to the
+address register if ordering rules are sufficiently relaxed:
+
+	STORE *ADDR = 3, STORE *ADDR = 4, STORE *DATA = y, q = LOAD *DATA
+
+
+If ordering rules are relaxed, it must be assumed that accesses done inside an
+interrupt disabled section may leak outside of it and may interleave with
+accesses performed in an interrupt - and vice versa - unless implicit or
+explicit barriers are used.
+
+Normally this won't be a problem because the I/O accesses done inside such
+sections will include synchronous load operations on strictly ordered I/O
+registers that form implicit I/O barriers. If this isn't sufficient then an
+mmiowb() may need to be used explicitly.
+
+
+A similar situation may occur between an interrupt routine and two routines
+running on separate CPUs that communicate with each other. If such a case is
+likely, then interrupt-disabling locks should be used to guarantee ordering.
+
+
+==========================
+KERNEL I/O BARRIER EFFECTS
+==========================
+
+When accessing I/O memory, drivers should use the appropriate accessor
+functions:
+
+ (*) inX(), outX():
+
+     These are intended to talk to I/O space rather than memory space, but
+     that's primarily a CPU-specific concept. The i386 and x86_64 processors do
+     indeed have special I/O space access cycles and instructions, but many
+     CPUs don't have such a concept.
+
+     The PCI bus, amongst others, defines an I/O space concept - which on such
+     CPUs as i386 and x86_64 cpus readily maps to the CPU's concept of I/O
+     space.  However, it may also mapped as a virtual I/O space in the CPU's
+     memory map, particularly on those CPUs that don't support alternate
+     I/O spaces.
+
+     Accesses to this space may be fully synchronous (as on i386), but
+     intermediary bridges (such as the PCI host bridge) may not fully honour
+     that.
+
+     They are guaranteed to be fully ordered with respect to each other.
+
+     They are not guaranteed to be fully ordered with respect to other types of
+     memory and I/O operation.
+
+ (*) readX(), writeX():
+
+     Whether these are guaranteed to be fully ordered and uncombined with
+     respect to each other on the issuing CPU depends on the characteristics
+     defined for the memory window through which they're accessing. On later
+     i386 architecture machines, for example, this is controlled by way of the
+     MTRR registers.
+
+     Ordinarily, these will be guaranteed to be fully ordered and uncombined,,
+     provided they're not accessing a prefetchable device.
+
+     However, intermediary hardware (such as a PCI bridge) may indulge in
+     deferral if it so wishes; to flush a store, a load from the same location
+     is preferred[*], but a load from the same device or from configuration
+     space should suffice for PCI.
+
+     [*] NOTE! attempting to load from the same location as was written to may
+     	 cause a malfunction - consider the 16550 Rx/Tx serial registers for
+     	 example.
+
+     Used with prefetchable I/O memory, an mmiowb() barrier may be required to
+     force stores to be ordered.
+
+     Please refer to the PCI specification for more information on interactions
+     between PCI transactions.
+
+ (*) readX_relaxed()
+
+     These are similar to readX(), but are not guaranteed to be ordered in any
+     way. Be aware that there is no I/O read barrier available.
+
+ (*) ioreadX(), iowriteX()
+
+     These will perform as appropriate for the type of access they're actually
+     doing, be it inX()/outX() or readX()/writeX().
+
+
+========================================
+ASSUMED MINIMUM EXECUTION ORDERING MODEL
+========================================
+
+It has to be assumed that the conceptual CPU is weakly-ordered but that it will
+maintain the appearance of program causality with respect to itself.  Some CPUs
+(such as i386 or x86_64) are more constrained than others (such as powerpc or
+frv), and so the most relaxed case (namely DEC Alpha) must be assumed outside
+of arch-specific code.
+
+This means that it must be considered that the CPU will execute its instruction
+stream in any order it feels like - or even in parallel - provided that if an
+instruction in the stream depends on the an earlier instruction, then that
+earlier instruction must be sufficiently complete[*] before the later
+instruction may proceed; in other words: provided that the appearance of
+causality is maintained.
+
+ [*] Some instructions have more than one effect - such as changing the
+     condition codes, changing registers or changing memory - and different
+     instructions may depend on different effects.
+
+A CPU may also discard any instruction sequence that winds up having no
+ultimate effect.  For example, if two adjacent instructions both load an
+immediate value into the same register, the first may be discarded.
+
+
+Similarly, it has to be assumed that compiler might reorder the instruction
+stream in any way it sees fit, again provided the appearance of causality is
+maintained.
+
+
+============================
+THE EFFECTS OF THE CPU CACHE
+============================
+
+The way cached memory operations are perceived across the system is affected to
+a certain extent by the caches that lie between CPUs and memory, and by the
+memory coherence system that maintains the consistency of state in the system.
+
+As far as the way a CPU interacts with another part of the system through the
+caches goes, the memory system has to include the CPU's caches, and memory
+barriers for the most part act at the interface between the CPU and its cache
+(memory barriers logically act on the dotted line in the following diagram):
+
+	    <--- CPU --->         :       <----------- Memory ----------->
+	                          :
+	+--------+    +--------+  :   +--------+    +-----------+
+	|        |    |        |  :   |        |    |           |    +--------+
+	|  CPU   |    | Memory |  :   | CPU    |    |           |    |	      |
+	|  Core  |--->| Access |----->| Cache  |<-->|           |    |	      |
+	|        |    | Queue  |  :   |        |    |           |--->| Memory |
+	|        |    |        |  :   |        |    |           |    |	      |
+	+--------+    +--------+  :   +--------+    |           |    | 	      |
+	                          :                 | Cache     |    +--------+
+	                          :                 | Coherency |
+	                          :                 | Mechanism |    +--------+
+	+--------+    +--------+  :   +--------+    |           |    |	      |
+	|        |    |        |  :   |        |    |           |    |        |
+	|  CPU   |    | Memory |  :   | CPU    |    |           |--->| Device |
+	|  Core  |--->| Access |----->| Cache  |<-->|           |    | 	      |
+	|        |    | Queue  |  :   |        |    |           |    | 	      |
+	|        |    |        |  :   |        |    |           |    +--------+
+	+--------+    +--------+  :   +--------+    +-----------+
+	                          :
+	                          :
+
+Although any particular load or store may not actually appear outside of the
+CPU that issued it since it may have been satisfied within the CPU's own cache,
+it will still appear as if the full memory access had taken place as far as the
+other CPUs are concerned since the cache coherency mechanisms will migrate the
+cacheline over to the accessing CPU and propagate the effects upon conflict.
+
+The CPU core may execute instructions in any order it deems fit, provided the
+expected program causality appears to be maintained.  Some of the instructions
+generate load and store operations which then go into the queue of memory
+accesses to be performed.  The core may place these in the queue in any order
+it wishes, and continue execution until it is forced to wait for an instruction
+to complete.
+
+What memory barriers are concerned with is controlling the order in which
+accesses cross from the CPU side of things to the memory side of things, and
+the order in which the effects are perceived to happen by the other observers
+in the system.
+
+[!] Memory barriers are _not_ needed within a given CPU, as CPUs always see
+their own loads and stores as if they had happened in program order.
+
+[!] MMIO or other device accesses may bypass the cache system.  This depends on
+the properties of the memory window through which devices are accessed and/or
+the use of any special device communication instructions the CPU may have.
+
+
+CACHE COHERENCY
+---------------
+
+Life isn't quite as simple as it may appear above, however: for while the
+caches are expected to be coherent, there's no guarantee that that coherency
+will be ordered.  This means that whilst changes made on one CPU will
+eventually become visible on all CPUs, there's no guarantee that they will
+become apparent in the same order on those other CPUs.
+
+
+Consider dealing with a system that has pair of CPUs (1 & 2), each of which has
+a pair of parallel data caches (CPU 1 has A/B, and CPU 2 has C/D):
+
+	            :
+	            :                          +--------+
+	            :      +---------+         |        |
+	+--------+  : +--->| Cache A |<------->|        |
+	|        |  : |    +---------+         |        |
+	|  CPU 1 |<---+                        |        |
+	|        |  : |    +---------+         |        |
+	+--------+  : +--->| Cache B |<------->|        |
+	            :      +---------+         |        |
+	            :                          | Memory |
+	            :      +---------+         | System |
+	+--------+  : +--->| Cache C |<------->|        |
+	|        |  : |    +---------+         |        |
+	|  CPU 2 |<---+                        |        |
+	|        |  : |    +---------+         |        |
+	+--------+  : +--->| Cache D |<------->|        |
+	            :      +---------+         |        |
+	            :                          +--------+
+	            :
+
+Imagine the system has the following properties:
+
+ (*) an odd-numbered cache line may be in cache A, cache C or it may still be
+     resident in memory;
+
+ (*) an even-numbered cache line may be in cache B, cache D or it may still be
+     resident in memory;
+
+ (*) whilst the CPU core is interrogating one cache, the other cache may be
+     making use of the bus to access the rest of the system - perhaps to
+     displace a dirty cacheline or to do a speculative load;
+
+ (*) each cache has a queue of operations that need to be applied to that cache
+     to maintain coherency with the rest of the system;
+
+ (*) the coherency queue is not flushed by normal loads to lines already
+     present in the cache, even though the contents of the queue may
+     potentially effect those loads.
+
+Imagine, then, that two writes are made on the first CPU, with a write barrier
+between them to guarantee that they will appear to reach that CPU's caches in
+the requisite order:
+
+	CPU 1		CPU 2		COMMENT
+	===============	===============	=======================================
+					u == 0, v == 1 and p == &u, q == &u
+	v = 2;
+	smp_wmb();			Make sure change to v visible before
+					 change to p
+	<A:modify v=2>			v is now in cache A exclusively
+	p = &v;
+	<B:modify p=&v>			p is now in cache B exclusively
+
+The write memory barrier forces the other CPUs in the system to perceive that
+the local CPU's caches have apparently been updated in the correct order.  But
+now imagine that the second CPU that wants to read those values:
+
+	CPU 1		CPU 2		COMMENT
+	===============	===============	=======================================
+	...
+			q = p;
+			x = *q;
+
+The above pair of reads may then fail to happen in expected order, as the
+cacheline holding p may get updated in one of the second CPU's caches whilst
+the update to the cacheline holding v is delayed in the other of the second
+CPU's caches by some other cache event:
+
+	CPU 1		CPU 2		COMMENT
+	===============	===============	=======================================
+					u == 0, v == 1 and p == &u, q == &u
+	v = 2;
+	smp_wmb();
+	<A:modify v=2>	<C:busy>
+			<C:queue v=2>
+	p = &b;		q = p;
+			<D:request p>
+	<B:modify p=&v>	<D:commit p=&v>
+		  	<D:read p>
+			x = *q;
+			<C:read *q>	Reads from v before v updated in cache
+			<C:unbusy>
+			<C:commit v=2>
+
+Basically, whilst both cachelines will be updated on CPU 2 eventually, there's
+no guarantee that, without intervention, the order of update will be the same
+as that committed on CPU 1.
+
+
+To intervene, we need to interpolate a data dependency barrier or a read
+barrier between the loads.  This will force the cache to commit its coherency
+queue before processing any further requests:
+
+	CPU 1		CPU 2		COMMENT
+	===============	===============	=======================================
+					u == 0, v == 1 and p == &u, q == &u
+	v = 2;
+	smp_wmb();
+	<A:modify v=2>	<C:busy>
+			<C:queue v=2>
+	p = &b;		q = p;
+			<D:request p>
+	<B:modify p=&v>	<D:commit p=&v>
+		  	<D:read p>
+			smp_read_barrier_depends()
+			<C:unbusy>
+			<C:commit v=2>
+			x = *q;
+			<C:read *q>	Reads from v after v updated in cache
+
+
+This sort of problem can be encountered on DEC Alpha processors as they have a
+split cache that improves performance by making better use of the data bus.
+Whilst most CPUs do imply a data dependency barrier on the read when a memory
+access depends on a read, not all do, so it may not be relied on.
+
+Other CPUs may also have split caches, but must coordinate between the various
+cachelets for normal memory accesss.  The semantics of the Alpha removes the
+need for coordination in absence of memory barriers.
+
+
+CACHE COHERENCY VS DMA
+----------------------
+
+Not all systems maintain cache coherency with respect to devices doing DMA.  In
+such cases, a device attempting DMA may obtain stale data from RAM because
+dirty cache lines may be resident in the caches of various CPUs, and may not
+have been written back to RAM yet.  To deal with this, the appropriate part of
+the kernel must flush the overlapping bits of cache on each CPU (and maybe
+invalidate them as well).
+
+In addition, the data DMA'd to RAM by a device may be overwritten by dirty
+cache lines being written back to RAM from a CPU's cache after the device has
+installed its own data, or cache lines simply present in a CPUs cache may
+simply obscure the fact that RAM has been updated, until at such time as the
+cacheline is discarded from the CPU's cache and reloaded.  To deal with this,
+the appropriate part of the kernel must invalidate the overlapping bits of the
+cache on each CPU.
+
+See Documentation/cachetlb.txt for more information on cache management.
+
+
+CACHE COHERENCY VS MMIO
+-----------------------
+
+Memory mapped I/O usually takes place through memory locations that are part of
+a window in the CPU's memory space that have different properties assigned than
+the usual RAM directed window.
+
+Amongst these properties is usually the fact that such accesses bypass the
+caching entirely and go directly to the device buses.  This means MMIO accesses
+may, in effect, overtake accesses to cached memory that were emitted earlier.
+A memory barrier isn't sufficient in such a case, but rather the cache must be
+flushed between the cached memory write and the MMIO access if the two are in
+any way dependent.
+
+
+=========================
+THE THINGS CPUS GET UP TO
+=========================
+
+A programmer might take it for granted that the CPU will perform memory
+operations in exactly the order specified, so that if a CPU is, for example,
+given the following piece of code to execute:
+
+	a = *A;
+	*B = b;
+	c = *C;
+	d = *D;
+	*E = e;
+
+They would then expect that the CPU will complete the memory operation for each
+instruction before moving on to the next one, leading to a definite sequence of
+operations as seen by external observers in the system:
+
+	LOAD *A, STORE *B, LOAD *C, LOAD *D, STORE *E.
+
+
+Reality is, of course, much messier.  With many CPUs and compilers, the above
+assumption doesn't hold because:
+
+ (*) loads are more likely to need to be completed immediately to permit
+     execution progress, whereas stores can often be deferred without a
+     problem;
+
+ (*) loads may be done speculatively, and the result discarded should it prove
+     to have been unnecessary;
+
+ (*) loads may be done speculatively, leading to the result having being
+     fetched at the wrong time in the expected sequence of events;
+
+ (*) the order of the memory accesses may be rearranged to promote better use
+     of the CPU buses and caches;
+
+ (*) loads and stores may be combined to improve performance when talking to
+     memory or I/O hardware that can do batched accesses of adjacent locations,
+     thus cutting down on transaction setup costs (memory and PCI devices may
+     both be able to do this); and
+
+ (*) the CPU's data cache may affect the ordering, and whilst cache-coherency
+     mechanisms may alleviate this - once the store has actually hit the cache
+     - there's no guarantee that the coherency management will be propagated in
+     order to other CPUs.
+
+So what another CPU, say, might actually observe from the above piece of code
+is:
+
+	LOAD *A, ..., LOAD {*C,*D}, STORE *E, STORE *B
+
+	(Where "LOAD {*C,*D}" is a combined load)
+
+
+However, it is guaranteed that a CPU will be self-consistent: it will see its
+_own_ accesses appear to be correctly ordered, without the need for a memory
+barrier.  For instance with the following code:
+
+	U = *A;
+	*A = V;
+	*A = W;
+	X = *A;
+	*A = Y;
+	Z = *A;
+
+and assuming no intervention by an external influence, it can be assumed that
+the final result will appear to be:
+
+	U == the original value of *A
+	X == W
+	Z == Y
+	*A == Y
+
+The code above may cause the CPU to generate the full sequence of memory
+accesses:
+
+	U=LOAD *A, STORE *A=V, STORE *A=W, X=LOAD *A, STORE *A=Y, Z=LOAD *A
+
+in that order, but, without intervention, the sequence may have almost any
+combination of elements combined or discarded, provided the program's view of
+the world remains consistent.
+
+The compiler may also combine, discard or defer elements of the sequence before
+the CPU even sees them.
+
+For instance:
+
+	*A = V;
+	*A = W;
+
+may be reduced to:
+
+	*A = W;
+
+since, without a write barrier, it can be assumed that the effect of the
+storage of V to *A is lost.  Similarly:
+
+	*A = Y;
+	Z = *A;
+
+may, without a memory barrier, be reduced to:
+
+	*A = Y;
+	Z = Y;
+
+and the LOAD operation never appear outside of the CPU.
+
+
+AND THEN THERE'S THE ALPHA
+--------------------------
+
+The DEC Alpha CPU is one of the most relaxed CPUs there is.  Not only that,
+some versions of the Alpha CPU have a split data cache, permitting them to have
+two semantically related cache lines updating at separate times.  This is where
+the data dependency barrier really becomes necessary as this synchronises both
+caches with the memory coherence system, thus making it seem like pointer
+changes vs new data occur in the right order.
+
+The Alpha defines the Linux's kernel's memory barrier model.
+
+See the subsection on "Cache Coherency" above.
+
+
+==========
+REFERENCES
+==========
+
+Alpha AXP Architecture Reference Manual, Second Edition (Sites & Witek,
+Digital Press)
+	Chapter 5.2: Physical Address Space Characteristics
+	Chapter 5.4: Caches and Write Buffers
+	Chapter 5.5: Data Sharing
+	Chapter 5.6: Read/Write Ordering
+
+AMD64 Architecture Programmer's Manual Volume 2: System Programming
+	Chapter 7.1: Memory-Access Ordering
+	Chapter 7.4: Buffering and Combining Memory Writes
+
+IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+System Programming Guide
+	Chapter 7.1: Locked Atomic Operations
+	Chapter 7.2: Memory Ordering
+	Chapter 7.4: Serializing Instructions
+
+The SPARC Architecture Manual, Version 9
+	Chapter 8: Memory Models
+	Appendix D: Formal Specification of the Memory Models
+	Appendix J: Programming with the Memory Models
+
+UltraSPARC Programmer Reference Manual
+	Chapter 5: Memory Accesses and Cacheability
+	Chapter 15: Sparc-V9 Memory Models
+
+UltraSPARC III Cu User's Manual
+	Chapter 9: Memory Models
+
+UltraSPARC IIIi Processor User's Manual
+	Chapter 8: Memory Models
+
+UltraSPARC Architecture 2005
+	Chapter 9: Memory
+	Appendix D: Formal Specifications of the Memory Models
+
+UltraSPARC T1 Supplement to the UltraSPARC Architecture 2005
+	Chapter 8: Memory Models
+	Appendix F: Caches and Cache Coherency
+
+Solaris Internals, Core Kernel Architecture, p63-68:
+	Chapter 3.3: Hardware Considerations for Locks and
+			Synchronization
+
+Unix Systems for Modern Architectures, Symmetric Multiprocessing and Caching
+for Kernel Programmers:
+	Chapter 13: Other Memory Models
+
+Intel Itanium Architecture Software Developer's Manual: Volume 1:
+	Section 2.6: Speculation
+	Section 4.4: Memory Access
diff --git a/Documentation/networking/TODO b/Documentation/networking/TODO
deleted file mode 100644
index 66d36ff..0000000
--- a/Documentation/networking/TODO
+++ /dev/null
@@ -1,18 +0,0 @@
-To-do items for network drivers
--------------------------------
-
-* Move ethernet crc routine to generic code
-
-* (for 2.5) Integrate Jamal Hadi Salim's netdev Rx polling API change
-
-* Audit all net drivers to make sure magic packet / wake-on-lan /
-  similar features are disabled in the driver by default.
-
-* Audit all net drivers to make sure the module always prints out a
-  version string when loaded as a module, but only prints a version
-  string when built into the kernel if a device is detected.
-
-* Add ETHTOOL_GDRVINFO ioctl support to all ethernet drivers.
-
-* dmfe PCI DMA is totally wrong and only works on x86
-
diff --git a/Documentation/networking/bcm43xx.txt b/Documentation/networking/bcm43xx.txt
new file mode 100644
index 0000000..28541d2
--- /dev/null
+++ b/Documentation/networking/bcm43xx.txt
@@ -0,0 +1,36 @@
+
+			BCM43xx Linux Driver Project
+			============================
+
+About this software
+-------------------
+
+The goal of this project is to develop a linux driver for Broadcom
+BCM43xx chips, based on the specification at 
+http://bcm-specs.sipsolutions.net/
+
+The project page is http://bcm43xx.berlios.de/
+
+
+Requirements
+------------
+
+1)	Linux Kernel 2.6.16 or later
+	http://www.kernel.org/
+
+	You may want to configure your kernel with:
+
+	CONFIG_DEBUG_FS (optional):
+		-> Kernel hacking
+		  -> Debug Filesystem
+
+2)	SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211
+	modules:
+	http://softmac.sipsolutions.net/
+
+3)	Firmware Files
+
+	Please try fwcutter. Fwcutter can extract the firmware from various 
+	binary driver files. It supports driver files from Windows, MacOS and 
+	Linux. You can get fwcutter from http://bcm43xx.berlios.de/.
+	Also, fwcutter comes with a README file for further instructions.
diff --git a/Documentation/networking/ifenslave.c b/Documentation/networking/ifenslave.c
index 545447a..a120598 100644
--- a/Documentation/networking/ifenslave.c
+++ b/Documentation/networking/ifenslave.c
@@ -87,7 +87,7 @@
  *	   would fail and generate an error message in the system log.
  * 	 - For opt_c: slave should not be set to the master's setting
  *	   while it is running. It was already set during enslave. To
- *	   simplify things, it is now handeled separately.
+ *	   simplify things, it is now handled separately.
  *
  *    - 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
  *	 - Code cleanup and style changes
diff --git a/Documentation/networking/vortex.txt b/Documentation/networking/vortex.txt
index 3759acf..6091e5f 100644
--- a/Documentation/networking/vortex.txt
+++ b/Documentation/networking/vortex.txt
@@ -24,36 +24,44 @@
 
 This driver supports the following hardware:
 
-   3c590 Vortex 10Mbps
-   3c592 EISA 10mbps Demon/Vortex
-   3c597 EISA Fast Demon/Vortex
-   3c595 Vortex 100baseTx
-   3c595 Vortex 100baseT4
-   3c595 Vortex 100base-MII
-   3Com Vortex
-   3c900 Boomerang 10baseT
-   3c900 Boomerang 10Mbps Combo
-   3c900 Cyclone 10Mbps TPO
-   3c900B Cyclone 10Mbps T
-   3c900 Cyclone 10Mbps Combo
-   3c900 Cyclone 10Mbps TPC
-   3c900B-FL Cyclone 10base-FL
-   3c905 Boomerang 100baseTx
-   3c905 Boomerang 100baseT4
-   3c905B Cyclone 100baseTx
-   3c905B Cyclone 10/100/BNC
-   3c905B-FX Cyclone 100baseFx
-   3c905C Tornado
-   3c980 Cyclone
-   3cSOHO100-TX Hurricane
-   3c555 Laptop Hurricane
-   3c575 Boomerang CardBus
-   3CCFE575 Cyclone CardBus
-   3CCFE575CT Cyclone CardBus
-   3CCFE656 Cyclone CardBus
-   3CCFEM656 Cyclone CardBus
-   3c450 Cyclone/unknown
-
+	3c590 Vortex 10Mbps
+	3c592 EISA 10Mbps Demon/Vortex
+	3c597 EISA Fast Demon/Vortex
+	3c595 Vortex 100baseTx
+	3c595 Vortex 100baseT4
+	3c595 Vortex 100base-MII
+	3c900 Boomerang 10baseT
+	3c900 Boomerang 10Mbps Combo
+	3c900 Cyclone 10Mbps TPO
+	3c900 Cyclone 10Mbps Combo
+	3c900 Cyclone 10Mbps TPC
+	3c900B-FL Cyclone 10base-FL
+	3c905 Boomerang 100baseTx
+	3c905 Boomerang 100baseT4
+	3c905B Cyclone 100baseTx
+	3c905B Cyclone 10/100/BNC
+	3c905B-FX Cyclone 100baseFx
+	3c905C Tornado
+	3c920B-EMB-WNM (ATI Radeon 9100 IGP)
+	3c980 Cyclone
+	3c980C Python-T
+	3cSOHO100-TX Hurricane
+	3c555 Laptop Hurricane
+	3c556 Laptop Tornado
+	3c556B Laptop Hurricane
+	3c575 [Megahertz] 10/100 LAN  CardBus
+	3c575 Boomerang CardBus
+	3CCFE575BT Cyclone CardBus
+	3CCFE575CT Tornado CardBus
+	3CCFE656 Cyclone CardBus
+	3CCFEM656B Cyclone+Winmodem CardBus
+	3CXFEM656C Tornado+Winmodem CardBus
+	3c450 HomePNA Tornado
+	3c920 Tornado
+	3c982 Hydra Dual Port A
+	3c982 Hydra Dual Port B
+	3c905B-T4
+	3c920B-EMB-WNM Tornado
 
 Module parameters
 =================
@@ -293,11 +301,6 @@
 
      http://www.scyld.com/wakeonlan.html
 
-3Com's documentation for many NICs, including the ones supported by
-this driver is available at 
-
-     http://support.3com.com/partners/developer/developer_form.html
-
 3Com's DOS-based application for setting up the NICs EEPROMs:
 
 	ftp://ftp.3com.com/pub/nic/3c90x/3c90xx2.exe
@@ -312,10 +315,10 @@
 ---------------------
 
   The driver uses a one-minute heartbeat for adapting to changes in
-  the external LAN environment.  This means that when, for example, a
-  machine is unplugged from a hubbed 10baseT LAN plugged into a
-  switched 100baseT LAN, the throughput will be quite dreadful for up
-  to sixty seconds.  Be patient.
+  the external LAN environment if link is up and 5 seconds if link is down.
+  This means that when, for example, a machine is unplugged from a hubbed
+  10baseT LAN plugged into a  switched 100baseT LAN, the throughput
+  will be quite dreadful for up to sixty seconds.  Be patient.
 
   Cisco interoperability note from Walter Wong <wcw+@CMU.EDU>:
 
diff --git a/Documentation/pnp.txt b/Documentation/pnp.txt
index af0f6ea..9529c9c 100644
--- a/Documentation/pnp.txt
+++ b/Documentation/pnp.txt
@@ -115,6 +115,9 @@
 pnp_register_driver
 - adds a PnP driver to the Plug and Play Layer
 - this includes driver model integration
+- returns zero for success or a negative error number for failure; count
+  calls to the .add() method if you need to know how many devices bind to
+  the driver
 
 pnp_unregister_driver
 - removes a PnP driver from the Plug and Play Layer
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index ee551c6..217e517 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -719,6 +719,11 @@
     - model : this is your board name/model
     - #address-cells : address representation for "root" devices
     - #size-cells: the size representation for "root" devices
+    - device_type : This property shouldn't be necessary. However, if
+      you decide to create a device_type for your root node, make sure it
+      is _not_ "chrp" unless your platform is a pSeries or PAPR compliant
+      one for 64-bit, or a CHRP-type machine for 32-bit as this will
+      matched by the kernel this way.
 
   Additionally, some recommended properties are:
 
diff --git a/Documentation/robust-futex-ABI.txt b/Documentation/robust-futex-ABI.txt
new file mode 100644
index 0000000..8529a17
--- /dev/null
+++ b/Documentation/robust-futex-ABI.txt
@@ -0,0 +1,182 @@
+Started by Paul Jackson <pj@sgi.com>
+
+The robust futex ABI
+--------------------
+
+Robust_futexes provide a mechanism that is used in addition to normal
+futexes, for kernel assist of cleanup of held locks on task exit.
+
+The interesting data as to what futexes a thread is holding is kept on a
+linked list in user space, where it can be updated efficiently as locks
+are taken and dropped, without kernel intervention.  The only additional
+kernel intervention required for robust_futexes above and beyond what is
+required for futexes is:
+
+ 1) a one time call, per thread, to tell the kernel where its list of
+    held robust_futexes begins, and
+ 2) internal kernel code at exit, to handle any listed locks held
+    by the exiting thread.
+
+The existing normal futexes already provide a "Fast Userspace Locking"
+mechanism, which handles uncontested locking without needing a system
+call, and handles contested locking by maintaining a list of waiting
+threads in the kernel.  Options on the sys_futex(2) system call support
+waiting on a particular futex, and waking up the next waiter on a
+particular futex.
+
+For robust_futexes to work, the user code (typically in a library such
+as glibc linked with the application) has to manage and place the
+necessary list elements exactly as the kernel expects them.  If it fails
+to do so, then improperly listed locks will not be cleaned up on exit,
+probably causing deadlock or other such failure of the other threads
+waiting on the same locks.
+
+A thread that anticipates possibly using robust_futexes should first
+issue the system call:
+
+    asmlinkage long
+    sys_set_robust_list(struct robust_list_head __user *head, size_t len);
+
+The pointer 'head' points to a structure in the threads address space
+consisting of three words.  Each word is 32 bits on 32 bit arch's, or 64
+bits on 64 bit arch's, and local byte order.  Each thread should have
+its own thread private 'head'.
+
+If a thread is running in 32 bit compatibility mode on a 64 native arch
+kernel, then it can actually have two such structures - one using 32 bit
+words for 32 bit compatibility mode, and one using 64 bit words for 64
+bit native mode.  The kernel, if it is a 64 bit kernel supporting 32 bit
+compatibility mode, will attempt to process both lists on each task
+exit, if the corresponding sys_set_robust_list() call has been made to
+setup that list.
+
+  The first word in the memory structure at 'head' contains a
+  pointer to a single linked list of 'lock entries', one per lock,
+  as described below.  If the list is empty, the pointer will point
+  to itself, 'head'.  The last 'lock entry' points back to the 'head'.
+
+  The second word, called 'offset', specifies the offset from the
+  address of the associated 'lock entry', plus or minus, of what will
+  be called the 'lock word', from that 'lock entry'.  The 'lock word'
+  is always a 32 bit word, unlike the other words above.  The 'lock
+  word' holds 3 flag bits in the upper 3 bits, and the thread id (TID)
+  of the thread holding the lock in the bottom 29 bits.  See further
+  below for a description of the flag bits.
+
+  The third word, called 'list_op_pending', contains transient copy of
+  the address of the 'lock entry', during list insertion and removal,
+  and is needed to correctly resolve races should a thread exit while
+  in the middle of a locking or unlocking operation.
+
+Each 'lock entry' on the single linked list starting at 'head' consists
+of just a single word, pointing to the next 'lock entry', or back to
+'head' if there are no more entries.  In addition, nearby to each 'lock
+entry', at an offset from the 'lock entry' specified by the 'offset'
+word, is one 'lock word'.
+
+The 'lock word' is always 32 bits, and is intended to be the same 32 bit
+lock variable used by the futex mechanism, in conjunction with
+robust_futexes.  The kernel will only be able to wakeup the next thread
+waiting for a lock on a threads exit if that next thread used the futex
+mechanism to register the address of that 'lock word' with the kernel.
+
+For each futex lock currently held by a thread, if it wants this
+robust_futex support for exit cleanup of that lock, it should have one
+'lock entry' on this list, with its associated 'lock word' at the
+specified 'offset'.  Should a thread die while holding any such locks,
+the kernel will walk this list, mark any such locks with a bit
+indicating their holder died, and wakeup the next thread waiting for
+that lock using the futex mechanism.
+
+When a thread has invoked the above system call to indicate it
+anticipates using robust_futexes, the kernel stores the passed in 'head'
+pointer for that task.  The task may retrieve that value later on by
+using the system call:
+
+    asmlinkage long
+    sys_get_robust_list(int pid, struct robust_list_head __user **head_ptr,
+                        size_t __user *len_ptr);
+
+It is anticipated that threads will use robust_futexes embedded in
+larger, user level locking structures, one per lock.  The kernel
+robust_futex mechanism doesn't care what else is in that structure, so
+long as the 'offset' to the 'lock word' is the same for all
+robust_futexes used by that thread.  The thread should link those locks
+it currently holds using the 'lock entry' pointers.  It may also have
+other links between the locks, such as the reverse side of a double
+linked list, but that doesn't matter to the kernel.
+
+By keeping its locks linked this way, on a list starting with a 'head'
+pointer known to the kernel, the kernel can provide to a thread the
+essential service available for robust_futexes, which is to help clean
+up locks held at the time of (a perhaps unexpectedly) exit.
+
+Actual locking and unlocking, during normal operations, is handled
+entirely by user level code in the contending threads, and by the
+existing futex mechanism to wait for, and wakeup, locks.  The kernels
+only essential involvement in robust_futexes is to remember where the
+list 'head' is, and to walk the list on thread exit, handling locks
+still held by the departing thread, as described below.
+
+There may exist thousands of futex lock structures in a threads shared
+memory, on various data structures, at a given point in time. Only those
+lock structures for locks currently held by that thread should be on
+that thread's robust_futex linked lock list a given time.
+
+A given futex lock structure in a user shared memory region may be held
+at different times by any of the threads with access to that region. The
+thread currently holding such a lock, if any, is marked with the threads
+TID in the lower 29 bits of the 'lock word'.
+
+When adding or removing a lock from its list of held locks, in order for
+the kernel to correctly handle lock cleanup regardless of when the task
+exits (perhaps it gets an unexpected signal 9 in the middle of
+manipulating this list), the user code must observe the following
+protocol on 'lock entry' insertion and removal:
+
+On insertion:
+ 1) set the 'list_op_pending' word to the address of the 'lock word'
+    to be inserted,
+ 2) acquire the futex lock,
+ 3) add the lock entry, with its thread id (TID) in the bottom 29 bits
+    of the 'lock word', to the linked list starting at 'head', and
+ 4) clear the 'list_op_pending' word.
+
+On removal:
+ 1) set the 'list_op_pending' word to the address of the 'lock word'
+    to be removed,
+ 2) remove the lock entry for this lock from the 'head' list,
+ 2) release the futex lock, and
+ 2) clear the 'lock_op_pending' word.
+
+On exit, the kernel will consider the address stored in
+'list_op_pending' and the address of each 'lock word' found by walking
+the list starting at 'head'.  For each such address, if the bottom 29
+bits of the 'lock word' at offset 'offset' from that address equals the
+exiting threads TID, then the kernel will do two things:
+
+ 1) if bit 31 (0x80000000) is set in that word, then attempt a futex
+    wakeup on that address, which will waken the next thread that has
+    used to the futex mechanism to wait on that address, and
+ 2) atomically set  bit 30 (0x40000000) in the 'lock word'.
+
+In the above, bit 31 was set by futex waiters on that lock to indicate
+they were waiting, and bit 30 is set by the kernel to indicate that the
+lock owner died holding the lock.
+
+The kernel exit code will silently stop scanning the list further if at
+any point:
+
+ 1) the 'head' pointer or an subsequent linked list pointer
+    is not a valid address of a user space word
+ 2) the calculated location of the 'lock word' (address plus
+    'offset') is not the valud address of a 32 bit user space
+    word
+ 3) if the list contains more than 1 million (subject to
+    future kernel configuration changes) elements.
+
+When the kernel sees a list entry whose 'lock word' doesn't have the
+current threads TID in the lower 29 bits, it does nothing with that
+entry, and goes on to the next entry.
+
+Bit 29 (0x20000000) of the 'lock word' is reserved for future use.
diff --git a/Documentation/robust-futexes.txt b/Documentation/robust-futexes.txt
new file mode 100644
index 0000000..df82d75
--- /dev/null
+++ b/Documentation/robust-futexes.txt
@@ -0,0 +1,218 @@
+Started by: Ingo Molnar <mingo@redhat.com>
+
+Background
+----------
+
+what are robust futexes? To answer that, we first need to understand
+what futexes are: normal futexes are special types of locks that in the
+noncontended case can be acquired/released from userspace without having
+to enter the kernel.
+
+A futex is in essence a user-space address, e.g. a 32-bit lock variable
+field. If userspace notices contention (the lock is already owned and
+someone else wants to grab it too) then the lock is marked with a value
+that says "there's a waiter pending", and the sys_futex(FUTEX_WAIT)
+syscall is used to wait for the other guy to release it. The kernel
+creates a 'futex queue' internally, so that it can later on match up the
+waiter with the waker - without them having to know about each other.
+When the owner thread releases the futex, it notices (via the variable
+value) that there were waiter(s) pending, and does the
+sys_futex(FUTEX_WAKE) syscall to wake them up.  Once all waiters have
+taken and released the lock, the futex is again back to 'uncontended'
+state, and there's no in-kernel state associated with it. The kernel
+completely forgets that there ever was a futex at that address. This
+method makes futexes very lightweight and scalable.
+
+"Robustness" is about dealing with crashes while holding a lock: if a
+process exits prematurely while holding a pthread_mutex_t lock that is
+also shared with some other process (e.g. yum segfaults while holding a
+pthread_mutex_t, or yum is kill -9-ed), then waiters for that lock need
+to be notified that the last owner of the lock exited in some irregular
+way.
+
+To solve such types of problems, "robust mutex" userspace APIs were
+created: pthread_mutex_lock() returns an error value if the owner exits
+prematurely - and the new owner can decide whether the data protected by
+the lock can be recovered safely.
+
+There is a big conceptual problem with futex based mutexes though: it is
+the kernel that destroys the owner task (e.g. due to a SEGFAULT), but
+the kernel cannot help with the cleanup: if there is no 'futex queue'
+(and in most cases there is none, futexes being fast lightweight locks)
+then the kernel has no information to clean up after the held lock!
+Userspace has no chance to clean up after the lock either - userspace is
+the one that crashes, so it has no opportunity to clean up. Catch-22.
+
+In practice, when e.g. yum is kill -9-ed (or segfaults), a system reboot
+is needed to release that futex based lock. This is one of the leading
+bugreports against yum.
+
+To solve this problem, the traditional approach was to extend the vma
+(virtual memory area descriptor) concept to have a notion of 'pending
+robust futexes attached to this area'. This approach requires 3 new
+syscall variants to sys_futex(): FUTEX_REGISTER, FUTEX_DEREGISTER and
+FUTEX_RECOVER. At do_exit() time, all vmas are searched to see whether
+they have a robust_head set. This approach has two fundamental problems
+left:
+
+ - it has quite complex locking and race scenarios. The vma-based
+   approach had been pending for years, but they are still not completely
+   reliable.
+
+ - they have to scan _every_ vma at sys_exit() time, per thread!
+
+The second disadvantage is a real killer: pthread_exit() takes around 1
+microsecond on Linux, but with thousands (or tens of thousands) of vmas
+every pthread_exit() takes a millisecond or more, also totally
+destroying the CPU's L1 and L2 caches!
+
+This is very much noticeable even for normal process sys_exit_group()
+calls: the kernel has to do the vma scanning unconditionally! (this is
+because the kernel has no knowledge about how many robust futexes there
+are to be cleaned up, because a robust futex might have been registered
+in another task, and the futex variable might have been simply mmap()-ed
+into this process's address space).
+
+This huge overhead forced the creation of CONFIG_FUTEX_ROBUST so that
+normal kernels can turn it off, but worse than that: the overhead makes
+robust futexes impractical for any type of generic Linux distribution.
+
+So something had to be done.
+
+New approach to robust futexes
+------------------------------
+
+At the heart of this new approach there is a per-thread private list of
+robust locks that userspace is holding (maintained by glibc) - which
+userspace list is registered with the kernel via a new syscall [this
+registration happens at most once per thread lifetime]. At do_exit()
+time, the kernel checks this user-space list: are there any robust futex
+locks to be cleaned up?
+
+In the common case, at do_exit() time, there is no list registered, so
+the cost of robust futexes is just a simple current->robust_list != NULL
+comparison. If the thread has registered a list, then normally the list
+is empty. If the thread/process crashed or terminated in some incorrect
+way then the list might be non-empty: in this case the kernel carefully
+walks the list [not trusting it], and marks all locks that are owned by
+this thread with the FUTEX_OWNER_DEAD bit, and wakes up one waiter (if
+any).
+
+The list is guaranteed to be private and per-thread at do_exit() time,
+so it can be accessed by the kernel in a lockless way.
+
+There is one race possible though: since adding to and removing from the
+list is done after the futex is acquired by glibc, there is a few
+instructions window for the thread (or process) to die there, leaving
+the futex hung. To protect against this possibility, userspace (glibc)
+also maintains a simple per-thread 'list_op_pending' field, to allow the
+kernel to clean up if the thread dies after acquiring the lock, but just
+before it could have added itself to the list. Glibc sets this
+list_op_pending field before it tries to acquire the futex, and clears
+it after the list-add (or list-remove) has finished.
+
+That's all that is needed - all the rest of robust-futex cleanup is done
+in userspace [just like with the previous patches].
+
+Ulrich Drepper has implemented the necessary glibc support for this new
+mechanism, which fully enables robust mutexes.
+
+Key differences of this userspace-list based approach, compared to the
+vma based method:
+
+ - it's much, much faster: at thread exit time, there's no need to loop
+   over every vma (!), which the VM-based method has to do. Only a very
+   simple 'is the list empty' op is done.
+
+ - no VM changes are needed - 'struct address_space' is left alone.
+
+ - no registration of individual locks is needed: robust mutexes dont
+   need any extra per-lock syscalls. Robust mutexes thus become a very
+   lightweight primitive - so they dont force the application designer
+   to do a hard choice between performance and robustness - robust
+   mutexes are just as fast.
+
+ - no per-lock kernel allocation happens.
+
+ - no resource limits are needed.
+
+ - no kernel-space recovery call (FUTEX_RECOVER) is needed.
+
+ - the implementation and the locking is "obvious", and there are no
+   interactions with the VM.
+
+Performance
+-----------
+
+I have benchmarked the time needed for the kernel to process a list of 1
+million (!) held locks, using the new method [on a 2GHz CPU]:
+
+ - with FUTEX_WAIT set [contended mutex]: 130 msecs
+ - without FUTEX_WAIT set [uncontended mutex]: 30 msecs
+
+I have also measured an approach where glibc does the lock notification
+[which it currently does for !pshared robust mutexes], and that took 256
+msecs - clearly slower, due to the 1 million FUTEX_WAKE syscalls
+userspace had to do.
+
+(1 million held locks are unheard of - we expect at most a handful of
+locks to be held at a time. Nevertheless it's nice to know that this
+approach scales nicely.)
+
+Implementation details
+----------------------
+
+The patch adds two new syscalls: one to register the userspace list, and
+one to query the registered list pointer:
+
+ asmlinkage long
+ sys_set_robust_list(struct robust_list_head __user *head,
+                     size_t len);
+
+ asmlinkage long
+ sys_get_robust_list(int pid, struct robust_list_head __user **head_ptr,
+                     size_t __user *len_ptr);
+
+List registration is very fast: the pointer is simply stored in
+current->robust_list. [Note that in the future, if robust futexes become
+widespread, we could extend sys_clone() to register a robust-list head
+for new threads, without the need of another syscall.]
+
+So there is virtually zero overhead for tasks not using robust futexes,
+and even for robust futex users, there is only one extra syscall per
+thread lifetime, and the cleanup operation, if it happens, is fast and
+straightforward. The kernel doesnt have any internal distinction between
+robust and normal futexes.
+
+If a futex is found to be held at exit time, the kernel sets the
+following bit of the futex word:
+
+	#define FUTEX_OWNER_DIED        0x40000000
+
+and wakes up the next futex waiter (if any). User-space does the rest of
+the cleanup.
+
+Otherwise, robust futexes are acquired by glibc by putting the TID into
+the futex field atomically. Waiters set the FUTEX_WAITERS bit:
+
+	#define FUTEX_WAITERS           0x80000000
+
+and the remaining bits are for the TID.
+
+Testing, architecture support
+-----------------------------
+
+i've tested the new syscalls on x86 and x86_64, and have made sure the
+parsing of the userspace list is robust [ ;-) ] even if the list is
+deliberately corrupted.
+
+i386 and x86_64 syscalls are wired up at the moment, and Ulrich has
+tested the new glibc code (on x86_64 and i386), and it works for his
+robust-mutex testcases.
+
+All other architectures should build just fine too - but they wont have
+the new syscalls yet.
+
+Architectures need to implement the new futex_atomic_cmpxchg_inatomic()
+inline function before writing up the syscalls (that function returns
+-ENOSYS right now).
diff --git a/Documentation/rpc-cache.txt b/Documentation/rpc-cache.txt
index 2b5d443..5f757c8 100644
--- a/Documentation/rpc-cache.txt
+++ b/Documentation/rpc-cache.txt
@@ -1,4 +1,4 @@
-This document gives a brief introduction to the caching
+	This document gives a brief introduction to the caching
 mechanisms in the sunrpc layer that is used, in particular,
 for NFS authentication.
 
@@ -25,25 +25,17 @@
    - supporting 'NEGATIVE' as well as positive entries
    - allowing an EXPIRED time on cache items, and removing
      items after they expire, and are no longe in-use.
-
-   Future code extensions are expect to handle
    - making requests to user-space to fill in cache entries
    - allowing user-space to directly set entries in the cache
    - delaying RPC requests that depend on as-yet incomplete
      cache entries, and replaying those requests when the cache entry
      is complete.
-   - maintaining last-access times on cache entries
-   - clean out old entries when the caches become full
-
-The code for performing a cache lookup is also common, but in the form
-of a template.  i.e. a #define.
-Each cache defines a lookup function by using the DefineCacheLookup
-macro, or the simpler DefineSimpleCacheLookup macro
+   - clean out old entries as they expire.
 
 Creating a Cache
 ----------------
 
-1/ A cache needs a datum to cache.  This is in the form of a
+1/ A cache needs a datum to store.  This is in the form of a
    structure definition that must contain a
      struct cache_head
    as an element, usually the first.
@@ -51,35 +43,69 @@
    Each cache element is reference counted and contains
    expiry and update times for use in cache management.
 2/ A cache needs a "cache_detail" structure that
-   describes the cache.  This stores the hash table, and some
-   parameters for cache management.
-3/ A cache needs a lookup function.  This is created using
-   the DefineCacheLookup macro.  This lookup function is used both
-   to find entries and to update entries.  The normal mode for
-   updating an entry is to replace the old entry with a new
-   entry.  However it is possible to allow update-in-place
-   for those caches where it makes sense (no atomicity issues
-   or indirect reference counting issue)
-4/ A cache needs to be registered using cache_register().  This
-   includes in on a list of caches that will be regularly
-   cleaned to discard old data.  For this to work, some
-   thread must periodically call cache_clean
-   
+   describes the cache.  This stores the hash table, some
+   parameters for cache management, and some operations detailing how
+   to work with particular cache items.
+   The operations requires are:
+   	struct cache_head *alloc(void)
+		This simply allocates appropriate memory and returns
+   		a pointer to the cache_detail embedded within the
+		structure
+	void cache_put(struct kref *)
+		This is called when the last reference to an item is
+		is dropped.  The pointer passed is to the 'ref' field
+		in the cache_head.  cache_put should release any
+		references create by 'cache_init' and, if CACHE_VALID
+		is set, any references created by cache_update.
+		It should then release the memory allocated by
+   		'alloc'.
+        int match(struct cache_head *orig, struct cache_head *new)
+		test if the keys in the two structures match.  Return
+		1 if they do, 0 if they don't.
+	void init(struct cache_head *orig, struct cache_head *new)
+		Set the 'key' fields in 'new' from 'orig'.  This may
+		include taking references to shared objects.
+	void update(struct cache_head *orig, struct cache_head *new)
+		Set the 'content' fileds in 'new' from 'orig'.
+	int cache_show(struct seq_file *m, struct cache_detail *cd,
+			struct cache_head *h)
+		Optional.  Used to provide a /proc file that lists the
+		contents of a cache.  This should show one item,
+   		usually on just one line.
+	int cache_request(struct cache_detail *cd, struct cache_head *h,
+   		char **bpp, int *blen)
+		Format a request to be send to user-space for an item
+   		to be instantiated.  *bpp is a buffer of size *blen.
+		bpp should be moved forward over the encoded message,
+		and  *blen should be reduced to show how much free
+		space remains.  Return 0 on success or <0 if not
+		enough room or other problem.
+	int cache_parse(struct cache_detail *cd, char *buf, int len)
+		A message from user space has arrived to fill out a
+		cache entry.  It is in 'buf' of length 'len'.
+		cache_parse should parse this, find the item in the
+		cache with sunrpc_cache_lookup, and update the item
+		with sunrpc_cache_update.
+
+
+3/ A cache needs to be registered using cache_register().  This
+   includes it on a list of caches that will be regularly
+   cleaned to discard old data.
+
 Using a cache
 -------------
 
-To find a value in a cache, call the lookup function passing it a the
-datum which contains key, and possibly content, and a flag saying
-whether to update the cache with new data from the datum.   Depending
-on how the cache lookup function was defined, it may take an extra
-argument to identify the particular cache in question.
+To find a value in a cache, call sunrpc_cache_lookup passing a pointer
+to the cache_head in a sample item with the 'key' fields filled in.
+This will be passed to ->match to identify the target entry.  If no
+entry is found, a new entry will be create, added to the cache, and
+marked as not containing valid data.
 
-Except in cases of kmalloc failure, the lookup function
-will return a new datum which will store the key and
-may contain valid content, or may not.
-This datum is typically passed to cache_check which determines the
-validity of the datum and may later initiate an upcall to fill
-in the data.
+The item returned is typically passed to cache_check which will check
+if the data is valid, and may initiate an up-call to get fresh data.
+cache_check will return -ENOENT in the entry is negative or if an up
+call is needed but not possible, -EAGAIN if an upcall is pending,
+or 0 if the data is valid;
 
 cache_check can be passed a "struct cache_req *".  This structure is
 typically embedded in the actual request and can be used to create a
@@ -90,6 +116,13 @@
 revisited (->revisit).  It is expected that this method will
 reschedule the request for processing.
 
+The value returned by sunrpc_cache_lookup can also be passed to
+sunrpc_cache_update to set the content for the item.  A second item is
+passed which should hold the content.  If the item found by _lookup
+has valid data, then it is discarded and a new item is created.  This
+saves any user of an item from worrying about content changing while
+it is being inspected.  If the item found by _lookup does not contain
+valid data, then the content is copied across and CACHE_VALID is set.
 
 Populating a cache
 ------------------
@@ -114,8 +147,8 @@
 expiry time should be set on that item.
 
 Reading from a channel is a bit more interesting.  When a cache
-lookup fail, or when it suceeds but finds an entry that may soon
-expiry, a request is lodged for that cache item to be updated by
+lookup fails, or when it succeeds but finds an entry that may soon
+expire, a request is lodged for that cache item to be updated by
 user-space.  These requests appear in the channel file.
 
 Successive reads will return successive requests.
@@ -130,7 +163,7 @@
     write a response
   loop.
 
-If it dies and needs to be restarted, any requests that have not be
+If it dies and needs to be restarted, any requests that have not been
 answered will still appear in the file and will be read by the new
 instance of the helper.
 
@@ -142,10 +175,9 @@
 takes a cache item and encodes a request into the buffer
 provided.
 
-
 Note: If a cache has no active readers on the channel, and has had not
 active readers for more than 60 seconds, further requests will not be
-added to the channel but instead all looks that do not find a valid
+added to the channel but instead all lookups that do not find a valid
 entry will fail.  This is partly for backward compatibility: The
 previous nfs exports table was deemed to be authoritative and a
 failed lookup meant a definite 'no'.
@@ -154,18 +186,17 @@
 -----------------------
 
 While each cache is free to use it's own format for requests
-and responses over channel, the following is recommended are
+and responses over channel, the following is recommended as
 appropriate and support routines are available to help:
 Each request or response record should be printable ASCII
 with precisely one newline character which should be at the end.
 Fields within the record should be separated by spaces, normally one.
 If spaces, newlines, or nul characters are needed in a field they
-much be quotes.  two mechanisms are available:
+much be quoted.  two mechanisms are available:
 1/ If a field begins '\x' then it must contain an even number of
    hex digits, and pairs of these digits provide the bytes in the
    field.
 2/ otherwise a \ in the field must be followed by 3 octal digits
    which give the code for a byte.  Other characters are treated
-   as them selves.  At the very least, space, newlines nul, and
+   as them selves.  At the very least, space, newline, nul, and
    '\' must be quoted in this way.
-   
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
index 6dc9d9f..6feef9e 100644
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
@@ -2836,7 +2836,7 @@
 
         <para>
 	Note that this callback became non-atomic since the recent version.
-	You can use schedule-related fucntions safely in this callback now.
+	You can use schedule-related functions safely in this callback now.
         </para>
 
         <para>
diff --git a/MAINTAINERS b/MAINTAINERS
index 4e8fbbc..c946581 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -882,13 +882,34 @@
 S:	Maintained
 
 EDAC-CORE
-P:      Doug Thompson
-M:      norsk5@xmission.com, dthompson@linuxnetworx.com
-P:      Dave Peterson
-M:      dsp@llnl.gov, dave_peterson@pobox.com
-L:      bluesmoke-devel@lists.sourceforge.net
-W:      bluesmoke.sourceforge.net
-S:      Maintained
+P:	Doug Thompson
+M:	norsk5@xmission.com, dthompson@linuxnetworx.com
+P:	Dave Peterson
+M:	dsp@llnl.gov, dave_peterson@pobox.com
+L:	bluesmoke-devel@lists.sourceforge.net
+W:	bluesmoke.sourceforge.net
+S:	Maintained
+
+EDAC-E752X
+P:	Dave Peterson
+M:	dsp@llnl.gov, dave_peterson@pobox.com
+L:	bluesmoke-devel@lists.sourceforge.net
+W:	bluesmoke.sourceforge.net
+S:	Maintained
+
+EDAC-E7XXX
+P:	Dave Peterson
+M:	dsp@llnl.gov, dave_peterson@pobox.com
+L:	bluesmoke-devel@lists.sourceforge.net
+W:	bluesmoke.sourceforge.net
+S:	Maintained
+
+EDAC-R82600
+P:	Tim Small
+M:	tim@buttersideup.com
+L:	bluesmoke-devel@lists.sourceforge.net
+W:	bluesmoke.sourceforge.net
+S:	Maintained
 
 EEPRO100 NETWORK DRIVER
 P:	Andrey V. Savochkin
@@ -1039,6 +1060,15 @@
 W:	http://www.kernel.org/pub/linux/utils/net/hdlc/
 S:	Maintained
 
+GIGASET ISDN DRIVERS
+P:	Hansjoerg Lipp
+M:	hjlipp@web.de
+P:	Tilman Schmidt
+M:	tilman@imap.cc
+L:	gigaset307x-common@lists.sourceforge.net
+W:	http://gigaset307x.sourceforge.net/
+S:	Maintained
+
 HARDWARE MONITORING
 P:	Jean Delvare
 M:	khali@linux-fr.org
@@ -1855,6 +1885,7 @@
 P:	Networking Team
 M:	netdev@vger.kernel.org
 L:	netdev@vger.kernel.org
+W:	http://linux-net.osdl.org/
 S:	Maintained
 
 NETWORKING [IPv4/IPv6]
@@ -2203,6 +2234,12 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+REAL TIME CLOCK (RTC) SUBSYSTEM
+P:	Alessandro Zummo
+M:	a.zummo@towertech.it
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+
 REISERFS FILE SYSTEM
 P:	Hans Reiser
 M:	reiserfs-dev@namesys.com
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index eedf41b..9bef61b 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -25,6 +25,10 @@
 	bool
 	default y
 
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
@@ -447,6 +451,10 @@
 	depends on ALPHA_NAUTILUS
 	default y
 
+config GENERIC_HWEIGHT
+	bool
+	default y if !ALPHA_EV6 && !ALPHA_EV67
+
 config ALPHA_AVANTI
 	bool
 	depends on ALPHA_XL || ALPHA_AVANTI_CH
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index 1898ea7..9d6186d 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -216,8 +216,6 @@
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memchr);
 
-EXPORT_SYMBOL(get_wchan);
-
 #ifdef CONFIG_ALPHA_IRONGATE
 EXPORT_SYMBOL(irongate_ioremap);
 EXPORT_SYMBOL(irongate_iounmap);
diff --git a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c
index 44866cb..7f6a984 100644
--- a/arch/alpha/kernel/core_marvel.c
+++ b/arch/alpha/kernel/core_marvel.c
@@ -435,7 +435,7 @@
 		str = pchar;
 	} while(*str);
 
-	return 0;
+	return 1;
 }
 __setup("io7=", marvel_specify_io7);
 
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 7fb14f4..31afe3d 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -821,7 +821,6 @@
    affects all sorts of things, like timeval and itimerval.  */
 
 extern struct timezone sys_tz;
-extern int do_adjtimex(struct timex *);
 
 struct timeval32
 {
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index b4e5f8f..dd87696 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -34,6 +34,7 @@
 #include <linux/root_dev.h>
 #include <linux/initrd.h>
 #include <linux/eisa.h>
+#include <linux/pfn.h>
 #ifdef CONFIG_MAGIC_SYSRQ
 #include <linux/sysrq.h>
 #include <linux/reboot.h>
@@ -42,7 +43,7 @@
 #include <asm/setup.h>
 #include <asm/io.h>
 
-extern struct notifier_block *panic_notifier_list;
+extern struct atomic_notifier_head panic_notifier_list;
 static int alpha_panic_event(struct notifier_block *, unsigned long, void *);
 static struct notifier_block alpha_panic_block = {
 	alpha_panic_event,
@@ -241,9 +242,6 @@
 		request_resource(io, standard_io_resources+i);
 }
 
-#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
-#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
 #define PFN_MAX		PFN_DOWN(0x80000000)
 #define for_each_mem_cluster(memdesc, cluster, i)		\
 	for ((cluster) = (memdesc)->cluster, (i) = 0;		\
@@ -472,11 +470,6 @@
 	return 0;
 }
 
-#undef PFN_UP
-#undef PFN_DOWN
-#undef PFN_PHYS
-#undef PFN_MAX
-
 void __init
 setup_arch(char **cmdline_p)
 {
@@ -507,7 +500,8 @@
 	}
 
 	/* Register a call for panic conditions. */
-	notifier_chain_register(&panic_notifier_list, &alpha_panic_block);
+	atomic_notifier_chain_register(&panic_notifier_list,
+			&alpha_panic_block);
 
 #ifdef CONFIG_ALPHA_GENERIC
 	/* Assume that we've booted from SRM if we haven't booted from MILO.
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index 6b2921b..3859749 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -314,10 +314,11 @@
 	if (!est_cycle_freq)
 		est_cycle_freq = validate_cc_value(calibrate_cc_with_pit());
 
-	cc1 = rpcc_after_update_in_progress();
+	cc1 = rpcc();
 
 	/* Calibrate CPU clock -- attempt #2.  */
 	if (!est_cycle_freq) {
+		cc1 = rpcc_after_update_in_progress();
 		cc2 = rpcc_after_update_in_progress();
 		est_cycle_freq = validate_cc_value(cc2 - cc1);
 		cc1 = cc2;
diff --git a/arch/alpha/lib/ev6-memchr.S b/arch/alpha/lib/ev6-memchr.S
index a8e843d..1a5f71b 100644
--- a/arch/alpha/lib/ev6-memchr.S
+++ b/arch/alpha/lib/ev6-memchr.S
@@ -84,7 +84,7 @@
         beq     $2, $not_found	# U : U L U L
 
 $found_it:
-#if defined(__alpha_fix__) && defined(__alpha_cix__)
+#ifdef CONFIG_ALPHA_EV67
 	/*
 	 * Since we are guaranteed to have set one of the bits, we don't
 	 * have to worry about coming back with a 0x40 out of cttz...
diff --git a/arch/alpha/lib/fpreg.c b/arch/alpha/lib/fpreg.c
index 97c4d9d..05017ba 100644
--- a/arch/alpha/lib/fpreg.c
+++ b/arch/alpha/lib/fpreg.c
@@ -4,7 +4,7 @@
  * (C) Copyright 1998 Linus Torvalds
  */
 
-#if defined(__alpha_cix__) || defined(__alpha_fix__)
+#if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
 #define STT(reg,val)  asm volatile ("ftoit $f"#reg",%0" : "=r"(val));
 #else
 #define STT(reg,val)  asm volatile ("stt $f"#reg",%0" : "=m"(val));
@@ -53,7 +53,7 @@
 	return val;
 }
 
-#if defined(__alpha_cix__) || defined(__alpha_fix__)
+#if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
 #define LDT(reg,val)  asm volatile ("itoft %0,$f"#reg : : "r"(val));
 #else
 #define LDT(reg,val)  asm volatile ("ldt $f"#reg",%0" : : "m"(val));
@@ -98,7 +98,7 @@
 	}
 }
 
-#if defined(__alpha_cix__) || defined(__alpha_fix__)
+#if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
 #define STS(reg,val)  asm volatile ("ftois $f"#reg",%0" : "=r"(val));
 #else
 #define STS(reg,val)  asm volatile ("sts $f"#reg",%0" : "=m"(val));
@@ -147,7 +147,7 @@
 	return val;
 }
 
-#if defined(__alpha_cix__) || defined(__alpha_fix__)
+#if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
 #define LDS(reg,val)  asm volatile ("itofs %0,$f"#reg : : "r"(val));
 #else
 #define LDS(reg,val)  asm volatile ("lds $f"#reg",%0" : : "m"(val));
diff --git a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c
index 6d52512..bf6b65c 100644
--- a/arch/alpha/mm/numa.c
+++ b/arch/alpha/mm/numa.c
@@ -13,6 +13,7 @@
 #include <linux/bootmem.h>
 #include <linux/swap.h>
 #include <linux/initrd.h>
+#include <linux/pfn.h>
 
 #include <asm/hwrpb.h>
 #include <asm/pgalloc.h>
@@ -27,9 +28,6 @@
 #define DBGDCONT(args...)
 #endif
 
-#define PFN_UP(x)       (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_DOWN(x)     ((x) >> PAGE_SHIFT)
-#define PFN_PHYS(x)     ((x) << PAGE_SHIFT)
 #define for_each_mem_cluster(memdesc, cluster, i)		\
 	for ((cluster) = (memdesc)->cluster, (i) = 0;		\
 	     (i) < (memdesc)->numclusters; (i)++, (cluster)++)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1077c67..dc5a933 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -8,6 +8,7 @@
 config ARM
 	bool
 	default y
+	select RTC_LIB
 	help
 	  The ARM series is a line of low-power-consumption RISC chip designs
 	  licensed by ARM Ltd and targeted at embedded applications and
@@ -53,6 +54,10 @@
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
@@ -842,6 +847,8 @@
 
 source "drivers/mfd/Kconfig"
 
+source "drivers/leds/Kconfig"
+
 source "drivers/media/Kconfig"
 
 source "drivers/video/Kconfig"
@@ -852,6 +859,8 @@
 
 source "drivers/mmc/Kconfig"
 
+source "drivers/rtc/Kconfig"
+
 endmenu
 
 source "fs/Kconfig"
diff --git a/arch/arm/common/rtctime.c b/arch/arm/common/rtctime.c
index e851d86..35c9a64 100644
--- a/arch/arm/common/rtctime.c
+++ b/arch/arm/common/rtctime.c
@@ -20,6 +20,7 @@
 #include <linux/capability.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
+#include <linux/rtc.h>
 
 #include <asm/rtc.h>
 #include <asm/semaphore.h>
@@ -42,89 +43,6 @@
 
 #define rtc_epoch 1900UL
 
-static const unsigned char days_in_month[] = {
-	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
-#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
-
-static int month_days(unsigned int month, unsigned int year)
-{
-	return days_in_month[month] + (LEAP_YEAR(year) && month == 1);
-}
-
-/*
- * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
- */
-void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
-{
-	int days, month, year;
-
-	days = time / 86400;
-	time -= days * 86400;
-
-	tm->tm_wday = (days + 4) % 7;
-
-	year = 1970 + days / 365;
-	days -= (year - 1970) * 365
-	        + LEAPS_THRU_END_OF(year - 1)
-	        - LEAPS_THRU_END_OF(1970 - 1);
-	if (days < 0) {
-		year -= 1;
-		days += 365 + LEAP_YEAR(year);
-	}
-	tm->tm_year = year - 1900;
-	tm->tm_yday = days + 1;
-
-	for (month = 0; month < 11; month++) {
-		int newdays;
-
-		newdays = days - month_days(month, year);
-		if (newdays < 0)
-			break;
-		days = newdays;
-	}
-	tm->tm_mon = month;
-	tm->tm_mday = days + 1;
-
-	tm->tm_hour = time / 3600;
-	time -= tm->tm_hour * 3600;
-	tm->tm_min = time / 60;
-	tm->tm_sec = time - tm->tm_min * 60;
-}
-EXPORT_SYMBOL(rtc_time_to_tm);
-
-/*
- * Does the rtc_time represent a valid date/time?
- */
-int rtc_valid_tm(struct rtc_time *tm)
-{
-	if (tm->tm_year < 70 ||
-	    tm->tm_mon >= 12 ||
-	    tm->tm_mday < 1 ||
-	    tm->tm_mday > month_days(tm->tm_mon, tm->tm_year + 1900) ||
-	    tm->tm_hour >= 24 ||
-	    tm->tm_min >= 60 ||
-	    tm->tm_sec >= 60)
-		return -EINVAL;
-
-	return 0;
-}
-EXPORT_SYMBOL(rtc_valid_tm);
-
-/*
- * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
- */
-int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
-{
-	*time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
-		       tm->tm_hour, tm->tm_min, tm->tm_sec);
-
-	return 0;
-}
-EXPORT_SYMBOL(rtc_tm_to_time);
-
 /*
  * Calculate the next alarm time given the requested alarm time mask
  * and the current time.
@@ -151,13 +69,13 @@
 	}
 }
 
-static inline int rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm)
+static inline int rtc_arm_read_time(struct rtc_ops *ops, struct rtc_time *tm)
 {
 	memset(tm, 0, sizeof(struct rtc_time));
 	return ops->read_time(tm);
 }
 
-static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm)
+static inline int rtc_arm_set_time(struct rtc_ops *ops, struct rtc_time *tm)
 {
 	int ret;
 
@@ -168,7 +86,7 @@
 	return ret;
 }
 
-static inline int rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
+static inline int rtc_arm_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
 {
 	int ret = -EINVAL;
 	if (ops->read_alarm) {
@@ -178,7 +96,7 @@
 	return ret;
 }
 
-static inline int rtc_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
+static inline int rtc_arm_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
 {
 	int ret = -EINVAL;
 	if (ops->set_alarm)
@@ -266,7 +184,7 @@
 
 	switch (cmd) {
 	case RTC_ALM_READ:
-		ret = rtc_read_alarm(ops, &alrm);
+		ret = rtc_arm_read_alarm(ops, &alrm);
 		if (ret)
 			break;
 		ret = copy_to_user(uarg, &alrm.time, sizeof(tm));
@@ -288,11 +206,11 @@
 		alrm.time.tm_wday = -1;
 		alrm.time.tm_yday = -1;
 		alrm.time.tm_isdst = -1;
-		ret = rtc_set_alarm(ops, &alrm);
+		ret = rtc_arm_set_alarm(ops, &alrm);
 		break;
 
 	case RTC_RD_TIME:
-		ret = rtc_read_time(ops, &tm);
+		ret = rtc_arm_read_time(ops, &tm);
 		if (ret)
 			break;
 		ret = copy_to_user(uarg, &tm, sizeof(tm));
@@ -310,7 +228,7 @@
 			ret = -EFAULT;
 			break;
 		}
-		ret = rtc_set_time(ops, &tm);
+		ret = rtc_arm_set_time(ops, &tm);
 		break;
 
 	case RTC_EPOCH_SET:
@@ -341,11 +259,11 @@
 			ret = -EFAULT;
 			break;
 		}
-		ret = rtc_set_alarm(ops, &alrm);
+		ret = rtc_arm_set_alarm(ops, &alrm);
 		break;
 
 	case RTC_WKALM_RD:
-		ret = rtc_read_alarm(ops, &alrm);
+		ret = rtc_arm_read_alarm(ops, &alrm);
 		if (ret)
 			break;
 		ret = copy_to_user(uarg, &alrm, sizeof(alrm));
@@ -435,7 +353,7 @@
 	struct rtc_time tm;
 	char *p = page;
 
-	if (rtc_read_time(ops, &tm) == 0) {
+	if (rtc_arm_read_time(ops, &tm) == 0) {
 		p += sprintf(p,
 			"rtc_time\t: %02d:%02d:%02d\n"
 			"rtc_date\t: %04d-%02d-%02d\n"
@@ -445,7 +363,7 @@
 			rtc_epoch);
 	}
 
-	if (rtc_read_alarm(ops, &alrm) == 0) {
+	if (rtc_arm_read_alarm(ops, &alrm) == 0) {
 		p += sprintf(p, "alrm_time\t: ");
 		if ((unsigned int)alrm.time.tm_hour <= 24)
 			p += sprintf(p, "%02d:", alrm.time.tm_hour);
diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c
index 978d32e..3cd8c9e 100644
--- a/arch/arm/common/sharpsl_pm.c
+++ b/arch/arm/common/sharpsl_pm.c
@@ -22,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/leds.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
@@ -75,6 +76,7 @@
 struct sharpsl_pm_status sharpsl_pm;
 DECLARE_WORK(toggle_charger, sharpsl_charge_toggle, NULL);
 DECLARE_WORK(sharpsl_bat, sharpsl_battery_thread, NULL);
+DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger);
 
 
 static int get_percentage(int voltage)
@@ -190,10 +192,10 @@
 		dev_err(sharpsl_pm.dev, "Charging Error!\n");
 	} else if (val == SHARPSL_LED_ON) {
 		dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
-
+		led_trigger_event(sharpsl_charge_led_trigger, LED_FULL);
 	} else {
 		dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
-
+		led_trigger_event(sharpsl_charge_led_trigger, LED_OFF);
 	}
 }
 
@@ -786,6 +788,8 @@
 	init_timer(&sharpsl_pm.chrg_full_timer);
 	sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer;
 
+	led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger);
+
 	sharpsl_pm.machinfo->init();
 
 	device_create_file(&pdev->dev, &dev_attr_battery_percentage);
@@ -807,6 +811,8 @@
 	device_remove_file(&pdev->dev, &dev_attr_battery_percentage);
 	device_remove_file(&pdev->dev, &dev_attr_battery_voltage);
 
+	led_trigger_unregister_simple(sharpsl_charge_led_trigger);
+
 	sharpsl_pm.machinfo->exit();
 
 	del_timer_sync(&sharpsl_pm.chrg_full_timer);
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 489c069..1ff75ce 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -474,4 +474,3 @@
 	} while (count ++ < 16);
 	return 0;
 }
-EXPORT_SYMBOL(get_wchan);
diff --git a/arch/arm/lib/copy_template.S b/arch/arm/lib/copy_template.S
index 838e435..cab355c 100644
--- a/arch/arm/lib/copy_template.S
+++ b/arch/arm/lib/copy_template.S
@@ -236,7 +236,7 @@
 
 
 /*
- * Abort preanble and completion macros.
+ * Abort preamble and completion macros.
  * If a fixup handler is required then those macros must surround it.
  * It is assumed that the fixup code will handle the private part of
  * the exit macro.
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 865427b..2d892e4 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -30,7 +30,9 @@
 #include <linux/time.h>
 #include <linux/timex.h>
 #include <linux/delay.h>
+#include <linux/termios.h>
 #include <linux/amba/bus.h>
+#include <linux/amba/serial.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -360,6 +362,68 @@
 /*************************************************************************
  * EP93xx peripheral handling
  *************************************************************************/
+#define EP93XX_UART_MCR_OFFSET		(0x0100)
+
+static void ep93xx_uart_set_mctrl(struct amba_device *dev,
+				  void __iomem *base, unsigned int mctrl)
+{
+	unsigned int mcr;
+
+	mcr = 0;
+	if (!(mctrl & TIOCM_RTS))
+		mcr |= 2;
+	if (!(mctrl & TIOCM_DTR))
+		mcr |= 1;
+
+	__raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET);
+}
+
+static struct amba_pl010_data ep93xx_uart_data = {
+	.set_mctrl	= ep93xx_uart_set_mctrl,
+};
+
+static struct amba_device uart1_device = {
+	.dev		= {
+		.bus_id		= "apb:uart1",
+		.platform_data	= &ep93xx_uart_data,
+	},
+	.res		= {
+		.start	= EP93XX_UART1_PHYS_BASE,
+		.end	= EP93XX_UART1_PHYS_BASE + 0x0fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= { IRQ_EP93XX_UART1, NO_IRQ },
+	.periphid	= 0x00041010,
+};
+
+static struct amba_device uart2_device = {
+	.dev		= {
+		.bus_id		= "apb:uart2",
+		.platform_data	= &ep93xx_uart_data,
+	},
+	.res		= {
+		.start	= EP93XX_UART2_PHYS_BASE,
+		.end	= EP93XX_UART2_PHYS_BASE + 0x0fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= { IRQ_EP93XX_UART2, NO_IRQ },
+	.periphid	= 0x00041010,
+};
+
+static struct amba_device uart3_device = {
+	.dev		= {
+		.bus_id		= "apb:uart3",
+		.platform_data	= &ep93xx_uart_data,
+	},
+	.res		= {
+		.start	= EP93XX_UART3_PHYS_BASE,
+		.end	= EP93XX_UART3_PHYS_BASE + 0x0fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= { IRQ_EP93XX_UART3, NO_IRQ },
+	.periphid	= 0x00041010,
+};
+
 void __init ep93xx_init_devices(void)
 {
 	unsigned int v;
@@ -371,4 +435,8 @@
 	v &= ~EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE;
 	__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
 	__raw_writel(v, EP93XX_SYSCON_DEVICE_CONFIG);
+
+	amba_device_register(&uart1_device, &iomem_resource);
+	amba_device_register(&uart2_device, &iomem_resource);
+	amba_device_register(&uart3_device, &iomem_resource);
 }
diff --git a/arch/arm/mach-footbridge/time.c b/arch/arm/mach-footbridge/time.c
index 2c64a0b..5d02e95 100644
--- a/arch/arm/mach-footbridge/time.c
+++ b/arch/arm/mach-footbridge/time.c
@@ -34,27 +34,12 @@
 static unsigned long __init get_isa_cmos_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
-	int i;
 
 	// check to see if the RTC makes sense.....
 	if ((CMOS_READ(RTC_VALID) & RTC_VRT) == 0)
 		return mktime(1970, 1, 1, 0, 0, 0);
 
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-	/* read RTC exactly on falling edge of update flag */
-	for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
-		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-			break;
-
-	for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
-		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-			break;
-
-	do { /* Isn't this overkill ? UIP above should guarantee consistency */
+	do {
 		sec  = CMOS_READ(RTC_SECONDS);
 		min  = CMOS_READ(RTC_MINUTES);
 		hour = CMOS_READ(RTC_HOURS);
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index 20071a2..576a5e9 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -15,7 +15,9 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
+#include <linux/termios.h>
 #include <linux/amba/bus.h>
+#include <linux/amba/serial.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
@@ -28,6 +30,8 @@
 
 #include "common.h"
 
+static struct amba_pl010_data integrator_uart_data;
+
 static struct amba_device rtc_device = {
 	.dev		= {
 		.bus_id	= "mb:15",
@@ -44,6 +48,7 @@
 static struct amba_device uart0_device = {
 	.dev		= {
 		.bus_id	= "mb:16",
+		.platform_data = &integrator_uart_data,
 	},
 	.res		= {
 		.start	= INTEGRATOR_UART0_BASE,
@@ -57,6 +62,7 @@
 static struct amba_device uart1_device = {
 	.dev		= {
 		.bus_id	= "mb:17",
+		.platform_data = &integrator_uart_data,
 	},
 	.res		= {
 		.start	= INTEGRATOR_UART1_BASE,
@@ -115,6 +121,46 @@
 
 arch_initcall(integrator_init);
 
+/*
+ * On the Integrator platform, the port RTS and DTR are provided by
+ * bits in the following SC_CTRLS register bits:
+ *        RTS  DTR
+ *  UART0  7    6
+ *  UART1  5    4
+ */
+#define SC_CTRLC	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
+#define SC_CTRLS	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
+
+static void integrator_uart_set_mctrl(struct amba_device *dev, void __iomem *base, unsigned int mctrl)
+{
+	unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask;
+
+	if (dev == &uart0_device) {
+		rts_mask = 1 << 4;
+		dtr_mask = 1 << 5;
+	} else {
+		rts_mask = 1 << 6;
+		dtr_mask = 1 << 7;
+	}
+
+	if (mctrl & TIOCM_RTS)
+		ctrlc |= rts_mask;
+	else
+		ctrls |= rts_mask;
+
+	if (mctrl & TIOCM_DTR)
+		ctrlc |= dtr_mask;
+	else
+		ctrls |= dtr_mask;
+
+	__raw_writel(ctrls, SC_CTRLS);
+	__raw_writel(ctrlc, SC_CTRLC);
+}
+
+static struct amba_pl010_data integrator_uart_data = {
+	.set_mctrl = integrator_uart_set_mctrl,
+};
+
 #define CM_CTRL	IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET
 
 static DEFINE_SPINLOCK(cm_lock);
diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c
index 3c22c16..bc07f52 100644
--- a/arch/arm/mach-integrator/time.c
+++ b/arch/arm/mach-integrator/time.c
@@ -40,13 +40,13 @@
 	return 1;
 }
 
-static int rtc_read_alarm(struct rtc_wkalrm *alrm)
+static int integrator_rtc_read_alarm(struct rtc_wkalrm *alrm)
 {
 	rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time);
 	return 0;
 }
 
-static inline int rtc_set_alarm(struct rtc_wkalrm *alrm)
+static inline int integrator_rtc_set_alarm(struct rtc_wkalrm *alrm)
 {
 	unsigned long time;
 	int ret;
@@ -62,7 +62,7 @@
 	return ret;
 }
 
-static int rtc_read_time(struct rtc_time *tm)
+static int integrator_rtc_read_time(struct rtc_time *tm)
 {
 	rtc_time_to_tm(readl(rtc_base + RTC_DR), tm);
 	return 0;
@@ -76,7 +76,7 @@
  * edge of the 1Hz clock, we must write the time one second
  * in advance.
  */
-static inline int rtc_set_time(struct rtc_time *tm)
+static inline int integrator_rtc_set_time(struct rtc_time *tm)
 {
 	unsigned long time;
 	int ret;
@@ -90,10 +90,10 @@
 
 static struct rtc_ops rtc_ops = {
 	.owner		= THIS_MODULE,
-	.read_time	= rtc_read_time,
-	.set_time	= rtc_set_time,
-	.read_alarm	= rtc_read_alarm,
-	.set_alarm	= rtc_set_alarm,
+	.read_time	= integrator_rtc_read_time,
+	.set_time	= integrator_rtc_set_time,
+	.read_alarm	= integrator_rtc_read_alarm,
+	.set_alarm	= integrator_rtc_set_alarm,
 };
 
 static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id,
diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c
index 60d5f8a..7520e60 100644
--- a/arch/arm/mach-omap1/board-netstar.c
+++ b/arch/arm/mach-omap1/board-netstar.c
@@ -141,7 +141,7 @@
 	/* TODO: Setup front panel switch here */
 
 	/* Setup panic notifier */
-	notifier_chain_register(&panic_notifier_list, &panic_block);
+	atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
 
 	return 0;
 }
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index bfd5fdd..52e4a9d 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -235,7 +235,7 @@
 static int __init voiceblue_setup(void)
 {
 	/* Setup panic notifier */
-	notifier_chain_register(&panic_notifier_list, &panic_block);
+	atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
 
 	return 0;
 }
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index 68923b1..d6d7260 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -141,6 +141,8 @@
  */
 static struct corgibl_machinfo corgi_bl_machinfo = {
 	.max_intensity = 0x2f,
+	.default_intensity = 0x1f,
+	.limit_mask = 0x0b,
 	.set_bl_intensity = corgi_bl_set_intensity,
 };
 
@@ -164,6 +166,14 @@
 
 
 /*
+ * Corgi LEDs
+ */
+static struct platform_device corgiled_device = {
+	.name		= "corgi-led",
+	.id		= -1,
+};
+
+/*
  * Corgi Touch Screen Device
  */
 static struct resource corgits_resources[] = {
@@ -297,6 +307,7 @@
 	&corgikbd_device,
 	&corgibl_device,
 	&corgits_device,
+	&corgiled_device,
 };
 
 static void __init corgi_init(void)
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index 9b48a90..5efa847 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -319,6 +319,11 @@
 	pxaficp_device.dev.platform_data = info;
 }
 
+static struct platform_device pxartc_device = {
+	.name		= "sa1100-rtc",
+	.id		= -1,
+};
+
 static struct platform_device *devices[] __initdata = {
 	&pxamci_device,
 	&udc_device,
@@ -329,6 +334,7 @@
 	&pxaficp_device,
 	&i2c_device,
 	&i2s_device,
+	&pxartc_device,
 };
 
 static int __init pxa_init(void)
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 0dbb079..19b372d 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -220,6 +220,8 @@
  * Spitz Backlight Device
  */
 static struct corgibl_machinfo spitz_bl_machinfo = {
+	.default_intensity = 0x1f,
+	.limit_mask = 0x0b,
 	.max_intensity = 0x2f,
 };
 
@@ -242,6 +244,14 @@
 
 
 /*
+ * Spitz LEDs
+ */
+static struct platform_device spitzled_device = {
+	.name		= "spitz-led",
+	.id		= -1,
+};
+
+/*
  * Spitz Touch Screen Device
  */
 static struct resource spitzts_resources[] = {
@@ -418,6 +428,7 @@
 	&spitzkbd_device,
 	&spitzts_device,
 	&spitzbl_device,
+	&spitzled_device,
 };
 
 static void __init common_init(void)
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index 66ec717..76c0e7f 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -251,10 +251,19 @@
 	.id		= -1,
 };
 
+/*
+ * Tosa LEDs
+ */
+static struct platform_device tosaled_device = {
+    .name   = "tosa-led",
+    .id     = -1,
+};
+
 static struct platform_device *devices[] __initdata = {
 	&tosascoop_device,
 	&tosascoop_jc_device,
 	&tosakbd_device,
+	&tosaled_device,
 };
 
 static void __init tosa_init(void)
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index 2abdc41..9ea7155 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -324,6 +324,11 @@
 	sa11x0ir_device.dev.platform_data = irda;
 }
 
+static struct platform_device sa11x0rtc_device = {
+	.name		= "sa1100-rtc",
+	.id		= -1,
+};
+
 static struct platform_device *sa11x0_devices[] __initdata = {
 	&sa11x0udc_device,
 	&sa11x0uart1_device,
@@ -333,6 +338,7 @@
 	&sa11x0pcmcia_device,
 	&sa11x0fb_device,
 	&sa11x0mtd_device,
+	&sa11x0rtc_device,
 };
 
 static int __init sa1100_init(void)
diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig
index dee23d8..cf4ebf4 100644
--- a/arch/arm26/Kconfig
+++ b/arch/arm26/Kconfig
@@ -41,6 +41,10 @@
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff --git a/arch/arm26/kernel/armksyms.c b/arch/arm26/kernel/armksyms.c
index 811a6376c..a6a1b33 100644
--- a/arch/arm26/kernel/armksyms.c
+++ b/arch/arm26/kernel/armksyms.c
@@ -212,8 +212,6 @@
 EXPORT_SYMBOL(sys_exit);
 EXPORT_SYMBOL(sys_wait4);
 
-EXPORT_SYMBOL(get_wchan);
-
 #ifdef CONFIG_PREEMPT
 EXPORT_SYMBOL(kernel_flag);
 #endif
diff --git a/arch/arm26/kernel/traps.c b/arch/arm26/kernel/traps.c
index 5847ea5..a79de04 100644
--- a/arch/arm26/kernel/traps.c
+++ b/arch/arm26/kernel/traps.c
@@ -34,7 +34,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "ptrace.h"
 
@@ -207,19 +207,19 @@
     	die(str, regs, err);
 }
 
-static DECLARE_MUTEX(undef_sem);
+static DEFINE_MUTEX(undef_mutex);
 static int (*undef_hook)(struct pt_regs *);
 
 int request_undef_hook(int (*fn)(struct pt_regs *))
 {
 	int ret = -EBUSY;
 
-	down(&undef_sem);
+	mutex_lock(&undef_mutex);
 	if (undef_hook == NULL) {
 		undef_hook = fn;
 		ret = 0;
 	}
-	up(&undef_sem);
+	mutex_unlock(&undef_mutex);
 
 	return ret;
 }
@@ -228,12 +228,12 @@
 {
 	int ret = -EINVAL;
 
-	down(&undef_sem);
+	mutex_lock(&undef_mutex);
 	if (undef_hook == fn) {
 		undef_hook = NULL;
 		ret = 0;
 	}
-	up(&undef_sem);
+	mutex_unlock(&undef_mutex);
 
 	return ret;
 }
diff --git a/arch/arm26/mm/init.c b/arch/arm26/mm/init.c
index e3ecaa4..7da8a52 100644
--- a/arch/arm26/mm/init.c
+++ b/arch/arm26/mm/init.c
@@ -23,6 +23,7 @@
 #include <linux/initrd.h>
 #include <linux/bootmem.h>
 #include <linux/blkdev.h>
+#include <linux/pfn.h>
 
 #include <asm/segment.h>
 #include <asm/mach-types.h>
@@ -101,12 +102,6 @@
 	int bootmap_pages;
 };
 
-#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
-#define PFN_UP(x)	(PAGE_ALIGN(x) >> PAGE_SHIFT)
-#define PFN_SIZE(x)	((x) >> PAGE_SHIFT)
-#define PFN_RANGE(s,e)	PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \
-				(((unsigned long)(s)) & PAGE_MASK))
-
 /*
  * FIXME: We really want to avoid allocating the bootmap bitmap
  * over the top of the initrd.  Hopefully, this is located towards
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index b832619..856b665 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -16,6 +16,14 @@
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c
index 1ba57ef..619a6ee 100644
--- a/arch/cris/kernel/setup.c
+++ b/arch/cris/kernel/setup.c
@@ -18,6 +18,7 @@
 #include <linux/seq_file.h>
 #include <linux/tty.h>
 #include <linux/utsname.h>
+#include <linux/pfn.h>
 
 #include <asm/setup.h>
 
@@ -88,10 +89,6 @@
 	init_mm.end_data =   (unsigned long) &_edata;
 	init_mm.brk =        (unsigned long) &_end;
 
-#define PFN_UP(x)       (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_DOWN(x)     ((x) >> PAGE_SHIFT)
-#define PFN_PHYS(x)     ((x) << PAGE_SHIFT)
-
 	/* min_low_pfn points to the start of DRAM, start_pfn points
 	 * to the first DRAM pages after the kernel, and max_low_pfn
 	 * to the end of DRAM.
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index e083837..95a3892 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -17,6 +17,10 @@
 	bool
 	default y
 
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default n
diff --git a/arch/frv/kernel/frv_ksyms.c b/arch/frv/kernel/frv_ksyms.c
index aa6b7d0..07c8ffa 100644
--- a/arch/frv/kernel/frv_ksyms.c
+++ b/arch/frv/kernel/frv_ksyms.c
@@ -79,8 +79,6 @@
 EXPORT_SYMBOL(__outsl_ns);
 EXPORT_SYMBOL(__insl_ns);
 
-EXPORT_SYMBOL(get_wchan);
-
 #ifdef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
 EXPORT_SYMBOL(atomic_test_and_ANDNOT_mask);
 EXPORT_SYMBOL(atomic_test_and_OR_mask);
diff --git a/arch/frv/mm/mmu-context.c b/arch/frv/mm/mmu-context.c
index f2c6866..1530a411 100644
--- a/arch/frv/mm/mmu-context.c
+++ b/arch/frv/mm/mmu-context.c
@@ -54,9 +54,9 @@
 		/* find the first unallocated context number
 		 * - 0 is reserved for the kernel
 		 */
-		cxn = find_next_zero_bit(&cxn_bitmap, NR_CXN, 1);
+		cxn = find_next_zero_bit(cxn_bitmap, NR_CXN, 1);
 		if (cxn < NR_CXN) {
-			set_bit(cxn, &cxn_bitmap);
+			set_bit(cxn, cxn_bitmap);
 		}
 		else {
 			/* none remaining - need to steal someone else's cxn */
@@ -138,7 +138,7 @@
 			cxn_pinned = -1;
 
 		list_del_init(&ctx->id_link);
-		clear_bit(ctx->id, &cxn_bitmap);
+		clear_bit(ctx->id, cxn_bitmap);
 		__flush_tlb_mm(ctx->id);
 		ctx->id = 0;
 	}
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 98308b0..cabf0bf 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -29,6 +29,14 @@
 	bool
 	default n
 
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff --git a/arch/h8300/kernel/h8300_ksyms.c b/arch/h8300/kernel/h8300_ksyms.c
index 69d6ad3..b6cd78c 100644
--- a/arch/h8300/kernel/h8300_ksyms.c
+++ b/arch/h8300/kernel/h8300_ksyms.c
@@ -55,8 +55,6 @@
 EXPORT_SYMBOL(memscan);
 EXPORT_SYMBOL(memmove);
 
-EXPORT_SYMBOL(get_wchan);
-
 /*
  * libgcc functions - functions that are used internally by the
  * compiler...  (prototypes are not correct though, but that
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index b008fb0..f17bd1d 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -37,6 +37,10 @@
 	bool
 	default y
 
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config ARCH_MAY_HAVE_PC_FDC
 	bool
 	default y
@@ -227,6 +231,15 @@
 	  cost of slightly increased overhead in some places. If unsure say
 	  N here.
 
+config SCHED_MC
+	bool "Multi-core scheduler support"
+	depends on SMP
+	default y
+	help
+	  Multi-core scheduler support improves the CPU scheduler's decision
+	  making when dealing with multi-core CPU chips at a cost of slightly
+	  increased overhead in some places. If unsure say N here.
+
 source "kernel/Kconfig.preempt"
 
 config X86_UP_APIC
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index c848a5b..3e4adb1 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -103,7 +103,7 @@
 boot := arch/i386/boot
 
 PHONY += zImage bzImage compressed zlilo bzlilo \
-         zdisk bzdisk fdimage fdimage144 fdimage288 install
+         zdisk bzdisk fdimage fdimage144 fdimage288 isoimage install
 
 all: bzImage
 
@@ -122,7 +122,7 @@
 zdisk bzdisk: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) zdisk
 
-fdimage fdimage144 fdimage288: vmlinux
+fdimage fdimage144 fdimage288 isoimage: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) $@
 
 install:
@@ -139,6 +139,9 @@
   echo  '		   install to $$(INSTALL_PATH) and run lilo'
   echo  '  bzdisk       - Create a boot floppy in /dev/fd0'
   echo  '  fdimage      - Create a boot floppy image'
+  echo  '  isoimage     - Create a boot CD-ROM image'
 endef
 
-CLEAN_FILES += arch/$(ARCH)/boot/fdimage arch/$(ARCH)/boot/mtools.conf
+CLEAN_FILES += arch/$(ARCH)/boot/fdimage \
+	       arch/$(ARCH)/boot/image.iso \
+	       arch/$(ARCH)/boot/mtools.conf
diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
index f136752..33e5547 100644
--- a/arch/i386/boot/Makefile
+++ b/arch/i386/boot/Makefile
@@ -62,8 +62,12 @@
 $(obj)/compressed/vmlinux: FORCE
 	$(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
 
-# Set this if you want to pass append arguments to the zdisk/fdimage kernel
+# Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
 FDARGS = 
+# Set this if you want an initrd included with the zdisk/fdimage/isoimage kernel
+FDINITRD =
+
+image_cmdline = default linux $(FDARGS) $(if $(FDINITRD),initrd=initrd.img,)
 
 $(obj)/mtools.conf: $(src)/mtools.conf.in
 	sed -e 's|@OBJ@|$(obj)|g' < $< > $@
@@ -72,8 +76,11 @@
 zdisk: $(BOOTIMAGE) $(obj)/mtools.conf
 	MTOOLSRC=$(obj)/mtools.conf mformat a:			; sync
 	syslinux /dev/fd0					; sync
-	echo 'default linux $(FDARGS)' | \
+	echo '$(image_cmdline)' | \
 		MTOOLSRC=$(src)/mtools.conf mcopy - a:syslinux.cfg
+	if [ -f '$(FDINITRD)' ] ; then \
+		MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' a:initrd.img ; \
+	fi
 	MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) a:linux	; sync
 
 # These require being root or having syslinux 2.02 or higher installed
@@ -81,18 +88,39 @@
 	dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=1440
 	MTOOLSRC=$(obj)/mtools.conf mformat v:			; sync
 	syslinux $(obj)/fdimage					; sync
-	echo 'default linux $(FDARGS)' | \
+	echo '$(image_cmdline)' | \
 		MTOOLSRC=$(obj)/mtools.conf mcopy - v:syslinux.cfg
+	if [ -f '$(FDINITRD)' ] ; then \
+		MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' v:initrd.img ; \
+	fi
 	MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) v:linux	; sync
 
 fdimage288: $(BOOTIMAGE) $(obj)/mtools.conf
 	dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=2880
 	MTOOLSRC=$(obj)/mtools.conf mformat w:			; sync
 	syslinux $(obj)/fdimage					; sync
-	echo 'default linux $(FDARGS)' | \
+	echo '$(image_cmdline)' | \
 		MTOOLSRC=$(obj)/mtools.conf mcopy - w:syslinux.cfg
+	if [ -f '$(FDINITRD)' ] ; then \
+		MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' w:initrd.img ; \
+	fi
 	MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) w:linux	; sync
 
+isoimage: $(BOOTIMAGE)
+	-rm -rf $(obj)/isoimage
+	mkdir $(obj)/isoimage
+	cp `echo /usr/lib*/syslinux/isolinux.bin | awk '{ print $1; }'` \
+		$(obj)/isoimage
+	cp $(BOOTIMAGE) $(obj)/isoimage/linux
+	echo '$(image_cmdline)' > $(obj)/isoimage/isolinux.cfg
+	if [ -f '$(FDINITRD)' ] ; then \
+		cp '$(FDINITRD)' $(obj)/isoimage/initrd.img ; \
+	fi
+	mkisofs -J -r -o $(obj)/image.iso -b isolinux.bin -c boot.cat \
+		-no-emul-boot -boot-load-size 4 -boot-info-table \
+		$(obj)/isoimage
+	rm -rf $(obj)/isoimage
+
 zlilo: $(BOOTIMAGE)
 	if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
 	if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
index 2ac40c8..0000a26 100644
--- a/arch/i386/boot/video.S
+++ b/arch/i386/boot/video.S
@@ -1924,6 +1924,7 @@
 	ret
 
 store_edid:
+#ifdef CONFIG_FB_FIRMWARE_EDID
 	pushw	%es				# just save all registers
 	pushw	%ax
 	pushw	%bx
@@ -1954,6 +1955,7 @@
 	popw	%bx
 	popw	%ax
 	popw	%es
+#endif
 	ret
 
 # VIDEO_SELECT-only variables
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index f1a2194..0330661 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -668,10 +668,10 @@
 	unsigned long rsdp_phys = 0;
 
 	if (efi_enabled) {
-		if (efi.acpi20)
-			return __pa(efi.acpi20);
-		else if (efi.acpi)
-			return __pa(efi.acpi);
+		if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
+			return efi.acpi20;
+		else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
+			return efi.acpi;
 	}
 	/*
 	 * Scan memory looking for the RSDP signature. First search EBDA (low
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index eb5279d..6273bf7 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -415,6 +415,7 @@
 void __devinit setup_local_APIC(void)
 {
 	unsigned long oldvalue, value, ver, maxlvt;
+	int i, j;
 
 	/* Pound the ESR really hard over the head with a big hammer - mbligh */
 	if (esr_disable) {
@@ -452,6 +453,25 @@
 	apic_write_around(APIC_TASKPRI, value);
 
 	/*
+	 * After a crash, we no longer service the interrupts and a pending
+	 * interrupt from previous kernel might still have ISR bit set.
+	 *
+	 * Most probably by now CPU has serviced that pending interrupt and
+	 * it might not have done the ack_APIC_irq() because it thought,
+	 * interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it
+	 * does not clear the ISR bit and cpu thinks it has already serivced
+	 * the interrupt. Hence a vector might get locked. It was noticed
+	 * for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
+	 */
+	for (i = APIC_ISR_NR - 1; i >= 0; i--) {
+		value = apic_read(APIC_ISR + i*0x10);
+		for (j = 31; j >= 0; j--) {
+			if (value & (1<<j))
+				ack_APIC_irq();
+		}
+	}
+
+	/*
 	 * Now that we are all set up, enable the APIC
 	 */
 	value = apic_read(APIC_SPIV);
@@ -732,7 +752,7 @@
 		printk(KERN_WARNING "APIC Verbosity level %s not recognised"
 				" use apic=verbose or apic=debug\n", str);
 
-	return 0;
+	return 1;
 }
 
 __setup("apic=", apic_set_verbosity);
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index 7e3d6b6..a06a490 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -266,7 +266,7 @@
 void __cpuinit generic_identify(struct cpuinfo_x86 * c)
 {
 	u32 tfms, xlvl;
-	int junk;
+	int ebx;
 
 	if (have_cpuid_p()) {
 		/* Get vendor name */
@@ -282,7 +282,7 @@
 		/* Intel-defined flags: level 0x00000001 */
 		if ( c->cpuid_level >= 0x00000001 ) {
 			u32 capability, excap;
-			cpuid(0x00000001, &tfms, &junk, &excap, &capability);
+			cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
 			c->x86_capability[0] = capability;
 			c->x86_capability[4] = excap;
 			c->x86 = (tfms >> 8) & 15;
@@ -292,6 +292,11 @@
 			if (c->x86 >= 0x6)
 				c->x86_model += ((tfms >> 16) & 0xF) << 4;
 			c->x86_mask = tfms & 15;
+#ifdef CONFIG_SMP
+			c->apicid = phys_pkg_id((ebx >> 24) & 0xFF, 0);
+#else
+			c->apicid = (ebx >> 24) & 0xFF;
+#endif
 		} else {
 			/* Have CPUID level 0 only - unheard of */
 			c->x86 = 4;
@@ -474,7 +479,6 @@
 
 	cpuid(1, &eax, &ebx, &ecx, &edx);
 
-	c->apicid = phys_pkg_id((ebx >> 24) & 0xFF, 0);
 
 	if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
 		return;
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
index e5bc064..712a26b 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
@@ -40,6 +40,7 @@
 
 #ifdef CONFIG_X86_POWERNOW_K8_ACPI
 #include <linux/acpi.h>
+#include <linux/mutex.h>
 #include <acpi/processor.h>
 #endif
 
@@ -49,7 +50,7 @@
 #include "powernow-k8.h"
 
 /* serialize freq changes  */
-static DECLARE_MUTEX(fidvid_sem);
+static DEFINE_MUTEX(fidvid_mutex);
 
 static struct powernow_k8_data *powernow_data[NR_CPUS];
 
@@ -943,17 +944,17 @@
 	if (cpufreq_frequency_table_target(pol, data->powernow_table, targfreq, relation, &newstate))
 		goto err_out;
 
-	down(&fidvid_sem);
+	mutex_lock(&fidvid_mutex);
 
 	powernow_k8_acpi_pst_values(data, newstate);
 
 	if (transition_frequency(data, newstate)) {
 		printk(KERN_ERR PFX "transition frequency failed\n");
 		ret = 1;
-		up(&fidvid_sem);
+		mutex_unlock(&fidvid_mutex);
 		goto err_out;
 	}
-	up(&fidvid_sem);
+	mutex_unlock(&fidvid_mutex);
 
 	pol->cur = find_khz_freq_from_fid(data->currfid);
 	ret = 0;
@@ -1094,10 +1095,15 @@
 
 static unsigned int powernowk8_get (unsigned int cpu)
 {
-	struct powernow_k8_data *data = powernow_data[cpu];
+	struct powernow_k8_data *data;
 	cpumask_t oldmask = current->cpus_allowed;
 	unsigned int khz = 0;
 
+	data = powernow_data[first_cpu(cpu_core_map[cpu])];
+
+	if (!data)
+		return -EINVAL;
+
 	set_cpus_allowed(current, cpumask_of_cpu(cpu));
 	if (smp_processor_id() != cpu) {
 		printk(KERN_ERR PFX "limiting to CPU %d failed in powernowk8_get\n", cpu);
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
index 00ea899..79a7c5c 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
@@ -182,10 +182,6 @@
 
 static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index);
 
-#ifndef for_each_cpu_mask
-#define for_each_cpu_mask(i,mask) for (i=0;i<1;i++)
-#endif
-
 #ifdef CONFIG_SMP
 static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[])
 {
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
index ce61921..9df87b0 100644
--- a/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ b/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -173,6 +173,10 @@
 	unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
 	unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
 	unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */
+	unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb;
+#ifdef CONFIG_SMP
+	unsigned int cpu = (c == &boot_cpu_data) ? 0 : (c - cpu_data);
+#endif
 
 	if (c->cpuid_level > 3) {
 		static int is_initialized;
@@ -205,9 +209,15 @@
 					break;
 				    case 2:
 					new_l2 = this_leaf.size/1024;
+					num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
+					index_msb = get_count_order(num_threads_sharing);
+					l2_id = c->apicid >> index_msb;
 					break;
 				    case 3:
 					new_l3 = this_leaf.size/1024;
+					num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
+					index_msb = get_count_order(num_threads_sharing);
+					l3_id = c->apicid >> index_msb;
 					break;
 				    default:
 					break;
@@ -215,11 +225,19 @@
 			}
 		}
 	}
-	if (c->cpuid_level > 1) {
+	/*
+	 * Don't use cpuid2 if cpuid4 is supported. For P4, we use cpuid2 for
+	 * trace cache
+	 */
+	if ((num_cache_leaves == 0 || c->x86 == 15) && c->cpuid_level > 1) {
 		/* supports eax=2  call */
 		int i, j, n;
 		int regs[4];
 		unsigned char *dp = (unsigned char *)regs;
+		int only_trace = 0;
+
+		if (num_cache_leaves != 0 && c->x86 == 15)
+			only_trace = 1;
 
 		/* Number of times to iterate */
 		n = cpuid_eax(2) & 0xFF;
@@ -241,6 +259,8 @@
 				while (cache_table[k].descriptor != 0)
 				{
 					if (cache_table[k].descriptor == des) {
+						if (only_trace && cache_table[k].cache_type != LVL_TRACE)
+							break;
 						switch (cache_table[k].cache_type) {
 						case LVL_1_INST:
 							l1i += cache_table[k].size;
@@ -266,35 +286,46 @@
 				}
 			}
 		}
-
-		if (new_l1d)
-			l1d = new_l1d;
-
-		if (new_l1i)
-			l1i = new_l1i;
-
-		if (new_l2)
-			l2 = new_l2;
-
-		if (new_l3)
-			l3 = new_l3;
-
-		if ( trace )
-			printk (KERN_INFO "CPU: Trace cache: %dK uops", trace);
-		else if ( l1i )
-			printk (KERN_INFO "CPU: L1 I cache: %dK", l1i);
-		if ( l1d )
-			printk(", L1 D cache: %dK\n", l1d);
-		else
-			printk("\n");
-		if ( l2 )
-			printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
-		if ( l3 )
-			printk(KERN_INFO "CPU: L3 cache: %dK\n", l3);
-
-		c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d));
 	}
 
+	if (new_l1d)
+		l1d = new_l1d;
+
+	if (new_l1i)
+		l1i = new_l1i;
+
+	if (new_l2) {
+		l2 = new_l2;
+#ifdef CONFIG_SMP
+		cpu_llc_id[cpu] = l2_id;
+#endif
+	}
+
+	if (new_l3) {
+		l3 = new_l3;
+#ifdef CONFIG_SMP
+		cpu_llc_id[cpu] = l3_id;
+#endif
+	}
+
+	if (trace)
+		printk (KERN_INFO "CPU: Trace cache: %dK uops", trace);
+	else if ( l1i )
+		printk (KERN_INFO "CPU: L1 I cache: %dK", l1i);
+
+	if (l1d)
+		printk(", L1 D cache: %dK\n", l1d);
+	else
+		printk("\n");
+
+	if (l2)
+		printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
+
+	if (l3)
+		printk(KERN_INFO "CPU: L3 cache: %dK\n", l3);
+
+	c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d));
+
 	return l2;
 }
 
diff --git a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c
index 6170af3..afa0888 100644
--- a/arch/i386/kernel/cpu/mcheck/mce.c
+++ b/arch/i386/kernel/cpu/mcheck/mce.c
@@ -64,13 +64,13 @@
 static int __init mcheck_disable(char *str)
 {
 	mce_disabled = 1;
-	return 0;
+	return 1;
 }
 
 static int __init mcheck_enable(char *str)
 {
 	mce_disabled = -1;
-	return 0;
+	return 1;
 }
 
 __setup("nomce", mcheck_disable);
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index 3b4618b..fff90bd 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -36,6 +36,7 @@
 #include <linux/pci.h>
 #include <linux/smp.h>
 #include <linux/cpu.h>
+#include <linux/mutex.h>
 
 #include <asm/mtrr.h>
 
@@ -47,7 +48,7 @@
 u32 num_var_ranges = 0;
 
 unsigned int *usage_table;
-static DECLARE_MUTEX(mtrr_sem);
+static DEFINE_MUTEX(mtrr_mutex);
 
 u32 size_or_mask, size_and_mask;
 
@@ -333,7 +334,7 @@
 	/* No CPU hotplug when we change MTRR entries */
 	lock_cpu_hotplug();
 	/*  Search for existing MTRR  */
-	down(&mtrr_sem);
+	mutex_lock(&mtrr_mutex);
 	for (i = 0; i < num_var_ranges; ++i) {
 		mtrr_if->get(i, &lbase, &lsize, &ltype);
 		if (base >= lbase + lsize)
@@ -371,7 +372,7 @@
 		printk(KERN_INFO "mtrr: no more MTRRs available\n");
 	error = i;
  out:
-	up(&mtrr_sem);
+	mutex_unlock(&mtrr_mutex);
 	unlock_cpu_hotplug();
 	return error;
 }
@@ -464,7 +465,7 @@
 	max = num_var_ranges;
 	/* No CPU hotplug when we change MTRR entries */
 	lock_cpu_hotplug();
-	down(&mtrr_sem);
+	mutex_lock(&mtrr_mutex);
 	if (reg < 0) {
 		/*  Search for existing MTRR  */
 		for (i = 0; i < max; ++i) {
@@ -503,7 +504,7 @@
 		set_mtrr(reg, 0, 0, 0);
 	error = reg;
  out:
-	up(&mtrr_sem);
+	mutex_unlock(&mtrr_mutex);
 	unlock_cpu_hotplug();
 	return error;
 }
@@ -685,7 +686,7 @@
 	if (!mtrr_if || !use_intel())
 		return;
 	/*
-	 * Ideally we should hold mtrr_sem here to avoid mtrr entries changed,
+	 * Ideally we should hold mtrr_mutex here to avoid mtrr entries changed,
 	 * but this routine will be called in cpu boot time, holding the lock
 	 * breaks it. This routine is called in two cases: 1.very earily time
 	 * of software resume, when there absolutely isn't mtrr entry changes;
diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
index ebc8dc1..5efceeb 100644
--- a/arch/i386/kernel/dmi_scan.c
+++ b/arch/i386/kernel/dmi_scan.c
@@ -3,6 +3,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/dmi.h>
+#include <linux/efi.h>
 #include <linux/bootmem.h>
 #include <linux/slab.h>
 #include <asm/dmi.h>
@@ -185,47 +186,72 @@
 	}
 }
 
-void __init dmi_scan_machine(void)
+static int __init dmi_present(char __iomem *p)
 {
 	u8 buf[15];
+	memcpy_fromio(buf, p, 15);
+	if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
+		u16 num = (buf[13] << 8) | buf[12];
+		u16 len = (buf[7] << 8) | buf[6];
+		u32 base = (buf[11] << 24) | (buf[10] << 16) |
+			(buf[9] << 8) | buf[8];
+
+		/*
+		 * DMI version 0.0 means that the real version is taken from
+		 * the SMBIOS version, which we don't know at this point.
+		 */
+		if (buf[14] != 0)
+			printk(KERN_INFO "DMI %d.%d present.\n",
+			       buf[14] >> 4, buf[14] & 0xF);
+		else
+			printk(KERN_INFO "DMI present.\n");
+		if (dmi_table(base,len, num, dmi_decode) == 0)
+			return 0;
+	}
+	return 1;
+}
+
+void __init dmi_scan_machine(void)
+{
 	char __iomem *p, *q;
+	int rc;
 
-	/*
-	 * no iounmap() for that ioremap(); it would be a no-op, but it's
-	 * so early in setup that sucker gets confused into doing what
-	 * it shouldn't if we actually call it.
-	 */
-	p = ioremap(0xF0000, 0x10000);
-	if (p == NULL)
-		goto out;
+	if (efi_enabled) {
+		if (efi.smbios == EFI_INVALID_TABLE_ADDR)
+			goto out;
 
-	for (q = p; q < p + 0x10000; q += 16) {
-		memcpy_fromio(buf, q, 15);
-		if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
-			u16 num = (buf[13] << 8) | buf[12];
-			u16 len = (buf[7] << 8) | buf[6];
-			u32 base = (buf[11] << 24) | (buf[10] << 16) |
-				   (buf[9] << 8) | buf[8];
+               /* This is called as a core_initcall() because it isn't
+                * needed during early boot.  This also means we can
+                * iounmap the space when we're done with it.
+		*/
+		p = dmi_ioremap(efi.smbios, 32);
+		if (p == NULL)
+			goto out;
 
-			/*
-			 * DMI version 0.0 means that the real version is taken from
-			 * the SMBIOS version, which we don't know at this point.
-			 */
-			if (buf[14] != 0)
-				printk(KERN_INFO "DMI %d.%d present.\n",
-					buf[14] >> 4, buf[14] & 0xF);
-			else
-				printk(KERN_INFO "DMI present.\n");
+		rc = dmi_present(p + 0x10); /* offset of _DMI_ string */
+		dmi_iounmap(p, 32);
+		if (!rc)
+			return;
+	}
+	else {
+		/*
+		 * no iounmap() for that ioremap(); it would be a no-op, but
+		 * it's so early in setup that sucker gets confused into doing
+		 * what it shouldn't if we actually call it.
+		 */
+		p = dmi_ioremap(0xF0000, 0x10000);
+		if (p == NULL)
+			goto out;
 
-			if (dmi_table(base,len, num, dmi_decode) == 0)
+		for (q = p; q < p + 0x10000; q += 16) {
+			rc = dmi_present(q);
+			if (!rc)
 				return;
 		}
 	}
-
-out:	printk(KERN_INFO "DMI not present or invalid.\n");
+ out:	printk(KERN_INFO "DMI not present or invalid.\n");
 }
 
-
 /**
  *	dmi_check_system - check system DMI data
  *	@list: array of dmi_system_id structures to match against
diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c
index 7ec6cfa..9202b67 100644
--- a/arch/i386/kernel/efi.c
+++ b/arch/i386/kernel/efi.c
@@ -361,7 +361,7 @@
 	 */
 	c16 = (efi_char16_t *) boot_ioremap(efi.systab->fw_vendor, 2);
 	if (c16) {
-		for (i = 0; i < sizeof(vendor) && *c16; ++i)
+		for (i = 0; i < (sizeof(vendor) - 1) && *c16; ++i)
 			vendor[i] = *c16++;
 		vendor[i] = '\0';
 	} else
@@ -381,29 +381,38 @@
 	if (config_tables == NULL)
 		printk(KERN_ERR PFX "Could not map EFI Configuration Table!\n");
 
+	efi.mps        = EFI_INVALID_TABLE_ADDR;
+	efi.acpi       = EFI_INVALID_TABLE_ADDR;
+	efi.acpi20     = EFI_INVALID_TABLE_ADDR;
+	efi.smbios     = EFI_INVALID_TABLE_ADDR;
+	efi.sal_systab = EFI_INVALID_TABLE_ADDR;
+	efi.boot_info  = EFI_INVALID_TABLE_ADDR;
+	efi.hcdp       = EFI_INVALID_TABLE_ADDR;
+	efi.uga        = EFI_INVALID_TABLE_ADDR;
+
 	for (i = 0; i < num_config_tables; i++) {
 		if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) {
-			efi.mps = (void *)config_tables[i].table;
+			efi.mps = config_tables[i].table;
 			printk(KERN_INFO " MPS=0x%lx ", config_tables[i].table);
 		} else
 		    if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) == 0) {
-			efi.acpi20 = __va(config_tables[i].table);
+			efi.acpi20 = config_tables[i].table;
 			printk(KERN_INFO " ACPI 2.0=0x%lx ", config_tables[i].table);
 		} else
 		    if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) {
-			efi.acpi = __va(config_tables[i].table);
+			efi.acpi = config_tables[i].table;
 			printk(KERN_INFO " ACPI=0x%lx ", config_tables[i].table);
 		} else
 		    if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) {
-			efi.smbios = (void *) config_tables[i].table;
+			efi.smbios = config_tables[i].table;
 			printk(KERN_INFO " SMBIOS=0x%lx ", config_tables[i].table);
 		} else
 		    if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
-			efi.hcdp = (void *)config_tables[i].table;
+			efi.hcdp = config_tables[i].table;
 			printk(KERN_INFO " HCDP=0x%lx ", config_tables[i].table);
 		} else
 		    if (efi_guidcmp(config_tables[i].guid, UGA_IO_PROTOCOL_GUID) == 0) {
-			efi.uga = (void *)config_tables[i].table;
+			efi.uga = config_tables[i].table;
 			printk(KERN_INFO " UGA=0x%lx ", config_tables[i].table);
 		}
 	}
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 311b4e7..f8f132a 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -381,7 +381,7 @@
 	unsigned long imbalance = 0;
 	cpumask_t allowed_mask, target_cpu_mask, tmp;
 
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		int package_index;
 		CPU_IRQ(i) = 0;
 		if (!cpu_online(i))
@@ -632,7 +632,7 @@
 	else 
 		printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq");
 failed:
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		kfree(irq_cpu_data[i].irq_delta);
 		irq_cpu_data[i].irq_delta = NULL;
 		kfree(irq_cpu_data[i].last_irq);
@@ -644,7 +644,7 @@
 int __init irqbalance_disable(char *str)
 {
 	irqbalance_disabled = 1;
-	return 0;
+	return 1;
 }
 
 __setup("noirqbalance", irqbalance_disable);
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index 7a59050..f197687 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -35,12 +35,56 @@
 #include <asm/cacheflush.h>
 #include <asm/kdebug.h>
 #include <asm/desc.h>
+#include <asm/uaccess.h>
 
 void jprobe_return_end(void);
 
 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
 DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
 
+/* insert a jmp code */
+static inline void set_jmp_op(void *from, void *to)
+{
+	struct __arch_jmp_op {
+		char op;
+		long raddr;
+	} __attribute__((packed)) *jop;
+	jop = (struct __arch_jmp_op *)from;
+	jop->raddr = (long)(to) - ((long)(from) + 5);
+	jop->op = RELATIVEJUMP_INSTRUCTION;
+}
+
+/*
+ * returns non-zero if opcodes can be boosted.
+ */
+static inline int can_boost(kprobe_opcode_t opcode)
+{
+	switch (opcode & 0xf0 ) {
+	case 0x70:
+		return 0; /* can't boost conditional jump */
+	case 0x90:
+		/* can't boost call and pushf */
+		return opcode != 0x9a && opcode != 0x9c;
+	case 0xc0:
+		/* can't boost undefined opcodes and soft-interruptions */
+		return (0xc1 < opcode && opcode < 0xc6) ||
+			(0xc7 < opcode && opcode < 0xcc) || opcode == 0xcf;
+	case 0xd0:
+		/* can boost AA* and XLAT */
+		return (opcode == 0xd4 || opcode == 0xd5 || opcode == 0xd7);
+	case 0xe0:
+		/* can boost in/out and (may be) jmps */
+		return (0xe3 < opcode && opcode != 0xe8);
+	case 0xf0:
+		/* clear and set flags can be boost */
+		return (opcode == 0xf5 || (0xf7 < opcode && opcode < 0xfe));
+	default:
+		/* currently, can't boost 2 bytes opcodes */
+		return opcode != 0x0f;
+	}
+}
+
+
 /*
  * returns non-zero if opcode modifies the interrupt flag.
  */
@@ -65,6 +109,11 @@
 
 	memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
 	p->opcode = *p->addr;
+	if (can_boost(p->opcode)) {
+		p->ainsn.boostable = 0;
+	} else {
+		p->ainsn.boostable = -1;
+	}
 	return 0;
 }
 
@@ -155,9 +204,13 @@
 {
 	struct kprobe *p;
 	int ret = 0;
-	kprobe_opcode_t *addr = NULL;
-	unsigned long *lp;
+	kprobe_opcode_t *addr;
 	struct kprobe_ctlblk *kcb;
+#ifdef CONFIG_PREEMPT
+	unsigned pre_preempt_count = preempt_count();
+#endif /* CONFIG_PREEMPT */
+
+	addr = (kprobe_opcode_t *)(regs->eip - sizeof(kprobe_opcode_t));
 
 	/*
 	 * We don't want to be preempted for the entire
@@ -166,17 +219,6 @@
 	preempt_disable();
 	kcb = get_kprobe_ctlblk();
 
-	/* Check if the application is using LDT entry for its code segment and
-	 * calculate the address by reading the base address from the LDT entry.
-	 */
-	if ((regs->xcs & 4) && (current->mm)) {
-		lp = (unsigned long *) ((unsigned long)((regs->xcs >> 3) * 8)
-					+ (char *) current->mm->context.ldt);
-		addr = (kprobe_opcode_t *) (get_desc_base(lp) + regs->eip -
-						sizeof(kprobe_opcode_t));
-	} else {
-		addr = (kprobe_opcode_t *)(regs->eip - sizeof(kprobe_opcode_t));
-	}
 	/* Check we're not actually recursing */
 	if (kprobe_running()) {
 		p = get_kprobe(addr);
@@ -252,6 +294,21 @@
 		/* handler has already set things up, so skip ss setup */
 		return 1;
 
+	if (p->ainsn.boostable == 1 &&
+#ifdef CONFIG_PREEMPT
+	    !(pre_preempt_count) && /*
+				       * This enables booster when the direct
+				       * execution path aren't preempted.
+				       */
+#endif /* CONFIG_PREEMPT */
+	    !p->post_handler && !p->break_handler ) {
+		/* Boost up -- we can execute copied instructions directly */
+		reset_current_kprobe();
+		regs->eip = (unsigned long)p->ainsn.insn;
+		preempt_enable_no_resched();
+		return 1;
+	}
+
 ss_probe:
 	prepare_singlestep(p, regs);
 	kcb->kprobe_status = KPROBE_HIT_SS;
@@ -267,17 +324,44 @@
  * here. When a retprobed function returns, this probe is hit and
  * trampoline_probe_handler() runs, calling the kretprobe's handler.
  */
- void kretprobe_trampoline_holder(void)
+ void __kprobes kretprobe_trampoline_holder(void)
  {
- 	asm volatile (  ".global kretprobe_trampoline\n"
+	asm volatile ( ".global kretprobe_trampoline\n"
  			"kretprobe_trampoline: \n"
- 			"nop\n");
- }
+			"	pushf\n"
+			/* skip cs, eip, orig_eax, es, ds */
+			"	subl $20, %esp\n"
+			"	pushl %eax\n"
+			"	pushl %ebp\n"
+			"	pushl %edi\n"
+			"	pushl %esi\n"
+			"	pushl %edx\n"
+			"	pushl %ecx\n"
+			"	pushl %ebx\n"
+			"	movl %esp, %eax\n"
+			"	call trampoline_handler\n"
+			/* move eflags to cs */
+			"	movl 48(%esp), %edx\n"
+			"	movl %edx, 44(%esp)\n"
+			/* save true return address on eflags */
+			"	movl %eax, 48(%esp)\n"
+			"	popl %ebx\n"
+			"	popl %ecx\n"
+			"	popl %edx\n"
+			"	popl %esi\n"
+			"	popl %edi\n"
+			"	popl %ebp\n"
+			"	popl %eax\n"
+			/* skip eip, orig_eax, es, ds */
+			"	addl $16, %esp\n"
+			"	popf\n"
+			"	ret\n");
+}
 
 /*
- * Called when we hit the probe point at kretprobe_trampoline
+ * Called from kretprobe_trampoline
  */
-int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+fastcall void *__kprobes trampoline_handler(struct pt_regs *regs)
 {
         struct kretprobe_instance *ri = NULL;
         struct hlist_head *head;
@@ -306,8 +390,11 @@
 			/* another task is sharing our hash bucket */
                         continue;
 
-		if (ri->rp && ri->rp->handler)
+		if (ri->rp && ri->rp->handler){
+			__get_cpu_var(current_kprobe) = &ri->rp->kp;
 			ri->rp->handler(ri, regs);
+			__get_cpu_var(current_kprobe) = NULL;
+		}
 
 		orig_ret_address = (unsigned long)ri->ret_addr;
 		recycle_rp_inst(ri);
@@ -322,18 +409,10 @@
 	}
 
 	BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
-	regs->eip = orig_ret_address;
 
-	reset_current_kprobe();
 	spin_unlock_irqrestore(&kretprobe_lock, flags);
-	preempt_enable_no_resched();
 
-	/*
-	 * By returning a non-zero value, we are telling
-	 * kprobe_handler() that we don't want the post_handler
-	 * to run (and have re-enabled preemption)
-	 */
-        return 1;
+	return (void*)orig_ret_address;
 }
 
 /*
@@ -357,15 +436,17 @@
  * 2) If the single-stepped instruction was a call, the return address
  * that is atop the stack is the address following the copied instruction.
  * We need to make it the address following the original instruction.
+ *
+ * This function also checks instruction size for preparing direct execution.
  */
 static void __kprobes resume_execution(struct kprobe *p,
 		struct pt_regs *regs, struct kprobe_ctlblk *kcb)
 {
 	unsigned long *tos = (unsigned long *)&regs->esp;
-	unsigned long next_eip = 0;
 	unsigned long copy_eip = (unsigned long)p->ainsn.insn;
 	unsigned long orig_eip = (unsigned long)p->addr;
 
+	regs->eflags &= ~TF_MASK;
 	switch (p->ainsn.insn[0]) {
 	case 0x9c:		/* pushfl */
 		*tos &= ~(TF_MASK | IF_MASK);
@@ -375,37 +456,51 @@
 	case 0xcb:
 	case 0xc2:
 	case 0xca:
-		regs->eflags &= ~TF_MASK;
-		/* eip is already adjusted, no more changes required*/
-		return;
+	case 0xea:		/* jmp absolute -- eip is correct */
+		/* eip is already adjusted, no more changes required */
+		p->ainsn.boostable = 1;
+		goto no_change;
 	case 0xe8:		/* call relative - Fix return addr */
 		*tos = orig_eip + (*tos - copy_eip);
 		break;
 	case 0xff:
 		if ((p->ainsn.insn[1] & 0x30) == 0x10) {
 			/* call absolute, indirect */
-			/* Fix return addr; eip is correct. */
-			next_eip = regs->eip;
+			/*
+			 * Fix return addr; eip is correct.
+			 * But this is not boostable
+			 */
 			*tos = orig_eip + (*tos - copy_eip);
+			goto no_change;
 		} else if (((p->ainsn.insn[1] & 0x31) == 0x20) ||	/* jmp near, absolute indirect */
 			   ((p->ainsn.insn[1] & 0x31) == 0x21)) {	/* jmp far, absolute indirect */
-			/* eip is correct. */
-			next_eip = regs->eip;
+			/* eip is correct. And this is boostable */
+			p->ainsn.boostable = 1;
+			goto no_change;
 		}
-		break;
-	case 0xea:		/* jmp absolute -- eip is correct */
-		next_eip = regs->eip;
-		break;
 	default:
 		break;
 	}
 
-	regs->eflags &= ~TF_MASK;
-	if (next_eip) {
-		regs->eip = next_eip;
-	} else {
-		regs->eip = orig_eip + (regs->eip - copy_eip);
+	if (p->ainsn.boostable == 0) {
+		if ((regs->eip > copy_eip) &&
+		    (regs->eip - copy_eip) + 5 < MAX_INSN_SIZE) {
+			/*
+			 * These instructions can be executed directly if it
+			 * jumps back to correct address.
+			 */
+			set_jmp_op((void *)regs->eip,
+				   (void *)orig_eip + (regs->eip - copy_eip));
+			p->ainsn.boostable = 1;
+		} else {
+			p->ainsn.boostable = -1;
+		}
 	}
+
+	regs->eip = orig_eip + (regs->eip - copy_eip);
+
+no_change:
+	return;
 }
 
 /*
@@ -453,15 +548,57 @@
 	struct kprobe *cur = kprobe_running();
 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
 
-	if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-		return 1;
-
-	if (kcb->kprobe_status & KPROBE_HIT_SS) {
-		resume_execution(cur, regs, kcb);
+	switch(kcb->kprobe_status) {
+	case KPROBE_HIT_SS:
+	case KPROBE_REENTER:
+		/*
+		 * We are here because the instruction being single
+		 * stepped caused a page fault. We reset the current
+		 * kprobe and the eip points back to the probe address
+		 * and allow the page fault handler to continue as a
+		 * normal page fault.
+		 */
+		regs->eip = (unsigned long)cur->addr;
 		regs->eflags |= kcb->kprobe_old_eflags;
-
-		reset_current_kprobe();
+		if (kcb->kprobe_status == KPROBE_REENTER)
+			restore_previous_kprobe(kcb);
+		else
+			reset_current_kprobe();
 		preempt_enable_no_resched();
+		break;
+	case KPROBE_HIT_ACTIVE:
+	case KPROBE_HIT_SSDONE:
+		/*
+		 * We increment the nmissed count for accounting,
+		 * we can also use npre/npostfault count for accouting
+		 * these specific fault cases.
+		 */
+		kprobes_inc_nmissed_count(cur);
+
+		/*
+		 * We come here because instructions in the pre/post
+		 * handler caused the page_fault, this could happen
+		 * if handler tries to access user space by
+		 * copy_from_user(), get_user() etc. Let the
+		 * user-specified handler try to fix it first.
+		 */
+		if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
+			return 1;
+
+		/*
+		 * In case the user-specified fault handler returned
+		 * zero, try to fix up.
+		 */
+		if (fixup_exception(regs))
+			return 1;
+
+		/*
+		 * fixup_exception() could not handle it,
+		 * Let do_page_fault() fix it.
+		 */
+		break;
+	default:
+		break;
 	}
 	return 0;
 }
@@ -475,6 +612,9 @@
 	struct die_args *args = (struct die_args *)data;
 	int ret = NOTIFY_DONE;
 
+	if (args->regs && user_mode(args->regs))
+		return ret;
+
 	switch (val) {
 	case DIE_INT3:
 		if (kprobe_handler(args->regs))
@@ -564,12 +704,7 @@
 	return 0;
 }
 
-static struct kprobe trampoline_p = {
-	.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
-	.pre_handler = trampoline_probe_handler
-};
-
 int __init arch_init_kprobes(void)
 {
-	return register_kprobe(&trampoline_p);
+	return 0;
 }
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index 55bc365..e7c138f 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -81,6 +81,7 @@
 #include <linux/miscdevice.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/mutex.h>
 
 #include <asm/msr.h>
 #include <asm/uaccess.h>
@@ -114,7 +115,7 @@
 static DEFINE_SPINLOCK(microcode_update_lock);
 
 /* no concurrent ->write()s are allowed on /dev/cpu/microcode */
-static DECLARE_MUTEX(microcode_sem);
+static DEFINE_MUTEX(microcode_mutex);
 
 static void __user *user_buffer;	/* user area microcode data buffer */
 static unsigned int user_buffer_size;	/* it's size */
@@ -444,7 +445,7 @@
 		return -EINVAL;
 	}
 
-	down(&microcode_sem);
+	mutex_lock(&microcode_mutex);
 
 	user_buffer = (void __user *) buf;
 	user_buffer_size = (int) len;
@@ -453,31 +454,14 @@
 	if (!ret)
 		ret = (ssize_t)len;
 
-	up(&microcode_sem);
+	mutex_unlock(&microcode_mutex);
 
 	return ret;
 }
 
-static int microcode_ioctl (struct inode *inode, struct file *file, 
-		unsigned int cmd, unsigned long arg)
-{
-	switch (cmd) {
-		/* 
-		 *  XXX: will be removed after microcode_ctl 
-		 *  is updated to ignore failure of this ioctl()
-		 */
-		case MICROCODE_IOCFREE:
-			return 0;
-		default:
-			return -EINVAL;
-	}
-	return -EINVAL;
-}
-
 static struct file_operations microcode_fops = {
 	.owner		= THIS_MODULE,
 	.write		= microcode_write,
-	.ioctl		= microcode_ioctl,
 	.open		= microcode_open,
 };
 
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index 9074818..d43b498 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -138,12 +138,12 @@
 	if (nmi_watchdog == NMI_LOCAL_APIC)
 		smp_call_function(nmi_cpu_busy, (void *)&endflag, 0, 0);
 
-	for_each_cpu(cpu)
+	for_each_possible_cpu(cpu)
 		prev_nmi_count[cpu] = per_cpu(irq_stat, cpu).__nmi_count;
 	local_irq_enable();
 	mdelay((10*1000)/nmi_hz); // wait 10 ticks
 
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 #ifdef CONFIG_SMP
 		/* Check cpu_callin_map here because that is set
 		   after the timer is started. */
@@ -510,7 +510,7 @@
 	 * Just reset the alert counters, (other CPUs might be
 	 * spinning on locks we hold):
 	 */
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 		alert_counter[i] = 0;
 
 	/*
@@ -529,7 +529,8 @@
 	 * always switch the stack NMI-atomically, it's safe to use
 	 * smp_processor_id().
 	 */
-	int sum, cpu = smp_processor_id();
+	unsigned int sum;
+	int cpu = smp_processor_id();
 
 	sum = per_cpu(irq_stat, cpu).apic_timer_irqs;
 
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 299e616..6259afe 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -38,7 +38,6 @@
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
 #include <linux/random.h>
-#include <linux/kprobes.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -364,13 +363,6 @@
 	struct task_struct *tsk = current;
 	struct thread_struct *t = &tsk->thread;
 
-	/*
-	 * Remove function-return probe instances associated with this task
-	 * and put them back on the free list. Do not insert an exit probe for
-	 * this function, it will be disabled by kprobe_flush_task if you do.
-	 */
-	kprobe_flush_task(tsk);
-
 	/* The process may have allocated an io port bitmap... nuke it. */
 	if (unlikely(NULL != t->io_bitmap_ptr)) {
 		int cpu = get_cpu();
@@ -789,7 +781,6 @@
 	} while (count++ < 16);
 	return 0;
 }
-EXPORT_SYMBOL(get_wchan);
 
 /*
  * sys_alloc_thread_area: get a yet unused TLS descriptor index.
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index d313a11..8c08660 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -46,6 +46,7 @@
 #include <linux/kexec.h>
 #include <linux/crash_dump.h>
 #include <linux/dmi.h>
+#include <linux/pfn.h>
 
 #include <video/edid.h>
 
@@ -1058,10 +1059,10 @@
 free_available_memory(unsigned long start, unsigned long end, void *arg)
 {
 	/* check max_low_pfn */
-	if (start >= ((max_low_pfn + 1) << PAGE_SHIFT))
+	if (start >= (max_low_pfn << PAGE_SHIFT))
 		return 0;
-	if (end >= ((max_low_pfn + 1) << PAGE_SHIFT))
-		end = (max_low_pfn + 1) << PAGE_SHIFT;
+	if (end >= (max_low_pfn << PAGE_SHIFT))
+		end = max_low_pfn << PAGE_SHIFT;
 	if (start < end)
 		free_bootmem(start, end - start);
 
@@ -1286,8 +1287,6 @@
 	probe_roms();
 	for (i = 0; i < e820.nr_map; i++) {
 		struct resource *res;
-		if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL)
-			continue;
 		res = kzalloc(sizeof(struct resource), GFP_ATOMIC);
 		switch (e820.map[i].type) {
 		case E820_RAM:	res->name = "System RAM"; break;
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 82371d8..a696990 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -72,6 +72,9 @@
 /* Core ID of each logical CPU */
 int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
 
+/* Last level cache ID of each logical CPU */
+int cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID};
+
 /* representing HT siblings of each logical CPU */
 cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
 EXPORT_SYMBOL(cpu_sibling_map);
@@ -440,6 +443,18 @@
 
 static int cpucount;
 
+/* maps the cpu to the sched domain representing multi-core */
+cpumask_t cpu_coregroup_map(int cpu)
+{
+	struct cpuinfo_x86 *c = cpu_data + cpu;
+	/*
+	 * For perf, we return last level cache shared map.
+	 * TBD: when power saving sched policy is added, we will return
+	 *      cpu_core_map when power saving policy is enabled
+	 */
+	return c->llc_shared_map;
+}
+
 /* representing cpus for which sibling maps can be computed */
 static cpumask_t cpu_sibling_setup_map;
 
@@ -459,12 +474,16 @@
 				cpu_set(cpu, cpu_sibling_map[i]);
 				cpu_set(i, cpu_core_map[cpu]);
 				cpu_set(cpu, cpu_core_map[i]);
+				cpu_set(i, c[cpu].llc_shared_map);
+				cpu_set(cpu, c[i].llc_shared_map);
 			}
 		}
 	} else {
 		cpu_set(cpu, cpu_sibling_map[cpu]);
 	}
 
+	cpu_set(cpu, c[cpu].llc_shared_map);
+
 	if (current_cpu_data.x86_max_cores == 1) {
 		cpu_core_map[cpu] = cpu_sibling_map[cpu];
 		c[cpu].booted_cores = 1;
@@ -472,6 +491,11 @@
 	}
 
 	for_each_cpu_mask(i, cpu_sibling_setup_map) {
+		if (cpu_llc_id[cpu] != BAD_APICID &&
+		    cpu_llc_id[cpu] == cpu_llc_id[i]) {
+			cpu_set(i, c[cpu].llc_shared_map);
+			cpu_set(cpu, c[i].llc_shared_map);
+		}
 		if (phys_proc_id[cpu] == phys_proc_id[i]) {
 			cpu_set(i, cpu_core_map[cpu]);
 			cpu_set(cpu, cpu_core_map[i]);
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index ac687d0..4f58b9c 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -310,3 +310,7 @@
 	.long sys_pselect6
 	.long sys_ppoll
 	.long sys_unshare		/* 310 */
+	.long sys_set_robust_list
+	.long sys_get_robust_list
+	.long sys_splice
+	.long sys_sync_file_range
diff --git a/arch/i386/kernel/timers/timer_pm.c b/arch/i386/kernel/timers/timer_pm.c
index 264edaa..144e94a 100644
--- a/arch/i386/kernel/timers/timer_pm.c
+++ b/arch/i386/kernel/timers/timer_pm.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/pci.h>
 #include <asm/types.h>
 #include <asm/timer.h>
 #include <asm/smp.h>
@@ -45,24 +46,31 @@
 
 #define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */
 
+static int pmtmr_need_workaround __read_mostly = 1;
+
 /*helper function to safely read acpi pm timesource*/
 static inline u32 read_pmtmr(void)
 {
-	u32 v1=0,v2=0,v3=0;
-	/* It has been reported that because of various broken
-	 * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM time
-	 * source is not latched, so you must read it multiple
-	 * times to insure a safe value is read.
-	 */
-	do {
-		v1 = inl(pmtmr_ioport);
-		v2 = inl(pmtmr_ioport);
-		v3 = inl(pmtmr_ioport);
-	} while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
-			|| (v3 > v1 && v3 < v2));
+	if (pmtmr_need_workaround) {
+		u32 v1, v2, v3;
 
-	/* mask the output to 24 bits */
-	return v2 & ACPI_PM_MASK;
+		/* It has been reported that because of various broken
+		 * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM time
+		 * source is not latched, so you must read it multiple
+		 * times to insure a safe value is read.
+		 */
+		do {
+			v1 = inl(pmtmr_ioport);
+			v2 = inl(pmtmr_ioport);
+			v3 = inl(pmtmr_ioport);
+		} while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
+			 || (v3 > v1 && v3 < v2));
+
+		/* mask the output to 24 bits */
+		return v2 & ACPI_PM_MASK;
+	}
+
+	return inl(pmtmr_ioport) & ACPI_PM_MASK;
 }
 
 
@@ -263,6 +271,72 @@
 	.opts = &timer_pmtmr,
 };
 
+#ifdef CONFIG_PCI
+/*
+ * PIIX4 Errata:
+ *
+ * The power management timer may return improper results when read.
+ * Although the timer value settles properly after incrementing,
+ * while incrementing there is a 3 ns window every 69.8 ns where the
+ * timer value is indeterminate (a 4.2% chance that the data will be
+ * incorrect when read). As a result, the ACPI free running count up
+ * timer specification is violated due to erroneous reads.
+ */
+static int __init pmtmr_bug_check(void)
+{
+	static struct pci_device_id gray_list[] __initdata = {
+		/* these chipsets may have bug. */
+		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
+				PCI_DEVICE_ID_INTEL_82801DB_0) },
+		{ },
+	};
+	struct pci_dev *dev;
+	int pmtmr_has_bug = 0;
+	u8 rev;
+
+	if (cur_timer != &timer_pmtmr || !pmtmr_need_workaround)
+		return 0;
+
+	dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+			     PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
+	if (dev) {
+		pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+		/* the bug has been fixed in PIIX4M */
+		if (rev < 3) {
+			printk(KERN_WARNING "* Found PM-Timer Bug on this "
+				"chipset. Due to workarounds for a bug,\n"
+				"* this time source is slow.  Consider trying "
+				"other time sources (clock=)\n");
+			pmtmr_has_bug = 1;
+		}
+		pci_dev_put(dev);
+	}
+
+	if (pci_dev_present(gray_list)) {
+		printk(KERN_WARNING "* This chipset may have PM-Timer Bug.  Due"
+			" to workarounds for a bug,\n"
+			"* this time source is slow. If you are sure your timer"
+			" does not have\n"
+			"* this bug, please use \"pmtmr_good\" to disable the "
+			"workaround\n");
+		pmtmr_has_bug = 1;
+	}
+
+	if (!pmtmr_has_bug)
+		pmtmr_need_workaround = 0;
+
+	return 0;
+}
+device_initcall(pmtmr_bug_check);
+#endif
+
+static int __init pmtr_good_setup(char *__str)
+{
+	pmtmr_need_workaround = 0;
+	return 1;
+}
+__setup("pmtmr_good", pmtr_good_setup);
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
 MODULE_DESCRIPTION("Power Management Timer (PMTMR) as primary timing source for x86");
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index de5386b..e385279 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -92,22 +92,21 @@
 asmlinkage void machine_check(void);
 
 static int kstack_depth_to_print = 24;
-struct notifier_block *i386die_chain;
-static DEFINE_SPINLOCK(die_notifier_lock);
+ATOMIC_NOTIFIER_HEAD(i386die_chain);
 
 int register_die_notifier(struct notifier_block *nb)
 {
-	int err = 0;
-	unsigned long flags;
-
 	vmalloc_sync_all();
-	spin_lock_irqsave(&die_notifier_lock, flags);
-	err = notifier_chain_register(&i386die_chain, nb);
-	spin_unlock_irqrestore(&die_notifier_lock, flags);
-	return err;
+	return atomic_notifier_chain_register(&i386die_chain, nb);
 }
 EXPORT_SYMBOL(register_die_notifier);
 
+int unregister_die_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&i386die_chain, nb);
+}
+EXPORT_SYMBOL(unregister_die_notifier);
+
 static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
 {
 	return	p > (void *)tinfo &&
@@ -386,8 +385,12 @@
 #endif
 		if (nl)
 			printk("\n");
-	notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
-		show_registers(regs);
+		if (notify_die(DIE_OOPS, str, regs, err,
+					current->thread.trap_no, SIGSEGV) !=
+				NOTIFY_STOP)
+			show_registers(regs);
+		else
+			regs = NULL;
   	} else
 		printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
 
@@ -395,6 +398,9 @@
 	die.lock_owner = -1;
 	spin_unlock_irqrestore(&die.lock, flags);
 
+	if (!regs)
+		return;
+
 	if (kexec_should_crash(current))
 		crash_kexec(regs);
 
@@ -623,7 +629,7 @@
 
 void die_nmi (struct pt_regs *regs, const char *msg)
 {
-	if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 0, SIGINT) ==
+	if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) ==
 	    NOTIFY_STOP)
 		return;
 
@@ -662,7 +668,7 @@
 		reason = get_nmi_reason();
  
 	if (!(reason & 0xc0)) {
-		if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT)
+		if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
 							== NOTIFY_STOP)
 			return;
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -678,7 +684,7 @@
 		unknown_nmi_error(reason, regs);
 		return;
 	}
-	if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP)
+	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
 		return;
 	if (reason & 0x80)
 		mem_parity_error(reason, regs);
@@ -1187,6 +1193,6 @@
 static int __init kstack_setup(char *s)
 {
 	kstack_depth_to_print = simple_strtoul(s, NULL, 0);
-	return 0;
+	return 1;
 }
 __setup("kstack=", kstack_setup);
diff --git a/arch/i386/kernel/vsyscall-sigreturn.S b/arch/i386/kernel/vsyscall-sigreturn.S
index fadb5bc..a92262f 100644
--- a/arch/i386/kernel/vsyscall-sigreturn.S
+++ b/arch/i386/kernel/vsyscall-sigreturn.S
@@ -44,7 +44,7 @@
 .LSTARTCIEDLSI1:
 	.long 0			/* CIE ID */
 	.byte 1			/* Version number */
-	.string "zR"		/* NUL-terminated augmentation string */
+	.string "zRS"		/* NUL-terminated augmentation string */
 	.uleb128 1		/* Code alignment factor */
 	.sleb128 -4		/* Data alignment factor */
 	.byte 8			/* Return address register column */
diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c
index 8165626..70e560a 100644
--- a/arch/i386/mach-voyager/voyager_smp.c
+++ b/arch/i386/mach-voyager/voyager_smp.c
@@ -1700,7 +1700,7 @@
 
 			printk("VOYAGER SMP: CPU%d lost interrupt %d\n",
 			       cpu, irq);
-			for_each_cpu(real_cpu, mask) {
+			for_each_possible_cpu(real_cpu, mask) {
 
 				outb(VIC_CPU_MASQUERADE_ENABLE | real_cpu,
 				     VIC_PROCESSOR_ID);
diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
index c4af963..fe6eb90 100644
--- a/arch/i386/mm/discontig.c
+++ b/arch/i386/mm/discontig.c
@@ -31,6 +31,7 @@
 #include <linux/nodemask.h>
 #include <linux/module.h>
 #include <linux/kexec.h>
+#include <linux/pfn.h>
 
 #include <asm/e820.h>
 #include <asm/setup.h>
@@ -352,17 +353,6 @@
 {
 	int nid;
 
-	/*
-	 * Insert nodes into pgdat_list backward so they appear in order.
-	 * Clobber node 0's links and NULL out pgdat_list before starting.
-	 */
-	pgdat_list = NULL;
-	for (nid = MAX_NUMNODES - 1; nid >= 0; nid--) {
-		if (!node_online(nid))
-			continue;
-		NODE_DATA(nid)->pgdat_next = pgdat_list;
-		pgdat_list = NODE_DATA(nid);
-	}
 
 	for_each_online_node(nid) {
 		unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c
index 9db3242..2889567 100644
--- a/arch/i386/mm/pgtable.c
+++ b/arch/i386/mm/pgtable.c
@@ -36,7 +36,7 @@
 	printk(KERN_INFO "Mem-info:\n");
 	show_free_areas();
 	printk(KERN_INFO "Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
-	for_each_pgdat(pgdat) {
+	for_each_online_pgdat(pgdat) {
 		pgdat_resize_lock(pgdat, &flags);
 		for (i = 0; i < pgdat->node_spanned_pages; ++i) {
 			page = pgdat_page_nr(pgdat, i);
diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
index 1accce5..1a2076c 100644
--- a/arch/i386/oprofile/nmi_int.c
+++ b/arch/i386/oprofile/nmi_int.c
@@ -122,7 +122,7 @@
 static void free_msrs(void)
 {
 	int i;
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		kfree(cpu_msrs[i].counters);
 		cpu_msrs[i].counters = NULL;
 		kfree(cpu_msrs[i].controls);
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 10b6b9e..edffe25 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -34,6 +34,10 @@
 	bool
 	default y
 
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
@@ -42,6 +46,10 @@
 	bool
 	default y
 
+config DMI
+	bool
+	default y
+
 config EFI
 	bool
 	default y
diff --git a/arch/ia64/ia32/ia32priv.h b/arch/ia64/ia32/ia32priv.h
index 68ceb4e..ccb98ed 100644
--- a/arch/ia64/ia32/ia32priv.h
+++ b/arch/ia64/ia32/ia32priv.h
@@ -29,9 +29,9 @@
 struct partial_page {
 	struct partial_page	*next; /* linked list, sorted by address */
 	struct rb_node		pp_rb;
-	/* 64K is the largest "normal" page supported by ia64 ABI. So 4K*32
+	/* 64K is the largest "normal" page supported by ia64 ABI. So 4K*64
 	 * should suffice.*/
-	unsigned int		bitmap;
+	unsigned long		bitmap;
 	unsigned int		base;
 };
 
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index 13e739e..5366b3b 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -25,7 +25,6 @@
 #include <linux/resource.h>
 #include <linux/times.h>
 #include <linux/utsname.h>
-#include <linux/timex.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/sem.h>
@@ -2591,78 +2590,4 @@
 	ssgid = (sgid == (compat_gid_t)-1) ? ((gid_t)-1) : ((gid_t)sgid);
 	return sys_setresgid(srgid, segid, ssgid);
 }
-
-/* Handle adjtimex compatibility. */
-
-struct timex32 {
-	u32 modes;
-	s32 offset, freq, maxerror, esterror;
-	s32 status, constant, precision, tolerance;
-	struct compat_timeval time;
-	s32 tick;
-	s32 ppsfreq, jitter, shift, stabil;
-	s32 jitcnt, calcnt, errcnt, stbcnt;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-};
-
-extern int do_adjtimex(struct timex *);
-
-asmlinkage long
-sys32_adjtimex(struct timex32 *utp)
-{
-	struct timex txc;
-	int ret;
-
-	memset(&txc, 0, sizeof(struct timex));
-
-	if(get_user(txc.modes, &utp->modes) ||
-	   __get_user(txc.offset, &utp->offset) ||
-	   __get_user(txc.freq, &utp->freq) ||
-	   __get_user(txc.maxerror, &utp->maxerror) ||
-	   __get_user(txc.esterror, &utp->esterror) ||
-	   __get_user(txc.status, &utp->status) ||
-	   __get_user(txc.constant, &utp->constant) ||
-	   __get_user(txc.precision, &utp->precision) ||
-	   __get_user(txc.tolerance, &utp->tolerance) ||
-	   __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	   __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	   __get_user(txc.tick, &utp->tick) ||
-	   __get_user(txc.ppsfreq, &utp->ppsfreq) ||
-	   __get_user(txc.jitter, &utp->jitter) ||
-	   __get_user(txc.shift, &utp->shift) ||
-	   __get_user(txc.stabil, &utp->stabil) ||
-	   __get_user(txc.jitcnt, &utp->jitcnt) ||
-	   __get_user(txc.calcnt, &utp->calcnt) ||
-	   __get_user(txc.errcnt, &utp->errcnt) ||
-	   __get_user(txc.stbcnt, &utp->stbcnt))
-		return -EFAULT;
-
-	ret = do_adjtimex(&txc);
-
-	if(put_user(txc.modes, &utp->modes) ||
-	   __put_user(txc.offset, &utp->offset) ||
-	   __put_user(txc.freq, &utp->freq) ||
-	   __put_user(txc.maxerror, &utp->maxerror) ||
-	   __put_user(txc.esterror, &utp->esterror) ||
-	   __put_user(txc.status, &utp->status) ||
-	   __put_user(txc.constant, &utp->constant) ||
-	   __put_user(txc.precision, &utp->precision) ||
-	   __put_user(txc.tolerance, &utp->tolerance) ||
-	   __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	   __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	   __put_user(txc.tick, &utp->tick) ||
-	   __put_user(txc.ppsfreq, &utp->ppsfreq) ||
-	   __put_user(txc.jitter, &utp->jitter) ||
-	   __put_user(txc.shift, &utp->shift) ||
-	   __put_user(txc.stabil, &utp->stabil) ||
-	   __put_user(txc.jitcnt, &utp->jitcnt) ||
-	   __put_user(txc.calcnt, &utp->calcnt) ||
-	   __put_user(txc.errcnt, &utp->errcnt) ||
-	   __put_user(txc.stbcnt, &utp->stbcnt))
-		ret = -EFAULT;
-
-	return ret;
-}
 #endif /* NOTYET */
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 09a0dbc..59e871d 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -7,7 +7,7 @@
 obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o	\
 	 irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o		\
 	 salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
-	 unwind.o mca.o mca_asm.o topology.o
+	 unwind.o mca.o mca_asm.o topology.o dmi_scan.o
 
 obj-$(CONFIG_IA64_BRL_EMU)	+= brl_emu.o
 obj-$(CONFIG_IA64_GENERIC)	+= acpi-ext.o
@@ -30,6 +30,7 @@
 obj-$(CONFIG_KPROBES)		+= kprobes.o jprobes.o
 obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR)	+= uncached.o
 mca_recovery-y			+= mca_drv.o mca_drv_asm.o
+dmi_scan-y			+= ../../i386/kernel/dmi_scan.o
 
 # The gate DSO image is built using a special linker script.
 targets += gate.so gate-syms.o
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index a4e218c..58c93a3 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -651,9 +651,9 @@
 {
 	unsigned long rsdp_phys = 0;
 
-	if (efi.acpi20)
-		rsdp_phys = __pa(efi.acpi20);
-	else if (efi.acpi)
+	if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
+		rsdp_phys = efi.acpi20;
+	else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
 		printk(KERN_WARNING PREFIX
 		       "v1.0/r0.71 tables no longer supported\n");
 	return rsdp_phys;
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index 9990320..12cfedc 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -458,24 +458,33 @@
 	printk(KERN_INFO "EFI v%u.%.02u by %s:",
 	       efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, vendor);
 
+	efi.mps        = EFI_INVALID_TABLE_ADDR;
+	efi.acpi       = EFI_INVALID_TABLE_ADDR;
+	efi.acpi20     = EFI_INVALID_TABLE_ADDR;
+	efi.smbios     = EFI_INVALID_TABLE_ADDR;
+	efi.sal_systab = EFI_INVALID_TABLE_ADDR;
+	efi.boot_info  = EFI_INVALID_TABLE_ADDR;
+	efi.hcdp       = EFI_INVALID_TABLE_ADDR;
+	efi.uga        = EFI_INVALID_TABLE_ADDR;
+
 	for (i = 0; i < (int) efi.systab->nr_tables; i++) {
 		if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) {
-			efi.mps = __va(config_tables[i].table);
+			efi.mps = config_tables[i].table;
 			printk(" MPS=0x%lx", config_tables[i].table);
 		} else if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) == 0) {
-			efi.acpi20 = __va(config_tables[i].table);
+			efi.acpi20 = config_tables[i].table;
 			printk(" ACPI 2.0=0x%lx", config_tables[i].table);
 		} else if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) {
-			efi.acpi = __va(config_tables[i].table);
+			efi.acpi = config_tables[i].table;
 			printk(" ACPI=0x%lx", config_tables[i].table);
 		} else if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) {
-			efi.smbios = __va(config_tables[i].table);
+			efi.smbios = config_tables[i].table;
 			printk(" SMBIOS=0x%lx", config_tables[i].table);
 		} else if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == 0) {
-			efi.sal_systab = __va(config_tables[i].table);
+			efi.sal_systab = config_tables[i].table;
 			printk(" SALsystab=0x%lx", config_tables[i].table);
 		} else if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
-			efi.hcdp = __va(config_tables[i].table);
+			efi.hcdp = config_tables[i].table;
 			printk(" HCDP=0x%lx", config_tables[i].table);
 		}
 	}
@@ -677,27 +686,34 @@
 /*
  * Determines whether the memory at phys_addr supports the desired
  * attribute (WB, UC, etc).  If this returns 1, the caller can safely
- * access *size bytes at phys_addr with the specified attribute.
+ * access size bytes at phys_addr with the specified attribute.
  */
-static int
-efi_mem_attribute_range (unsigned long phys_addr, unsigned long *size, u64 attr)
+int
+efi_mem_attribute_range (unsigned long phys_addr, unsigned long size, u64 attr)
 {
+	unsigned long end = phys_addr + size;
 	efi_memory_desc_t *md = efi_memory_descriptor(phys_addr);
-	unsigned long md_end;
 
-	if (!md || (md->attribute & attr) != attr)
+	/*
+	 * Some firmware doesn't report MMIO regions in the EFI memory
+	 * map.  The Intel BigSur (a.k.a. HP i2000) has this problem.
+	 * On those platforms, we have to assume UC is valid everywhere.
+	 */
+	if (!md || (md->attribute & attr) != attr) {
+		if (attr == EFI_MEMORY_UC && !efi_memmap_has_mmio())
+			return 1;
 		return 0;
+	}
 
 	do {
-		md_end = efi_md_end(md);
-		if (phys_addr + *size <= md_end)
+		unsigned long md_end = efi_md_end(md);
+
+		if (end <= md_end)
 			return 1;
 
 		md = efi_memory_descriptor(md_end);
-		if (!md || (md->attribute & attr) != attr) {
-			*size = md_end - phys_addr;
-			return 1;
-		}
+		if (!md || (md->attribute & attr) != attr)
+			return 0;
 	} while (md);
 	return 0;
 }
@@ -708,7 +724,7 @@
  * control access size.
  */
 int
-valid_phys_addr_range (unsigned long phys_addr, unsigned long *size)
+valid_phys_addr_range (unsigned long phys_addr, unsigned long size)
 {
 	return efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_WB);
 }
@@ -723,7 +739,7 @@
  * because that doesn't appear in the boot-time EFI memory map.
  */
 int
-valid_mmap_phys_addr_range (unsigned long phys_addr, unsigned long *size)
+valid_mmap_phys_addr_range (unsigned long phys_addr, unsigned long size)
 {
 	if (efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_WB))
 		return 1;
@@ -731,14 +747,6 @@
 	if (efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_UC))
 		return 1;
 
-	/*
-	 * Some firmware doesn't report MMIO regions in the EFI memory map.
-	 * The Intel BigSur (a.k.a. HP i2000) has this problem.  In this
-	 * case, we can't use the EFI memory map to validate mmap requests.
-	 */
-	if (!efi_memmap_has_mmio())
-		return 1;
-
 	return 0;
 }
 
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 0e3eda9..750e8e7 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1605,5 +1605,6 @@
 	data8 sys_ni_syscall			// reserved for pselect
 	data8 sys_ni_syscall			// 1295 reserved for ppoll
 	data8 sys_unshare
+	data8 sys_splice
 
 	.org sys_call_table + 8*NR_syscalls	// guard against failures to increase NR_syscalls
diff --git a/arch/ia64/kernel/gate.lds.S b/arch/ia64/kernel/gate.lds.S
index e1e4aba..7c99e6e 100644
--- a/arch/ia64/kernel/gate.lds.S
+++ b/arch/ia64/kernel/gate.lds.S
@@ -59,6 +59,7 @@
 	*(.dynbss)
 	*(.bss .bss.* .gnu.linkonce.b.*)
 	*(__ex_table)
+	*(__mca_table)
   }
 }
 
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index 8832c55..7956eb9 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -9,54 +9,65 @@
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
  *
- * 00/04/19	D. Mosberger	Rewritten to mirror more closely the x86 I/O APIC code.
- *				In particular, we now have separate handlers for edge
- *				and level triggered interrupts.
- * 00/10/27	Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector allocation
- *				PCI to vector mapping, shared PCI interrupts.
- * 00/10/27	D. Mosberger	Document things a bit more to make them more understandable.
- *				Clean up much of the old IOSAPIC cruft.
- * 01/07/27	J.I. Lee	PCI irq routing, Platform/Legacy interrupts and fixes for
- *				ACPI S5(SoftOff) support.
+ * 00/04/19	D. Mosberger	Rewritten to mirror more closely the x86 I/O
+ *				APIC code.  In particular, we now have separate
+ *				handlers for edge and level triggered
+ *				interrupts.
+ * 00/10/27	Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector
+ *				allocation PCI to vector mapping, shared PCI
+ *				interrupts.
+ * 00/10/27	D. Mosberger	Document things a bit more to make them more
+ *				understandable.  Clean up much of the old
+ *				IOSAPIC cruft.
+ * 01/07/27	J.I. Lee	PCI irq routing, Platform/Legacy interrupts
+ *				and fixes for ACPI S5(SoftOff) support.
  * 02/01/23	J.I. Lee	iosapic pgm fixes for PCI irq routing from _PRT
- * 02/01/07     E. Focht        <efocht@ess.nec.de> Redirectable interrupt vectors in
- *                              iosapic_set_affinity(), initializations for
- *                              /proc/irq/#/smp_affinity
+ * 02/01/07     E. Focht        <efocht@ess.nec.de> Redirectable interrupt
+ *				vectors in iosapic_set_affinity(),
+ *				initializations for /proc/irq/#/smp_affinity
  * 02/04/02	P. Diefenbaugh	Cleaned up ACPI PCI IRQ routing.
  * 02/04/18	J.I. Lee	bug fix in iosapic_init_pci_irq
- * 02/04/30	J.I. Lee	bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping
- *				error
+ * 02/04/30	J.I. Lee	bug fix in find_iosapic to fix ACPI PCI IRQ to
+ *				IOSAPIC mapping error
  * 02/07/29	T. Kochi	Allocate interrupt vectors dynamically
- * 02/08/04	T. Kochi	Cleaned up terminology (irq, global system interrupt, vector, etc.)
- * 02/09/20	D. Mosberger	Simplified by taking advantage of ACPI's pci_irq code.
+ * 02/08/04	T. Kochi	Cleaned up terminology (irq, global system
+ *				interrupt, vector, etc.)
+ * 02/09/20	D. Mosberger	Simplified by taking advantage of ACPI's
+ *				pci_irq code.
  * 03/02/19	B. Helgaas	Make pcat_compat system-wide, not per-IOSAPIC.
- *				Remove iosapic_address & gsi_base from external interfaces.
- *				Rationalize __init/__devinit attributes.
+ *				Remove iosapic_address & gsi_base from
+ *				external interfaces.  Rationalize
+ *				__init/__devinit attributes.
  * 04/12/04 Ashok Raj	<ashok.raj@intel.com> Intel Corporation 2004
- *				Updated to work with irq migration necessary for CPU Hotplug
+ *				Updated to work with irq migration necessary
+ *				for CPU Hotplug
  */
 /*
- * Here is what the interrupt logic between a PCI device and the kernel looks like:
+ * Here is what the interrupt logic between a PCI device and the kernel looks
+ * like:
  *
- * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD).  The
- *     device is uniquely identified by its bus--, and slot-number (the function
- *     number does not matter here because all functions share the same interrupt
- *     lines).
+ * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC,
+ *     INTD).  The device is uniquely identified by its bus-, and slot-number
+ *     (the function number does not matter here because all functions share
+ *     the same interrupt lines).
  *
- * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller.
- *     Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level
- *     triggered and use the same polarity).  Each interrupt line has a unique Global
- *     System Interrupt (GSI) number which can be calculated as the sum of the controller's
- *     base GSI number and the IOSAPIC pin number to which the line connects.
+ * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC
+ *     controller.  Multiple interrupt lines may have to share the same
+ *     IOSAPIC pin (if they're level triggered and use the same polarity).
+ *     Each interrupt line has a unique Global System Interrupt (GSI) number
+ *     which can be calculated as the sum of the controller's base GSI number
+ *     and the IOSAPIC pin number to which the line connects.
  *
- * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the IOSAPIC pin
- *     into the IA-64 interrupt vector.  This interrupt vector is then sent to the CPU.
+ * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the
+ * IOSAPIC pin into the IA-64 interrupt vector.  This interrupt vector is then
+ * sent to the CPU.
  *
- * (4) The kernel recognizes an interrupt as an IRQ.  The IRQ interface is used as
- *     architecture-independent interrupt handling mechanism in Linux.  As an
- *     IRQ is a number, we have to have IA-64 interrupt vector number <-> IRQ number
- *     mapping.  On smaller systems, we use one-to-one mapping between IA-64 vector and
- *     IRQ.  A platform can implement platform_irq_to_vector(irq) and
+ * (4) The kernel recognizes an interrupt as an IRQ.  The IRQ interface is
+ *     used as architecture-independent interrupt handling mechanism in Linux.
+ *     As an IRQ is a number, we have to have
+ *     IA-64 interrupt vector number <-> IRQ number mapping.  On smaller
+ *     systems, we use one-to-one mapping between IA-64 vector and IRQ.  A
+ *     platform can implement platform_irq_to_vector(irq) and
  *     platform_local_vector_to_irq(vector) APIs to differentiate the mapping.
  *     Please see also include/asm-ia64/hw_irq.h for those APIs.
  *
@@ -64,9 +75,9 @@
  *
  *	PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ
  *
- * Note: The term "IRQ" is loosely used everywhere in Linux kernel to describe interrupts.
- * Now we use "IRQ" only for Linux IRQ's.  ISA IRQ (isa_irq) is the only exception in this
- * source code.
+ * Note: The term "IRQ" is loosely used everywhere in Linux kernel to
+ * describeinterrupts.  Now we use "IRQ" only for Linux IRQ's.  ISA IRQ
+ * (isa_irq) is the only exception in this source code.
  */
 #include <linux/config.h>
 
@@ -90,7 +101,6 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 
-
 #undef DEBUG_INTERRUPT_ROUTING
 
 #ifdef DEBUG_INTERRUPT_ROUTING
@@ -99,36 +109,46 @@
 #define DBG(fmt...)
 #endif
 
-#define NR_PREALLOCATE_RTE_ENTRIES	(PAGE_SIZE / sizeof(struct iosapic_rte_info))
+#define NR_PREALLOCATE_RTE_ENTRIES \
+	(PAGE_SIZE / sizeof(struct iosapic_rte_info))
 #define RTE_PREALLOCATED	(1)
 
 static DEFINE_SPINLOCK(iosapic_lock);
 
-/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */
+/*
+ * These tables map IA-64 vectors to the IOSAPIC pin that generates this
+ * vector.
+ */
 
 struct iosapic_rte_info {
-	struct list_head rte_list;	/* node in list of RTEs sharing the same vector */
+	struct list_head rte_list;	/* node in list of RTEs sharing the
+					 * same vector */
 	char __iomem	*addr;		/* base address of IOSAPIC */
-	unsigned int	gsi_base;	/* first GSI assigned to this IOSAPIC */
+	unsigned int	gsi_base;	/* first GSI assigned to this
+					 * IOSAPIC */
 	char		rte_index;	/* IOSAPIC RTE index */
 	int		refcnt;		/* reference counter */
 	unsigned int	flags;		/* flags */
 } ____cacheline_aligned;
 
 static struct iosapic_intr_info {
-	struct list_head rtes;		/* RTEs using this vector (empty => not an IOSAPIC interrupt) */
+	struct list_head rtes;		/* RTEs using this vector (empty =>
+					 * not an IOSAPIC interrupt) */
 	int		count;		/* # of RTEs that shares this vector */
-	u32		low32;		/* current value of low word of Redirection table entry */
+	u32		low32;		/* current value of low word of
+					 * Redirection table entry */
 	unsigned int	dest;		/* destination CPU physical ID */
 	unsigned char	dmode	: 3;	/* delivery mode (see iosapic.h) */
-	unsigned char 	polarity: 1;	/* interrupt polarity (see iosapic.h) */
+	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;	/* number of RTE in this 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 */
@@ -149,7 +169,8 @@
 	int i;
 
 	for (i = 0; i < NR_IOSAPICS; i++) {
-		if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
+		if ((unsigned) (gsi - iosapic_lists[i].gsi_base) <
+		    iosapic_lists[i].num_rte)
 			return i;
 	}
 
@@ -162,7 +183,8 @@
 	struct iosapic_intr_info *info;
 	struct iosapic_rte_info *rte;
 
-	for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info)
+	for (info = iosapic_intr_info; info <
+		     iosapic_intr_info + IA64_NUM_VECTORS; ++info)
 		list_for_each_entry(rte, &info->rtes, rte_list)
 			if (rte->gsi_base + rte->rte_index == gsi)
 				return info - iosapic_intr_info;
@@ -185,8 +207,8 @@
 	unsigned long flags;
 	int irq;
 	/*
-	 * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq
-	 * numbers...
+	 * XXX fix me: this assumes an identity mapping between IA-64 vector
+	 * and Linux irq numbers...
 	 */
 	spin_lock_irqsave(&iosapic_lock, flags);
 	{
@@ -197,7 +219,8 @@
 	return irq;
 }
 
-static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec)
+static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi,
+						  unsigned int vec)
 {
 	struct iosapic_rte_info *rte;
 
@@ -237,7 +260,9 @@
 
 		for (irq = 0; irq < NR_IRQS; ++irq)
 			if (irq_to_vector(irq) == vector) {
-				set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
+				set_irq_affinity_info(irq,
+						      (int)(dest & 0xffff),
+						      redir);
 				break;
 			}
 	}
@@ -259,7 +284,7 @@
 }
 
 static void
-nop (unsigned int vector)
+nop (unsigned int irq)
 {
 	/* do nothing... */
 }
@@ -281,7 +306,8 @@
 	{
 		/* 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) {
+		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);
@@ -306,7 +332,8 @@
 	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) {
+		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);
@@ -346,21 +373,25 @@
 
 	spin_lock_irqsave(&iosapic_lock, flags);
 	{
-		low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
+		low32 = iosapic_intr_info[vec].low32 &
+			~(7 << IOSAPIC_DELIVERY_SHIFT);
 
 		if (redir)
 		        /* change delivery mode to lowest priority */
-			low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
+			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) {
+		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_HIGH(rte_index),
+				      high32);
 			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
 		}
 	}
@@ -433,7 +464,8 @@
 	 * interrupt for real. This prevents IRQ storms from unhandled
 	 * devices.
 	 */
-	if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED))
+	if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) ==
+	    (IRQ_PENDING|IRQ_DISABLED))
 		mask_irq(irq);
 }
 
@@ -467,7 +499,8 @@
 	return iosapic_read(addr, IOSAPIC_VERSION);
 }
 
-static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol)
+static int iosapic_find_sharable_vector (unsigned long trigger,
+					 unsigned long pol)
 {
 	int i, vector = -1, min_count = -1;
 	struct iosapic_intr_info *info;
@@ -482,7 +515,8 @@
 	for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; 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)) {
 			if (min_count == -1 || info->count < min_count) {
 				vector = i;
 				min_count = info->count;
@@ -506,12 +540,15 @@
 		new_vector = assign_irq_vector(AUTO_ASSIGN);
 		if (new_vector < 0)
 			panic("%s: out of interrupt vectors!\n", __FUNCTION__);
-		printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);
+		printk(KERN_INFO "Reassigning vector %d to %d\n",
+		       vector, new_vector);
 		memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
 		       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, sizeof(struct iosapic_intr_info));
+		list_move(iosapic_intr_info[vector].rtes.next,
+			  &iosapic_intr_info[new_vector].rtes);
+		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);
 	}
@@ -524,7 +561,8 @@
 	int preallocated = 0;
 
 	if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
-		rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES);
+		rte = alloc_bootmem(sizeof(struct iosapic_rte_info) *
+				    NR_PREALLOCATE_RTE_ENTRIES);
 		if (!rte)
 			return NULL;
 		for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
@@ -532,7 +570,8 @@
 	}
 
 	if (!list_empty(&free_rte_list)) {
-		rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list);
+		rte = list_entry(free_rte_list.next, struct iosapic_rte_info,
+				 rte_list);
 		list_del(&rte->rte_list);
 		preallocated++;
 	} else {
@@ -575,7 +614,8 @@
 
 	index = find_iosapic(gsi);
 	if (index < 0) {
-		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi);
+		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n",
+		       __FUNCTION__, gsi);
 		return -ENODEV;
 	}
 
@@ -586,7 +626,8 @@
 	if (!rte) {
 		rte = iosapic_alloc_rte();
 		if (!rte) {
-			printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__);
+			printk(KERN_WARNING "%s: cannot allocate memory\n",
+			       __FUNCTION__);
 			return -ENOMEM;
 		}
 
@@ -602,7 +643,9 @@
 	else if (vector_is_shared(vector)) {
 		struct iosapic_intr_info *info = &iosapic_intr_info[vector];
 		if (info->trigger != trigger || info->polarity != polarity) {
-			printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__);
+			printk (KERN_WARNING
+				"%s: cannot override the interrupt\n",
+				__FUNCTION__);
 			return -EINVAL;
 		}
 	}
@@ -619,8 +662,10 @@
 	idesc = irq_descp(vector);
 	if (idesc->handler != irq_type) {
 		if (idesc->handler != &no_irq_type)
-			printk(KERN_WARNING "%s: changing vector %d from %s to %s\n",
-			       __FUNCTION__, vector, idesc->handler->typename, irq_type->typename);
+			printk(KERN_WARNING
+			       "%s: changing vector %d from %s to %s\n",
+			       __FUNCTION__, vector,
+			       idesc->handler->typename, irq_type->typename);
 		idesc->handler = irq_type;
 	}
 	return 0;
@@ -681,7 +726,7 @@
 		if (!num_cpus)
 			goto skip_numa_setup;
 
-		/* Use vector assigment to distribute across cpus in node */
+		/* Use vector assignment to distribute across cpus in node */
 		cpu_index = vector % num_cpus;
 
 		for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++)
@@ -703,7 +748,7 @@
 	} while (!cpu_online(cpu));
 
 	return cpu_physical_id(cpu);
-#else
+#else  /* CONFIG_SMP */
 	return cpu_physical_id(smp_processor_id());
 #endif
 }
@@ -755,7 +800,8 @@
 			if (list_empty(&iosapic_intr_info[vector].rtes))
 				free_irq_vector(vector);
 			spin_unlock(&iosapic_lock);
-			spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
+			spin_unlock_irqrestore(&irq_descp(vector)->lock,
+					       flags);
 			goto again;
 		}
 
@@ -764,7 +810,8 @@
 			      polarity, trigger);
 		if (err < 0) {
 			spin_unlock(&iosapic_lock);
-			spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
+			spin_unlock_irqrestore(&irq_descp(vector)->lock,
+					       flags);
 			return err;
 		}
 
@@ -806,7 +853,8 @@
 	 */
 	irq = gsi_to_irq(gsi);
 	if (irq < 0) {
-		printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
+		printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n",
+		       gsi);
 		WARN_ON(1);
 		return;
 	}
@@ -817,7 +865,9 @@
 	spin_lock(&iosapic_lock);
 	{
 		if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
-			printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
+			printk(KERN_ERR
+			       "iosapic_unregister_intr(%u) unbalanced\n",
+			       gsi);
 			WARN_ON(1);
 			goto out;
 		}
@@ -827,7 +877,8 @@
 
 		/* Mask the interrupt */
 		low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
-		iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32);
+		iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index),
+			      low32);
 
 		/* Remove the rte entry from the list */
 		list_del(&rte->rte_list);
@@ -840,7 +891,9 @@
 		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",
+		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);
@@ -853,12 +906,15 @@
 			idesc->handler = &no_irq_type;
 
 			/* Clear the interrupt information */
-			memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
+			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);
+				printk(KERN_ERR
+				       "interrupt handlers still exist on"
+				       "IRQ %u\n", irq);
 				WARN_ON(1);
 			}
 
@@ -873,7 +929,6 @@
 
 /*
  * ACPI calls this when it finds an entry for a platform interrupt.
- * Note that the irq_base and IOSAPIC address must be set in iosapic_init().
  */
 int __init
 iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
@@ -907,13 +962,16 @@
 		mask = 1;
 		break;
 	      default:
-		printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type);
+		printk(KERN_ERR "%s: invalid int type 0x%x\n", __FUNCTION__,
+		       int_type);
 		return -1;
 	}
 
 	register_intr(gsi, vector, delivery, polarity, trigger);
 
-	printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
+	printk(KERN_INFO
+	       "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x)"
+	       " vector %d\n",
 	       int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown",
 	       int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
 	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
@@ -923,10 +981,8 @@
 	return vector;
 }
 
-
 /*
  * ACPI calls this when it finds an entry for a legacy ISA IRQ override.
- * Note that the gsi_base and IOSAPIC address must be set in iosapic_init().
  */
 void __init
 iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
@@ -955,16 +1011,19 @@
 
 	for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
 		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
-		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);	/* mark as unused */
+		/* mark as unused */
+		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
 	}
 
 	pcat_compat = system_pcat_compat;
 	if (pcat_compat) {
 		/*
-		 * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
-		 * enabled.
+		 * Disable the compatibility mode interrupts (8259 style),
+		 * needs IN/OUT support enabled.
 		 */
-		printk(KERN_INFO "%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__);
+		printk(KERN_INFO
+		       "%s: Disabling PC-AT compatible 8259 interrupts\n",
+		       __FUNCTION__);
 		outb(0xff, 0xA1);
 		outb(0xff, 0x21);
 	}
@@ -1004,10 +1063,7 @@
 		base = iosapic_lists[index].gsi_base;
 		end  = base + iosapic_lists[index].num_rte - 1;
 
-		if (gsi_base < base && gsi_end < base)
-			continue;/* OK */
-
-		if (gsi_base > end && gsi_end > end)
+		if (gsi_end < base || end < gsi_base)
 			continue; /* OK */
 
 		return -EBUSY;
@@ -1053,12 +1109,14 @@
 
 	if ((gsi_base == 0) && pcat_compat) {
 		/*
-		 * Map the legacy ISA devices into the IOSAPIC data.  Some of these may
-		 * get reprogrammed later on with data from the ACPI Interrupt Source
-		 * Override table.
+		 * Map the legacy ISA devices into the IOSAPIC data.  Some of
+		 * these may get reprogrammed later on with data from the ACPI
+		 * Interrupt Source Override table.
 		 */
 		for (isa_irq = 0; isa_irq < 16; ++isa_irq)
-			iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
+			iosapic_override_isa_irq(isa_irq, isa_irq,
+						 IOSAPIC_POL_HIGH,
+						 IOSAPIC_EDGE);
 	}
 	return 0;
 }
@@ -1081,7 +1139,8 @@
 
 		if (iosapic_lists[index].rtes_inuse) {
 			err = -EBUSY;
-			printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
+			printk(KERN_WARNING
+			       "%s: IOSAPIC for GSI base %u is busy\n",
 			       __FUNCTION__, gsi_base);
 			goto out;
 		}
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 50ae8c7..789881c 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -34,6 +34,7 @@
 #include <asm/pgtable.h>
 #include <asm/kdebug.h>
 #include <asm/sections.h>
+#include <asm/uaccess.h>
 
 extern void jprobe_inst_return(void);
 
@@ -722,13 +723,50 @@
 	struct kprobe *cur = kprobe_running();
 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
 
-	if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-		return 1;
 
-	if (kcb->kprobe_status & KPROBE_HIT_SS) {
-		resume_execution(cur, regs);
-		reset_current_kprobe();
+	switch(kcb->kprobe_status) {
+	case KPROBE_HIT_SS:
+	case KPROBE_REENTER:
+		/*
+		 * We are here because the instruction being single
+		 * stepped caused a page fault. We reset the current
+		 * kprobe and the instruction pointer points back to
+		 * the probe address and allow the page fault handler
+		 * to continue as a normal page fault.
+		 */
+		regs->cr_iip = ((unsigned long)cur->addr) & ~0xFULL;
+		ia64_psr(regs)->ri = ((unsigned long)cur->addr) & 0xf;
+		if (kcb->kprobe_status == KPROBE_REENTER)
+			restore_previous_kprobe(kcb);
+		else
+			reset_current_kprobe();
 		preempt_enable_no_resched();
+		break;
+	case KPROBE_HIT_ACTIVE:
+	case KPROBE_HIT_SSDONE:
+		/*
+		 * We increment the nmissed count for accounting,
+		 * we can also use npre/npostfault count for accouting
+		 * these specific fault cases.
+		 */
+		kprobes_inc_nmissed_count(cur);
+
+		/*
+		 * We come here because instructions in the pre/post
+		 * handler caused the page_fault, this could happen
+		 * if handler tries to access user space by
+		 * copy_from_user(), get_user() etc. Let the
+		 * user-specified handler try to fix it first.
+		 */
+		if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
+			return 1;
+
+		/*
+		 * Let ia64_do_page_fault() fix it.
+		 */
+		break;
+	default:
+		break;
 	}
 
 	return 0;
@@ -740,6 +778,9 @@
 	struct die_args *args = (struct die_args *)data;
 	int ret = NOTIFY_DONE;
 
+	if (args->regs && user_mode(args->regs))
+		return ret;
+
 	switch(val) {
 	case DIE_BREAK:
 		/* err is break number from ia64_bad_break() */
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 87ff7fe..8963171 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -69,6 +69,7 @@
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/workqueue.h>
+#include <linux/cpumask.h>
 
 #include <asm/delay.h>
 #include <asm/kdebug.h>
@@ -1505,7 +1506,7 @@
 	ti->cpu = cpu;
 	p->thread_info = ti;
 	p->state = TASK_UNINTERRUPTIBLE;
-	__set_bit(cpu, &p->cpus_allowed);
+	cpu_set(cpu, p->cpus_allowed);
 	INIT_LIST_HEAD(&p->tasks);
 	p->parent = p->real_parent = p->group_leader = p;
 	INIT_LIST_HEAD(&p->children);
diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c
index 89faa60..6386f63 100644
--- a/arch/ia64/kernel/palinfo.c
+++ b/arch/ia64/kernel/palinfo.c
@@ -240,7 +240,7 @@
 			}
 			p += sprintf(p,
 				     "%s Cache level %lu:\n"
-				     "\tSize           : %lu bytes\n"
+				     "\tSize           : %u bytes\n"
 				     "\tAttributes     : ",
 				     cache_types[j+cci.pcci_unified], i+1,
 				     cci.pcci_cache_size);
@@ -648,9 +648,9 @@
 	if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0;
 
 	p += sprintf(p,
-		     "Processor/Clock ratio   : %ld/%ld\n"
-		     "Bus/Clock ratio         : %ld/%ld\n"
-		     "ITC/Clock ratio         : %ld/%ld\n",
+		     "Processor/Clock ratio   : %d/%d\n"
+		     "Bus/Clock ratio         : %d/%d\n"
+		     "ITC/Clock ratio         : %d/%d\n",
 		     proc.num, proc.den, bus.num, bus.den, itc.num, itc.den);
 
 	return p - page;
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 309d596..355d579 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -30,7 +30,6 @@
 #include <linux/efi.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/kprobes.h>
 
 #include <asm/cpu.h>
 #include <asm/delay.h>
@@ -738,13 +737,6 @@
 exit_thread (void)
 {
 
-	/*
-	 * Remove function-return probe instances associated with this task
-	 * and put them back on the free list. Do not insert an exit probe for
-	 * this function, it will be disabled by kprobe_flush_task if you do.
-	 */
-	kprobe_flush_task(current);
-
 	ia64_drop_fpu(current);
 #ifdef CONFIG_PERFMON
        /* if needed, stop monitoring and flush state to perfmon context */
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index eb388e2..e4dfda1 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -37,6 +37,7 @@
 #include <linux/string.h>
 #include <linux/threads.h>
 #include <linux/tty.h>
+#include <linux/dmi.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <linux/efi.h>
@@ -433,7 +434,7 @@
 	find_memory();
 
 	/* process SAL system table: */
-	ia64_sal_init(efi.sal_systab);
+	ia64_sal_init(__va(efi.sal_systab));
 
 	ia64_setup_printk_clock();
 
@@ -887,3 +888,10 @@
 	ia64_patch_mckinley_e9((unsigned long) __start___mckinley_e9_bundles,
 			       (unsigned long) __end___mckinley_e9_bundles);
 }
+
+static int __init run_dmi_scan(void)
+{
+	dmi_scan_machine();
+	return 0;
+}
+core_initcall(run_dmi_scan);
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index ac16743..4995890 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -188,7 +188,7 @@
 	itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den;
 
 	local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ;
-	printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, "
+	printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%u/%u, "
 	       "ITC freq=%lu.%03luMHz", smp_processor_id(),
 	       platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000,
 	       itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000);
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index 3b6fd79..b47476d 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -9,6 +9,8 @@
  * 		2002/08/07 Erich Focht <efocht@ess.nec.de>
  * Populate cpu entries in sysfs for non-numa systems as well
  *  	Intel Corporation - Ashok Raj
+ * 02/27/2006 Zhang, Yanmin
+ *	Populate cpu cache entries in sysfs for cpu cache info
  */
 
 #include <linux/config.h>
@@ -19,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/nodemask.h>
+#include <linux/notifier.h>
 #include <asm/mmzone.h>
 #include <asm/numa.h>
 #include <asm/cpu.h>
@@ -101,3 +104,367 @@
 }
 
 subsys_initcall(topology_init);
+
+
+/*
+ * Export cpu cache information through sysfs
+ */
+
+/*
+ *  A bunch of string array to get pretty printing
+ */
+static const char *cache_types[] = {
+	"",			/* not used */
+	"Instruction",
+	"Data",
+	"Unified"	/* unified */
+};
+
+static const char *cache_mattrib[]={
+	"WriteThrough",
+	"WriteBack",
+	"",		/* reserved */
+	""		/* reserved */
+};
+
+struct cache_info {
+	pal_cache_config_info_t	cci;
+	cpumask_t shared_cpu_map;
+	int level;
+	int type;
+	struct kobject kobj;
+};
+
+struct cpu_cache_info {
+	struct cache_info *cache_leaves;
+	int	num_cache_leaves;
+	struct kobject kobj;
+};
+
+static struct cpu_cache_info	all_cpu_cache_info[NR_CPUS];
+#define LEAF_KOBJECT_PTR(x,y)    (&all_cpu_cache_info[x].cache_leaves[y])
+
+#ifdef CONFIG_SMP
+static void cache_shared_cpu_map_setup( unsigned int cpu,
+		struct cache_info * this_leaf)
+{
+	pal_cache_shared_info_t	csi;
+	int num_shared, i = 0;
+	unsigned int j;
+
+	if (cpu_data(cpu)->threads_per_core <= 1 &&
+		cpu_data(cpu)->cores_per_socket <= 1) {
+		cpu_set(cpu, this_leaf->shared_cpu_map);
+		return;
+	}
+
+	if (ia64_pal_cache_shared_info(this_leaf->level,
+					this_leaf->type,
+					0,
+					&csi) != PAL_STATUS_SUCCESS)
+		return;
+
+	num_shared = (int) csi.num_shared;
+	do {
+		for_each_cpu(j)
+			if (cpu_data(cpu)->socket_id == cpu_data(j)->socket_id
+				&& cpu_data(j)->core_id == csi.log1_cid
+				&& cpu_data(j)->thread_id == csi.log1_tid)
+				cpu_set(j, this_leaf->shared_cpu_map);
+
+		i++;
+	} while (i < num_shared &&
+		ia64_pal_cache_shared_info(this_leaf->level,
+				this_leaf->type,
+				i,
+				&csi) == PAL_STATUS_SUCCESS);
+}
+#else
+static void cache_shared_cpu_map_setup(unsigned int cpu,
+		struct cache_info * this_leaf)
+{
+	cpu_set(cpu, this_leaf->shared_cpu_map);
+	return;
+}
+#endif
+
+static ssize_t show_coherency_line_size(struct cache_info *this_leaf,
+					char *buf)
+{
+	return sprintf(buf, "%u\n", 1 << this_leaf->cci.pcci_line_size);
+}
+
+static ssize_t show_ways_of_associativity(struct cache_info *this_leaf,
+					char *buf)
+{
+	return sprintf(buf, "%u\n", this_leaf->cci.pcci_assoc);
+}
+
+static ssize_t show_attributes(struct cache_info *this_leaf, char *buf)
+{
+	return sprintf(buf,
+			"%s\n",
+			cache_mattrib[this_leaf->cci.pcci_cache_attr]);
+}
+
+static ssize_t show_size(struct cache_info *this_leaf, char *buf)
+{
+	return sprintf(buf, "%uK\n", this_leaf->cci.pcci_cache_size / 1024);
+}
+
+static ssize_t show_number_of_sets(struct cache_info *this_leaf, char *buf)
+{
+	unsigned number_of_sets = this_leaf->cci.pcci_cache_size;
+	number_of_sets /= this_leaf->cci.pcci_assoc;
+	number_of_sets /= 1 << this_leaf->cci.pcci_line_size;
+
+	return sprintf(buf, "%u\n", number_of_sets);
+}
+
+static ssize_t show_shared_cpu_map(struct cache_info *this_leaf, char *buf)
+{
+	ssize_t	len;
+	cpumask_t shared_cpu_map;
+
+	cpus_and(shared_cpu_map, this_leaf->shared_cpu_map, cpu_online_map);
+	len = cpumask_scnprintf(buf, NR_CPUS+1, shared_cpu_map);
+	len += sprintf(buf+len, "\n");
+	return len;
+}
+
+static ssize_t show_type(struct cache_info *this_leaf, char *buf)
+{
+	int type = this_leaf->type + this_leaf->cci.pcci_unified;
+	return sprintf(buf, "%s\n", cache_types[type]);
+}
+
+static ssize_t show_level(struct cache_info *this_leaf, char *buf)
+{
+	return sprintf(buf, "%u\n", this_leaf->level);
+}
+
+struct cache_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct cache_info *, char *);
+	ssize_t (*store)(struct cache_info *, const char *, size_t count);
+};
+
+#ifdef define_one_ro
+	#undef define_one_ro
+#endif
+#define define_one_ro(_name) \
+	static struct cache_attr _name = \
+__ATTR(_name, 0444, show_##_name, NULL)
+
+define_one_ro(level);
+define_one_ro(type);
+define_one_ro(coherency_line_size);
+define_one_ro(ways_of_associativity);
+define_one_ro(size);
+define_one_ro(number_of_sets);
+define_one_ro(shared_cpu_map);
+define_one_ro(attributes);
+
+static struct attribute * cache_default_attrs[] = {
+	&type.attr,
+	&level.attr,
+	&coherency_line_size.attr,
+	&ways_of_associativity.attr,
+	&attributes.attr,
+	&size.attr,
+	&number_of_sets.attr,
+	&shared_cpu_map.attr,
+	NULL
+};
+
+#define to_object(k) container_of(k, struct cache_info, kobj)
+#define to_attr(a) container_of(a, struct cache_attr, attr)
+
+static ssize_t cache_show(struct kobject * kobj, struct attribute * attr, char * buf)
+{
+	struct cache_attr *fattr = to_attr(attr);
+	struct cache_info *this_leaf = to_object(kobj);
+	ssize_t ret;
+
+	ret = fattr->show ? fattr->show(this_leaf, buf) : 0;
+	return ret;
+}
+
+static struct sysfs_ops cache_sysfs_ops = {
+	.show   = cache_show
+};
+
+static struct kobj_type cache_ktype = {
+	.sysfs_ops	= &cache_sysfs_ops,
+	.default_attrs	= cache_default_attrs,
+};
+
+static struct kobj_type cache_ktype_percpu_entry = {
+	.sysfs_ops	= &cache_sysfs_ops,
+};
+
+static void __cpuinit cpu_cache_sysfs_exit(unsigned int cpu)
+{
+	if (all_cpu_cache_info[cpu].cache_leaves) {
+		kfree(all_cpu_cache_info[cpu].cache_leaves);
+		all_cpu_cache_info[cpu].cache_leaves = NULL;
+	}
+	all_cpu_cache_info[cpu].num_cache_leaves = 0;
+	memset(&all_cpu_cache_info[cpu].kobj, 0, sizeof(struct kobject));
+
+	return;
+}
+
+static int __cpuinit cpu_cache_sysfs_init(unsigned int cpu)
+{
+	u64 i, levels, unique_caches;
+	pal_cache_config_info_t cci;
+	int j;
+	s64 status;
+	struct cache_info *this_cache;
+	int num_cache_leaves = 0;
+
+	if ((status = ia64_pal_cache_summary(&levels, &unique_caches)) != 0) {
+		printk(KERN_ERR "ia64_pal_cache_summary=%ld\n", status);
+		return -1;
+	}
+
+	this_cache=kzalloc(sizeof(struct cache_info)*unique_caches,
+			GFP_KERNEL);
+	if (this_cache == NULL)
+		return -ENOMEM;
+
+	for (i=0; i < levels; i++) {
+		for (j=2; j >0 ; j--) {
+			if ((status=ia64_pal_cache_config_info(i,j, &cci)) !=
+					PAL_STATUS_SUCCESS)
+				continue;
+
+			this_cache[num_cache_leaves].cci = cci;
+			this_cache[num_cache_leaves].level = i + 1;
+			this_cache[num_cache_leaves].type = j;
+
+			cache_shared_cpu_map_setup(cpu,
+					&this_cache[num_cache_leaves]);
+			num_cache_leaves ++;
+		}
+	}
+
+	all_cpu_cache_info[cpu].cache_leaves = this_cache;
+	all_cpu_cache_info[cpu].num_cache_leaves = num_cache_leaves;
+
+	memset(&all_cpu_cache_info[cpu].kobj, 0, sizeof(struct kobject));
+
+	return 0;
+}
+
+/* Add cache interface for CPU device */
+static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
+{
+	unsigned int cpu = sys_dev->id;
+	unsigned long i, j;
+	struct cache_info *this_object;
+	int retval = 0;
+	cpumask_t oldmask;
+
+	if (all_cpu_cache_info[cpu].kobj.parent)
+		return 0;
+
+	oldmask = current->cpus_allowed;
+	retval = set_cpus_allowed(current, cpumask_of_cpu(cpu));
+	if (unlikely(retval))
+		return retval;
+
+	retval = cpu_cache_sysfs_init(cpu);
+	set_cpus_allowed(current, oldmask);
+	if (unlikely(retval < 0))
+		return retval;
+
+	all_cpu_cache_info[cpu].kobj.parent = &sys_dev->kobj;
+	kobject_set_name(&all_cpu_cache_info[cpu].kobj, "%s", "cache");
+	all_cpu_cache_info[cpu].kobj.ktype = &cache_ktype_percpu_entry;
+	retval = kobject_register(&all_cpu_cache_info[cpu].kobj);
+
+	for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) {
+		this_object = LEAF_KOBJECT_PTR(cpu,i);
+		this_object->kobj.parent = &all_cpu_cache_info[cpu].kobj;
+		kobject_set_name(&(this_object->kobj), "index%1lu", i);
+		this_object->kobj.ktype = &cache_ktype;
+		retval = kobject_register(&(this_object->kobj));
+		if (unlikely(retval)) {
+			for (j = 0; j < i; j++) {
+				kobject_unregister(
+					&(LEAF_KOBJECT_PTR(cpu,j)->kobj));
+			}
+			kobject_unregister(&all_cpu_cache_info[cpu].kobj);
+			cpu_cache_sysfs_exit(cpu);
+			break;
+		}
+	}
+	return retval;
+}
+
+/* Remove cache interface for CPU device */
+static int __cpuinit cache_remove_dev(struct sys_device * sys_dev)
+{
+	unsigned int cpu = sys_dev->id;
+	unsigned long i;
+
+	for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++)
+		kobject_unregister(&(LEAF_KOBJECT_PTR(cpu,i)->kobj));
+
+	if (all_cpu_cache_info[cpu].kobj.parent) {
+		kobject_unregister(&all_cpu_cache_info[cpu].kobj);
+		memset(&all_cpu_cache_info[cpu].kobj,
+			0,
+			sizeof(struct kobject));
+	}
+
+	cpu_cache_sysfs_exit(cpu);
+
+	return 0;
+}
+
+/*
+ * When a cpu is hot-plugged, do a check and initiate
+ * cache kobject if necessary
+ */
+static int __cpuinit cache_cpu_callback(struct notifier_block *nfb,
+		unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+	struct sys_device *sys_dev;
+
+	sys_dev = get_cpu_sysdev(cpu);
+	switch (action) {
+	case CPU_ONLINE:
+		cache_add_dev(sys_dev);
+		break;
+	case CPU_DEAD:
+		cache_remove_dev(sys_dev);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block cache_cpu_notifier =
+{
+	.notifier_call = cache_cpu_callback
+};
+
+static int __cpuinit cache_sysfs_init(void)
+{
+	int i;
+
+	for_each_online_cpu(i) {
+		cache_cpu_callback(&cache_cpu_notifier, CPU_ONLINE,
+				(void *)(long)i);
+	}
+
+	register_cpu_notifier(&cache_cpu_notifier);
+
+	return 0;
+}
+
+device_initcall(cache_sysfs_init);
+
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index dabd6c3..7c1ddc8 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -30,19 +30,19 @@
 fpswa_interface_t *fpswa_interface;
 EXPORT_SYMBOL(fpswa_interface);
 
-struct notifier_block *ia64die_chain;
+ATOMIC_NOTIFIER_HEAD(ia64die_chain);
 
 int
 register_die_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_register(&ia64die_chain, nb);
+	return atomic_notifier_chain_register(&ia64die_chain, nb);
 }
 EXPORT_SYMBOL_GPL(register_die_notifier);
 
 int
 unregister_die_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_unregister(&ia64die_chain, nb);
+	return atomic_notifier_chain_unregister(&ia64die_chain, nb);
 }
 EXPORT_SYMBOL_GPL(unregister_die_notifier);
 
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 0b9e56d..783600f 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -70,6 +70,15 @@
 	  __stop___ex_table = .;
 	}
 
+  /* MCA table */
+  . = ALIGN(16);
+  __mca_table : AT(ADDR(__mca_table) - LOAD_OFFSET)
+	{
+	  __start___mca_table = .;
+	  *(__mca_table)
+	  __stop___mca_table = .;
+	}
+
   /* Global data */
   _data = .;
 
@@ -130,15 +139,6 @@
 	  __initcall_end = .;
 	}
 
-  /* MCA table */
-  . = ALIGN(16);
-  __mca_table : AT(ADDR(__mca_table) - LOAD_OFFSET)
-	{
-	  __start___mca_table = .;
-	  *(__mca_table)
-	  __stop___mca_table = .;
-	}
-
   .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET)
 	{
 	  __start___vtop_patchlist = .;
diff --git a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile
index ac64664..d8536a2 100644
--- a/arch/ia64/lib/Makefile
+++ b/arch/ia64/lib/Makefile
@@ -6,7 +6,7 @@
 
 lib-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o			\
 	__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o			\
-	bitop.o checksum.o clear_page.o csum_partial_copy.o		\
+	checksum.o clear_page.o csum_partial_copy.o			\
 	clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o	\
 	flush.o ip_fast_csum.o do_csum.o				\
 	memset.o strlen.o
diff --git a/arch/ia64/lib/bitop.c b/arch/ia64/lib/bitop.c
deleted file mode 100644
index 82e299c..0000000
--- a/arch/ia64/lib/bitop.c
+++ /dev/null
@@ -1,88 +0,0 @@
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <asm/intrinsics.h>
-#include <linux/module.h>
-#include <linux/bitops.h>
-
-/*
- * Find next zero bit in a bitmap reasonably efficiently..
- */
-
-int __find_next_zero_bit (const void *addr, unsigned long size, unsigned long offset)
-{
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
-	unsigned long result = offset & ~63UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 63UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (64-offset);
-		if (size < 64)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 64;
-		result += 64;
-	}
-	while (size & ~63UL) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += 64;
-		size -= 64;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-found_first:
-	tmp |= ~0UL << size;
-	if (tmp == ~0UL)		/* any bits zero? */
-		return result + size;	/* nope */
-found_middle:
-	return result + ffz(tmp);
-}
-EXPORT_SYMBOL(__find_next_zero_bit);
-
-/*
- * Find next bit in a bitmap reasonably efficiently..
- */
-int __find_next_bit(const void *addr, unsigned long size, unsigned long offset)
-{
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
-	unsigned long result = offset & ~63UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 63UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp &= ~0UL << offset;
-		if (size < 64)
-			goto found_first;
-		if (tmp)
-			goto found_middle;
-		size -= 64;
-		result += 64;
-	}
-	while (size & ~63UL) {
-		if ((tmp = *(p++)))
-			goto found_middle;
-		result += 64;
-		size -= 64;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-  found_first:
-	tmp &= ~0UL >> (64-size);
-	if (tmp == 0UL)		/* Are any bits set? */
-		return result + size; /* Nope. */
-  found_middle:
-	return result + __ffs(tmp);
-}
-EXPORT_SYMBOL(__find_next_bit);
diff --git a/arch/ia64/mm/Makefile b/arch/ia64/mm/Makefile
index d78d20f..bb0a01a 100644
--- a/arch/ia64/mm/Makefile
+++ b/arch/ia64/mm/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the ia64-specific parts of the memory manager.
 #
 
-obj-y := init.o fault.o tlb.o extable.o
+obj-y := init.o fault.o tlb.o extable.o ioremap.o
 
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
 obj-$(CONFIG_NUMA)	   += numa.o
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index 2f5e448..ec9eeb8 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -379,31 +379,6 @@
 }
 
 /**
- * pgdat_insert - insert the pgdat into global pgdat_list
- * @pgdat: the pgdat for a node.
- */
-static void __init pgdat_insert(pg_data_t *pgdat)
-{
-	pg_data_t *prev = NULL, *next;
-
-	for_each_pgdat(next)
-		if (pgdat->node_id < next->node_id)
-			break;
-		else
-			prev = next;
-
-	if (prev) {
-		prev->pgdat_next = pgdat;
-		pgdat->pgdat_next = next;
-	} else {
-		pgdat->pgdat_next = pgdat_list;
-		pgdat_list = pgdat;
-	}
-
-	return;
-}
-
-/**
  * memory_less_nodes - allocate and initialize CPU only nodes pernode
  *	information.
  */
@@ -560,7 +535,7 @@
 	printk("Mem-info:\n");
 	show_free_areas();
 	printk("Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
-	for_each_pgdat(pgdat) {
+	for_each_online_pgdat(pgdat) {
 		unsigned long present;
 		unsigned long flags;
 		int shared = 0, cached = 0, reserved = 0;
@@ -745,11 +720,5 @@
 				    pfn_offset, zholes_size);
 	}
 
-	/*
-	 * Make memory less nodes become a member of the known nodes.
-	 */
-	for_each_node_mask(node, memory_less_mask)
-		pgdat_insert(mem_data[node].pgdat);
-
 	zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
 }
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index ff4f31f..cafa877 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -109,6 +109,7 @@
 {
 	unsigned long addr;
 	struct page *page;
+	unsigned long order;
 
 	if (!pte_exec(pte))
 		return;				/* not an executable page... */
@@ -119,7 +120,12 @@
 	if (test_bit(PG_arch_1, &page->flags))
 		return;				/* i-cache is already coherent with d-cache */
 
-	flush_icache_range(addr, addr + PAGE_SIZE);
+	if (PageCompound(page)) {
+		order = (unsigned long) (page[1].lru.prev);
+		flush_icache_range(addr, addr + (1UL << order << PAGE_SHIFT));
+	}
+	else
+		flush_icache_range(addr, addr + PAGE_SIZE);
 	set_bit(PG_arch_1, &page->flags);	/* mark page as clean */
 }
 
@@ -600,7 +606,7 @@
 	kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START);
 	kclist_add(&kcore_kernel, _stext, _end - _stext);
 
-	for_each_pgdat(pgdat)
+	for_each_online_pgdat(pgdat)
 		if (pgdat->bdata->node_bootmem_map)
 			totalram_pages += free_all_bootmem_node(pgdat);
 
diff --git a/arch/ia64/mm/ioremap.c b/arch/ia64/mm/ioremap.c
new file mode 100644
index 0000000..643ccc6
--- /dev/null
+++ b/arch/ia64/mm/ioremap.c
@@ -0,0 +1,43 @@
+/*
+ * (c) Copyright 2006 Hewlett-Packard Development Company, L.P.
+ *	Bjorn Helgaas <bjorn.helgaas@hp.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/compiler.h>
+#include <linux/module.h>
+#include <linux/efi.h>
+#include <asm/io.h>
+
+static inline void __iomem *
+__ioremap (unsigned long offset, unsigned long size)
+{
+	return (void __iomem *) (__IA64_UNCACHED_OFFSET | offset);
+}
+
+void __iomem *
+ioremap (unsigned long offset, unsigned long size)
+{
+	if (efi_mem_attribute_range(offset, size, EFI_MEMORY_WB))
+		return phys_to_virt(offset);
+
+	if (efi_mem_attribute_range(offset, size, EFI_MEMORY_UC))
+		return __ioremap(offset, size);
+
+	/*
+	 * Someday this should check ACPI resources so we
+	 * can do the right thing for hot-plugged regions.
+	 */
+	return __ioremap(offset, size);
+}
+EXPORT_SYMBOL(ioremap);
+
+void __iomem *
+ioremap_nocache (unsigned long offset, unsigned long size)
+{
+	return __ioremap(offset, size);
+}
+EXPORT_SYMBOL(ioremap_nocache);
diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c
index 6a4eec9..4dbbca0 100644
--- a/arch/ia64/mm/tlb.c
+++ b/arch/ia64/mm/tlb.c
@@ -156,17 +156,19 @@
 		nbits = purge.max_bits;
 	start &= ~((1UL << nbits) - 1);
 
-# ifdef CONFIG_SMP
-	platform_global_tlb_purge(mm, start, end, nbits);
-# else
 	preempt_disable();
+#ifdef CONFIG_SMP
+	if (mm != current->active_mm || cpus_weight(mm->cpu_vm_mask) != 1) {
+		platform_global_tlb_purge(mm, start, end, nbits);
+		preempt_enable();
+		return;
+	}
+#endif
 	do {
 		ia64_ptcl(start, (nbits<<2));
 		start += (1UL << nbits);
 	} while (start < end);
 	preempt_enable();
-# endif
-
 	ia64_srlz_i();			/* srlz.i implies srlz.d */
 }
 EXPORT_SYMBOL(flush_tlb_range);
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index 8b6d5c8..30988df 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -327,10 +327,11 @@
 	struct pcdp_interface_pci if_pci;
 	extern struct efi efi;
 
-	pcdp = efi.hcdp;
-	if (! pcdp)
+	if (efi.hcdp == EFI_INVALID_TABLE_ADDR)
 		return;		/* no hcdp/pcdp table */
 
+	pcdp = __va(efi.hcdp);
+
 	if (pcdp->rev < 3)
 		return;		/* only support PCDP (rev >= 3) */
 
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
index 70db21f..d917afa 100644
--- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c
+++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
@@ -110,7 +110,11 @@
 	if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab))
 		return -1;
 
-	for_each_node(cnode) {
+	/*
+	 * FIXME: replace with cleaner for_each_XXX macro which addresses
+	 * both compute and IO nodes once ACPI3.0 is available.
+	 */
+	for (cnode = 0; cnode < num_cnodes; cnode++) {
 		geoid = cnodeid_get_geoid(cnode);
 		module_id = geo_module(geoid);
 		this_rack = MODULE_GET_RACK(module_id);
@@ -605,7 +609,7 @@
 	op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK;
 
 	if (cpu != SN_HWPERF_ARG_ANY_CPU) {
-		if (cpu >= num_online_cpus() || !cpu_online(cpu)) {
+		if (cpu >= NR_CPUS || !cpu_online(cpu)) {
 			r = -EINVAL;
 			goto out;
 		}
diff --git a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
index c686d9c..5100261 100644
--- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
+++ b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
@@ -93,19 +93,22 @@
 static struct proc_dir_entry
 *sn_procfs_create_entry(const char *name, struct proc_dir_entry *parent,
 			int (*openfunc)(struct inode *, struct file *),
-			int (*releasefunc)(struct inode *, struct file *))
+	int (*releasefunc)(struct inode *, struct file *),
+	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *))
 {
 	struct proc_dir_entry *e = create_proc_entry(name, 0444, parent);
 
 	if (e) {
-		e->proc_fops = (struct file_operations *)kmalloc(
-			sizeof(struct file_operations), GFP_KERNEL);
-		if (e->proc_fops) {
-			memset(e->proc_fops, 0, sizeof(struct file_operations));
-			e->proc_fops->open = openfunc;
-			e->proc_fops->read = seq_read;
-			e->proc_fops->llseek = seq_lseek;
-			e->proc_fops->release = releasefunc;
+		struct file_operations *f;
+
+		f = kzalloc(sizeof(*f), GFP_KERNEL);
+		if (f) {
+			f->open = openfunc;
+			f->read = seq_read;
+			f->llseek = seq_lseek;
+			f->release = releasefunc;
+			f->write = write;
+			e->proc_fops = f;
 		}
 	}
 
@@ -119,31 +122,29 @@
 void register_sn_procfs(void)
 {
 	static struct proc_dir_entry *sgi_proc_dir = NULL;
-	struct proc_dir_entry *e;
 
 	BUG_ON(sgi_proc_dir != NULL);
 	if (!(sgi_proc_dir = proc_mkdir("sgi_sn", NULL)))
 		return;
 
 	sn_procfs_create_entry("partition_id", sgi_proc_dir,
-			       partition_id_open, single_release);
+		partition_id_open, single_release, NULL);
 
 	sn_procfs_create_entry("system_serial_number", sgi_proc_dir,
-			       system_serial_number_open, single_release);
+		system_serial_number_open, single_release, NULL);
 
 	sn_procfs_create_entry("licenseID", sgi_proc_dir, 
-			       licenseID_open, single_release);
+		licenseID_open, single_release, NULL);
 
-	e = sn_procfs_create_entry("sn_force_interrupt", sgi_proc_dir, 
-				   sn_force_interrupt_open, single_release);
-	if (e) 
-		e->proc_fops->write = sn_force_interrupt_write_proc;
+	sn_procfs_create_entry("sn_force_interrupt", sgi_proc_dir,
+		sn_force_interrupt_open, single_release,
+		sn_force_interrupt_write_proc);
 
 	sn_procfs_create_entry("coherence_id", sgi_proc_dir, 
-			       coherence_id_open, single_release);
+		coherence_id_open, single_release, NULL);
 	
 	sn_procfs_create_entry("sn_topology", sgi_proc_dir,
-			       sn_topology_open, sn_topology_release);
+		sn_topology_open, sn_topology_release, NULL);
 }
 
 #endif /* CONFIG_PROC_FS */
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index a3dcc3f..05c864c 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -214,6 +214,14 @@
 	bool
 	default n
 
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c
index d742037..0d78942 100644
--- a/arch/m32r/kernel/setup.c
+++ b/arch/m32r/kernel/setup.c
@@ -24,6 +24,7 @@
 #include <linux/tty.h>
 #include <linux/cpu.h>
 #include <linux/nodemask.h>
+#include <linux/pfn.h>
 
 #include <asm/processor.h>
 #include <asm/pgtable.h>
diff --git a/arch/m32r/mm/discontig.c b/arch/m32r/mm/discontig.c
index 08e7279..cf610a7 100644
--- a/arch/m32r/mm/discontig.c
+++ b/arch/m32r/mm/discontig.c
@@ -13,6 +13,7 @@
 #include <linux/initrd.h>
 #include <linux/nodemask.h>
 #include <linux/module.h>
+#include <linux/pfn.h>
 
 #include <asm/setup.h>
 
@@ -137,12 +138,6 @@
 	int nid, i;
 	mem_prof_t *mp;
 
-	pgdat_list = NULL;
-	for (nid = num_online_nodes() - 1 ; nid >= 0 ; nid--) {
-		NODE_DATA(nid)->pgdat_next = pgdat_list;
-		pgdat_list = NODE_DATA(nid);
-	}
-
 	for_each_online_node(nid) {
 		mp = &mem_prof[nid];
 		for (i = 0 ; i < MAX_NR_ZONES ; i++) {
diff --git a/arch/m32r/mm/init.c b/arch/m32r/mm/init.c
index c9e7dad..b71348f 100644
--- a/arch/m32r/mm/init.c
+++ b/arch/m32r/mm/init.c
@@ -18,6 +18,7 @@
 #include <linux/highmem.h>
 #include <linux/bitops.h>
 #include <linux/nodemask.h>
+#include <linux/pfn.h>
 #include <asm/types.h>
 #include <asm/processor.h>
 #include <asm/page.h>
@@ -47,7 +48,7 @@
 	printk("Mem-info:\n");
 	show_free_areas();
 	printk("Free swap:       %6ldkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-	for_each_pgdat(pgdat) {
+	for_each_online_pgdat(pgdat) {
 		unsigned long flags;
 		pgdat_resize_lock(pgdat, &flags);
 		for (i = 0; i < pgdat->node_spanned_pages; ++i) {
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 8849439..805b81f 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -17,6 +17,10 @@
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index 3ffc84f..c90cb5f 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -142,7 +142,7 @@
     /* Now do the PIT configuration */
 
     pit->pgcr	= 0x00;	/* Unidirectional 8 bit, no handshake for now */
-    pit->psrr	= 0x18;	/* PIACK and PIRQ fucntions enabled */
+    pit->psrr	= 0x18;	/* PIACK and PIRQ functions enabled */
     pit->pacr	= 0x00;	/* Sub Mode 00, H2 i/p, no DMA */
     pit->padr	= 0x00;	/* Just to be tidy! */
     pit->paddr	= 0x00;	/* All inputs for now (safest) */
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index 3d7f200..c331951 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -79,4 +79,3 @@
 EXPORT_SYMBOL(__down_failed_trylock);
 EXPORT_SYMBOL(__up_wakeup);
 
-EXPORT_SYMBOL(get_wchan);
diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c
index a69fe30..b0e4c08 100644
--- a/arch/m68k/mvme16x/rtc.c
+++ b/arch/m68k/mvme16x/rtc.c
@@ -17,6 +17,7 @@
 #include <linux/poll.h>
 #include <linux/mc146818rtc.h>	/* For struct rtc_time and ioctls, etc */
 #include <linux/smp_lock.h>
+#include <linux/bcd.h>
 #include <asm/mvme16xhw.h>
 
 #include <asm/io.h>
@@ -31,9 +32,6 @@
  *	ioctls.
  */
 
-#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10)
-#define BIN2BCD(val) ((((val)/10)<<4) + (val)%10)
-
 static const unsigned char days_in_mo[] =
 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index e50858d..3cde682 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -25,6 +25,14 @@
 	bool
 	default n
 
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff --git a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68knommu/kernel/m68k_ksyms.c
index d844c75..f9b4ea1 100644
--- a/arch/m68knommu/kernel/m68k_ksyms.c
+++ b/arch/m68knommu/kernel/m68k_ksyms.c
@@ -57,8 +57,6 @@
 EXPORT_SYMBOL(__down_failed_trylock);
 EXPORT_SYMBOL(__up_wakeup);
 
-EXPORT_SYMBOL(get_wchan);
-
 /*
  * libgcc functions - functions that are used internally by the
  * compiler...  (prototypes are not correct though, but that
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index ac2012f..5080ea1 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -801,6 +801,14 @@
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index 1080558..307e98c 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -94,7 +94,7 @@
 
 	argptr = prom_getcmdline();
 
-#if defined(CONFIG_SERIAL_AU1X00_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
+#ifdef CONFIG_SERIAL_8250_CONSOLE
 	if ((argptr = strstr(argptr, "console=")) == NULL) {
 		argptr = prom_getcmdline();
 		strcat(argptr, " console=ttyS0,115200");
diff --git a/arch/mips/ddb5xxx/common/rtc_ds1386.c b/arch/mips/ddb5xxx/common/rtc_ds1386.c
index 995896a..5dc34da 100644
--- a/arch/mips/ddb5xxx/common/rtc_ds1386.c
+++ b/arch/mips/ddb5xxx/common/rtc_ds1386.c
@@ -165,6 +165,6 @@
 	WRITE_RTC(0xB, byte);
 
 	/* set the function pointers */
-	rtc_get_time = rtc_ds1386_get_time;
-	rtc_set_time = rtc_ds1386_set_time;
+	rtc_mips_get_time = rtc_ds1386_get_time;
+	rtc_mips_set_time = rtc_ds1386_set_time;
 }
diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c
index 1748223..74cb055 100644
--- a/arch/mips/dec/time.c
+++ b/arch/mips/dec/time.c
@@ -36,41 +36,13 @@
 #include <asm/dec/ioasic_addrs.h>
 #include <asm/dec/machtype.h>
 
-
-/*
- * Returns true if a clock update is in progress
- */
-static inline unsigned char dec_rtc_is_updating(void)
-{
-	unsigned char uip;
-	unsigned long flags;
-
-	spin_lock_irqsave(&rtc_lock, flags);
-	uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
-	spin_unlock_irqrestore(&rtc_lock, flags);
-	return uip;
-}
-
 static unsigned long dec_rtc_get_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec, real_year;
-	int i;
 	unsigned long flags;
 
-	/* The Linux interpretation of the DS1287 clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-	/* read RTC exactly on falling edge of update flag */
-	for (i = 0; i < 1000000; i++)	/* may take up to 1 second... */
-		if (dec_rtc_is_updating())
-			break;
-	for (i = 0; i < 1000000; i++)	/* must try at least 2.228 ms */
-		if (!dec_rtc_is_updating())
-			break;
 	spin_lock_irqsave(&rtc_lock, flags);
-	/* Isn't this overkill?  UIP above should guarantee consistency */
+
 	do {
 		sec = CMOS_READ(RTC_SECONDS);
 		min = CMOS_READ(RTC_MINUTES);
@@ -78,7 +50,16 @@
 		day = CMOS_READ(RTC_DAY_OF_MONTH);
 		mon = CMOS_READ(RTC_MONTH);
 		year = CMOS_READ(RTC_YEAR);
+		/*
+		 * The PROM will reset the year to either '72 or '73.
+		 * Therefore we store the real year separately, in one
+		 * of unused BBU RAM locations.
+		 */
+		real_year = CMOS_READ(RTC_DEC_YEAR);
 	} while (sec != CMOS_READ(RTC_SECONDS));
+
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
 	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
 		sec = BCD2BIN(sec);
 		min = BCD2BIN(min);
@@ -87,13 +68,7 @@
 		mon = BCD2BIN(mon);
 		year = BCD2BIN(year);
 	}
-	/*
-	 * The PROM will reset the year to either '72 or '73.
-	 * Therefore we store the real year separately, in one
-	 * of unused BBU RAM locations.
-	 */
-	real_year = CMOS_READ(RTC_DEC_YEAR);
-	spin_unlock_irqrestore(&rtc_lock, flags);
+
 	year += real_year - 72 + 2000;
 
 	return mktime(year, mon, day, hour, min, sec);
@@ -193,8 +168,8 @@
 
 void __init dec_time_init(void)
 {
-	rtc_get_time = dec_rtc_get_time;
-	rtc_set_mmss = dec_rtc_set_mmss;
+	rtc_mips_get_time = dec_rtc_get_time;
+	rtc_mips_set_mmss = dec_rtc_set_mmss;
 
 	mips_timer_state = dec_timer_state;
 	mips_timer_ack = dec_timer_ack;
diff --git a/arch/mips/ite-boards/generic/time.c b/arch/mips/ite-boards/generic/time.c
index f5d67ee..b79817b 100644
--- a/arch/mips/ite-boards/generic/time.c
+++ b/arch/mips/ite-boards/generic/time.c
@@ -227,8 +227,8 @@
 
 	local_irq_restore(flags);
 
-	rtc_get_time = it8172_rtc_get_time;
-	rtc_set_time = it8172_rtc_set_time;
+	rtc_mips_get_time = it8172_rtc_get_time;
+	rtc_mips_set_time = it8172_rtc_set_time;
 }
 
 #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
diff --git a/arch/mips/ite-boards/ivr/init.c b/arch/mips/ite-boards/ivr/init.c
index ea4e193..b774db0 100644
--- a/arch/mips/ite-boards/ivr/init.c
+++ b/arch/mips/ite-boards/ivr/init.c
@@ -45,9 +45,6 @@
 extern unsigned long __init prom_get_memsize(void);
 extern void __init it8172_init_ram_resource(unsigned long memsize);
 
-#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_ALIGN(x)	(((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
-
 const char *get_system_type(void)
 {
 	return "Globespan IVR";
diff --git a/arch/mips/ite-boards/qed-4n-s01b/init.c b/arch/mips/ite-boards/qed-4n-s01b/init.c
index 56dca7e..e8ec8be 100644
--- a/arch/mips/ite-boards/qed-4n-s01b/init.c
+++ b/arch/mips/ite-boards/qed-4n-s01b/init.c
@@ -45,9 +45,6 @@
 extern unsigned long __init prom_get_memsize(void);
 extern void __init it8172_init_ram_resource(unsigned long memsize);
 
-#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_ALIGN(x)	(((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
-
 const char *get_system_type(void)
 {
 	return "ITE QED-4N-S01B";
diff --git a/arch/mips/jmr3927/common/rtc_ds1742.c b/arch/mips/jmr3927/common/rtc_ds1742.c
index 9a8bff1..a6bd3f4 100644
--- a/arch/mips/jmr3927/common/rtc_ds1742.c
+++ b/arch/mips/jmr3927/common/rtc_ds1742.c
@@ -159,8 +159,8 @@
 	db_assert((rtc_base & 0xe0000000) == KSEG1);
 
 	/* set the function pointers */
-	rtc_get_time = rtc_ds1742_get_time;
-	rtc_set_time = rtc_ds1742_set_time;
+	rtc_mips_get_time = rtc_ds1742_get_time;
+	rtc_mips_set_time = rtc_ds1742_set_time;
 
 	/* clear oscillator stop bit */
 	CMOS_WRITE(RTC_READ, RTC_CONTROL);
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c
index 08273a2..8150f07 100644
--- a/arch/mips/kernel/irixsig.c
+++ b/arch/mips/kernel/irixsig.c
@@ -603,7 +603,7 @@
 			/* move to end of parent's list to avoid starvation */
 			write_lock_irq(&tasklist_lock);
 			remove_parent(p);
-			add_parent(p, p->parent);
+			add_parent(p);
 			write_unlock_irq(&tasklist_lock);
 			retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
 			if (retval)
@@ -643,7 +643,7 @@
 				write_lock_irq(&tasklist_lock);
 				remove_parent(p);
 				p->parent = p->real_parent;
-				add_parent(p, p->parent);
+				add_parent(p);
 				do_notify_parent(p, SIGCHLD);
 				write_unlock_irq(&tasklist_lock);
 			} else
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 013bc93..3f40c37 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -30,7 +30,6 @@
 #include <linux/utime.h>
 #include <linux/utsname.h>
 #include <linux/personality.h>
-#include <linux/timex.h>
 #include <linux/dnotify.h>
 #include <linux/module.h>
 #include <linux/binfmts.h>
@@ -1157,79 +1156,6 @@
 	return err;
 }
 
-/* Handle adjtimex compatibility. */
-
-struct timex32 {
-	u32 modes;
-	s32 offset, freq, maxerror, esterror;
-	s32 status, constant, precision, tolerance;
-	struct compat_timeval time;
-	s32 tick;
-	s32 ppsfreq, jitter, shift, stabil;
-	s32 jitcnt, calcnt, errcnt, stbcnt;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-};
-
-extern int do_adjtimex(struct timex *);
-
-asmlinkage int sys32_adjtimex(struct timex32 __user *utp)
-{
-	struct timex txc;
-	int ret;
-
-	memset(&txc, 0, sizeof(struct timex));
-
-	if (get_user(txc.modes, &utp->modes) ||
-	   __get_user(txc.offset, &utp->offset) ||
-	   __get_user(txc.freq, &utp->freq) ||
-	   __get_user(txc.maxerror, &utp->maxerror) ||
-	   __get_user(txc.esterror, &utp->esterror) ||
-	   __get_user(txc.status, &utp->status) ||
-	   __get_user(txc.constant, &utp->constant) ||
-	   __get_user(txc.precision, &utp->precision) ||
-	   __get_user(txc.tolerance, &utp->tolerance) ||
-	   __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	   __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	   __get_user(txc.tick, &utp->tick) ||
-	   __get_user(txc.ppsfreq, &utp->ppsfreq) ||
-	   __get_user(txc.jitter, &utp->jitter) ||
-	   __get_user(txc.shift, &utp->shift) ||
-	   __get_user(txc.stabil, &utp->stabil) ||
-	   __get_user(txc.jitcnt, &utp->jitcnt) ||
-	   __get_user(txc.calcnt, &utp->calcnt) ||
-	   __get_user(txc.errcnt, &utp->errcnt) ||
-	   __get_user(txc.stbcnt, &utp->stbcnt))
-		return -EFAULT;
-
-	ret = do_adjtimex(&txc);
-
-	if (put_user(txc.modes, &utp->modes) ||
-	   __put_user(txc.offset, &utp->offset) ||
-	   __put_user(txc.freq, &utp->freq) ||
-	   __put_user(txc.maxerror, &utp->maxerror) ||
-	   __put_user(txc.esterror, &utp->esterror) ||
-	   __put_user(txc.status, &utp->status) ||
-	   __put_user(txc.constant, &utp->constant) ||
-	   __put_user(txc.precision, &utp->precision) ||
-	   __put_user(txc.tolerance, &utp->tolerance) ||
-	   __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	   __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	   __put_user(txc.tick, &utp->tick) ||
-	   __put_user(txc.ppsfreq, &utp->ppsfreq) ||
-	   __put_user(txc.jitter, &utp->jitter) ||
-	   __put_user(txc.shift, &utp->shift) ||
-	   __put_user(txc.stabil, &utp->stabil) ||
-	   __put_user(txc.jitcnt, &utp->jitcnt) ||
-	   __put_user(txc.calcnt, &utp->calcnt) ||
-	   __put_user(txc.errcnt, &utp->errcnt) ||
-	   __put_user(txc.stbcnt, &utp->stbcnt))
-		ret = -EFAULT;
-
-	return ret;
-}
-
 asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset,
 	s32 count)
 {
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index a8f435d..c66db5e 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -419,4 +419,3 @@
 	return pc;
 }
 
-EXPORT_SYMBOL(get_wchan);
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 02c8267..05a2c05 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -273,7 +273,7 @@
 	PTR	sys_pivot_root
 	PTR	sys32_sysctl
 	PTR	sys_prctl
-	PTR	sys32_adjtimex
+	PTR	compat_sys_adjtimex
 	PTR	compat_sys_setrlimit		/* 6155 */
 	PTR	sys_chroot
 	PTR	sys_sync
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 797e0d8..19c4ca4 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -328,7 +328,7 @@
 	PTR	sys_setdomainname
 	PTR	sys32_newuname
 	PTR	sys_ni_syscall			/* sys_modify_ldt */
-	PTR	sys32_adjtimex
+	PTR	compat_sys_adjtimex
 	PTR	sys_mprotect			/* 4125 */
 	PTR	compat_sys_sigprocmask
 	PTR	sys_ni_syscall			/* was creat_module */
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 0cb3b60..dcbfd27 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -34,6 +34,7 @@
 #include <linux/highmem.h>
 #include <linux/console.h>
 #include <linux/mmzone.h>
+#include <linux/pfn.h>
 
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
@@ -257,10 +258,6 @@
 	return 0;
 }
 
-#define PFN_UP(x)	(((x) + PAGE_SIZE - 1) >> PAGE_SHIFT)
-#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
-#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
-
 #define MAXMEM		HIGHMEM_START
 #define MAXMEM_PFN	PFN_DOWN(MAXMEM)
 
@@ -493,10 +490,6 @@
 	}
 }
 
-#undef PFN_UP
-#undef PFN_DOWN
-#undef PFN_PHYS
-
 #undef MAXMEM
 #undef MAXMEM_PFN
 
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 51273b7..5e51a2d 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -65,9 +65,9 @@
 	return 0;
 }
 
-unsigned long (*rtc_get_time)(void) = null_rtc_get_time;
-int (*rtc_set_time)(unsigned long) = null_rtc_set_time;
-int (*rtc_set_mmss)(unsigned long);
+unsigned long (*rtc_mips_get_time)(void) = null_rtc_get_time;
+int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time;
+int (*rtc_mips_set_mmss)(unsigned long);
 
 
 /* usecs per counter cycle, shifted to left by 32 bits */
@@ -440,14 +440,14 @@
 
 	/*
 	 * If we have an externally synchronized Linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes. rtc_set_time() has to be
+	 * CMOS clock accordingly every ~11 minutes. rtc_mips_set_time() has to be
 	 * called as close as possible to 500 ms before the new second starts.
 	 */
 	if (ntp_synced() &&
 	    xtime.tv_sec > last_rtc_update + 660 &&
 	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
 	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
-		if (rtc_set_mmss(xtime.tv_sec) == 0) {
+		if (rtc_mips_set_mmss(xtime.tv_sec) == 0) {
 			last_rtc_update = xtime.tv_sec;
 		} else {
 			/* do it again in 60 s */
@@ -565,7 +565,7 @@
  *      b) (optional) calibrate and set the mips_hpt_frequency
  *	    (only needed if you intended to use fixed_rate_gettimeoffset
  *	     or use cpu counter as timer interrupt source)
- * 2) setup xtime based on rtc_get_time().
+ * 2) setup xtime based on rtc_mips_get_time().
  * 3) choose a appropriate gettimeoffset routine.
  * 4) calculate a couple of cached variables for later usage
  * 5) board_timer_setup() -
@@ -633,10 +633,10 @@
 	if (board_time_init)
 		board_time_init();
 
-	if (!rtc_set_mmss)
-		rtc_set_mmss = rtc_set_time;
+	if (!rtc_mips_set_mmss)
+		rtc_mips_set_mmss = rtc_mips_set_time;
 
-	xtime.tv_sec = rtc_get_time();
+	xtime.tv_sec = rtc_mips_get_time();
 	xtime.tv_nsec = 0;
 
 	set_normalized_timespec(&wall_to_monotonic,
@@ -772,8 +772,8 @@
 
 EXPORT_SYMBOL(rtc_lock);
 EXPORT_SYMBOL(to_tm);
-EXPORT_SYMBOL(rtc_set_time);
-EXPORT_SYMBOL(rtc_get_time);
+EXPORT_SYMBOL(rtc_mips_set_time);
+EXPORT_SYMBOL(rtc_mips_get_time);
 
 unsigned long long sched_clock(void)
 {
diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c
index 83eb08b..bb70a82 100644
--- a/arch/mips/lasat/setup.c
+++ b/arch/mips/lasat/setup.c
@@ -165,7 +165,8 @@
 
 	/* Set up panic notifier */
 	for (i = 0; i < sizeof(lasat_panic_block) / sizeof(struct notifier_block); i++)
-		notifier_chain_register(&panic_notifier_list, &lasat_panic_block[i]);
+		atomic_notifier_chain_register(&panic_notifier_list,
+				&lasat_panic_block[i]);
 
 	lasat_reboot_setup();
 
@@ -174,8 +175,8 @@
 
 #ifdef CONFIG_DS1603
 	ds1603 = &ds_defs[mips_machtype];
-	rtc_get_time = ds1603_read;
-	rtc_set_time = ds1603_set;
+	rtc_mips_get_time = ds1603_read;
+	rtc_mips_set_time = ds1603_set;
 #endif
 
 #ifdef DYNAMIC_SERIAL_INIT
diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c
index 8ff43a1..e3d5aaa 100644
--- a/arch/mips/lasat/sysctl.c
+++ b/arch/mips/lasat/sysctl.c
@@ -30,12 +30,13 @@
 #include <linux/string.h>
 #include <linux/net.h>
 #include <linux/inet.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include "sysctl.h"
 #include "ds1603.h"
 
-static DECLARE_MUTEX(lasat_info_sem);
+static DEFINE_MUTEX(lasat_info_mutex);
 
 /* Strategy function to write EEPROM after changing string entry */
 int sysctl_lasatstring(ctl_table *table, int *name, int nlen,
@@ -43,17 +44,17 @@
 		void *newval, size_t newlen, void **context)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	r = sysctl_string(table, name,
 			  nlen, oldval, oldlenp, newval, newlen, context);
 	if (r < 0) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	if (newval && newlen) {
 		lasat_write_eeprom_info();
 	}
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 1;
 }
 
@@ -63,14 +64,14 @@
 		       void *buffer, size_t *lenp, loff_t *ppos)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	r = proc_dostring(table, write, filp, buffer, lenp, ppos);
 	if ( (!write) || r) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	lasat_write_eeprom_info();
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 0;
 }
 
@@ -79,14 +80,14 @@
 		       void *buffer, size_t *lenp, loff_t *ppos)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	r = proc_dointvec(table, write, filp, buffer, lenp, ppos);
 	if ( (!write) || r) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	lasat_write_eeprom_info();
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 0;
 }
 
@@ -98,7 +99,7 @@
 		       void *buffer, size_t *lenp, loff_t *ppos)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	if (!write) {
 		rtctmp = ds1603_read();
 		/* check for time < 0 and set to 0 */
@@ -107,11 +108,11 @@
 	}
 	r = proc_dointvec(table, write, filp, buffer, lenp, ppos);
 	if ( (!write) || r) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	ds1603_set(rtctmp);
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 0;
 }
 #endif
@@ -122,16 +123,16 @@
 		    void *newval, size_t newlen, void **context)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
 	if (r < 0) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	if (newval && newlen) {
 		lasat_write_eeprom_info();
 	}
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 1;
 }
 
@@ -142,19 +143,19 @@
 		    void *newval, size_t newlen, void **context)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	rtctmp = ds1603_read();
 	if (rtctmp < 0)
 		rtctmp = 0;
 	r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
 	if (r < 0) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	if (newval && newlen) {
 		ds1603_set(rtctmp);
 	}
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 1;
 }
 #endif
@@ -192,13 +193,13 @@
 		return 0;
 	}
 
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	if (write) {
 		len = 0;
 		p = buffer;
 		while (len < *lenp) {
 			if(get_user(c, p++)) {
-				up(&lasat_info_sem);
+				mutex_unlock(&lasat_info_mutex);
 				return -EFAULT;
 			}
 			if (c == 0 || c == '\n')
@@ -209,7 +210,7 @@
 			len = sizeof(proc_lasat_ipbuf) - 1;
 		if (copy_from_user(proc_lasat_ipbuf, buffer, len))
 		{
-			up(&lasat_info_sem);
+			mutex_unlock(&lasat_info_mutex);
 			return -EFAULT;
 		}
 		proc_lasat_ipbuf[len] = 0;
@@ -230,12 +231,12 @@
 			len = *lenp;
 		if (len)
 			if(copy_to_user(buffer, proc_lasat_ipbuf, len)) {
-				up(&lasat_info_sem);
+				mutex_unlock(&lasat_info_mutex);
 				return -EFAULT;
 			}
 		if (len < *lenp) {
 			if(put_user('\n', ((char *) buffer) + len)) {
-				up(&lasat_info_sem);
+				mutex_unlock(&lasat_info_mutex);
 				return -EFAULT;
 			}
 			len++;
@@ -244,7 +245,7 @@
 		*ppos += len;
 	}
 	update_bcastaddr();
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 0;
 }
 #endif /* defined(CONFIG_INET) */
@@ -256,10 +257,10 @@
 {
 	int r;
 
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
 	if (r < 0) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 
@@ -271,7 +272,7 @@
 		lasat_write_eeprom_info();
 		lasat_init_board_info();
 	}
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 
 	return 0;
 }
@@ -280,10 +281,10 @@
 		       void *buffer, size_t *lenp, loff_t *ppos)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	r = proc_dointvec(table, write, filp, buffer, lenp, ppos);
 	if ( (!write) || r) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	if (filp && filp->f_dentry)
@@ -294,7 +295,7 @@
 			lasat_board_info.li_eeprom_info.debugaccess = lasat_board_info.li_debugaccess;
 	}
 	lasat_write_eeprom_info();
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 0;
 }
 
diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c
index 873cf31..c20d401 100644
--- a/arch/mips/mips-boards/atlas/atlas_setup.c
+++ b/arch/mips/mips-boards/atlas/atlas_setup.c
@@ -65,7 +65,7 @@
 
 	board_time_init = mips_time_init;
 	board_timer_setup = mips_timer_setup;
-	rtc_get_time = mips_rtc_get_time;
+	rtc_mips_get_time = mips_rtc_get_time;
 }
 
 static void __init serial_init(void)
diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c
index ee5e70c..32c9210 100644
--- a/arch/mips/mips-boards/generic/memory.c
+++ b/arch/mips/mips-boards/generic/memory.c
@@ -49,9 +49,6 @@
 /* References to section boundaries */
 extern char _end;
 
-#define PFN_ALIGN(x)    (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
-
-
 struct prom_pmemblock * __init prom_getmdesc(void)
 {
 	char *memsize_str;
@@ -109,10 +106,10 @@
 
 	mdesc[3].type = yamon_dontuse;
 	mdesc[3].base = 0x00100000;
-	mdesc[3].size = CPHYSADDR(PFN_ALIGN(&_end)) - mdesc[3].base;
+	mdesc[3].size = CPHYSADDR(PAGE_ALIGN(&_end)) - mdesc[3].base;
 
 	mdesc[4].type = yamon_free;
-	mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end));
+	mdesc[4].base = CPHYSADDR(PAGE_ALIGN(&_end));
 	mdesc[4].size = memsize - mdesc[4].base;
 
 	return &mdesc[0];
diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c
index 2209e8a..b8488aa 100644
--- a/arch/mips/mips-boards/malta/malta_setup.c
+++ b/arch/mips/mips-boards/malta/malta_setup.c
@@ -225,5 +225,5 @@
 
 	board_time_init = mips_time_init;
 	board_timer_setup = mips_timer_setup;
-	rtc_get_time = mips_rtc_get_time;
+	rtc_mips_get_time = mips_rtc_get_time;
 }
diff --git a/arch/mips/mips-boards/sim/sim_mem.c b/arch/mips/mips-boards/sim/sim_mem.c
index 1ec4e75..e57f737 100644
--- a/arch/mips/mips-boards/sim/sim_mem.c
+++ b/arch/mips/mips-boards/sim/sim_mem.c
@@ -42,9 +42,6 @@
 /* References to section boundaries */
 extern char _end;
 
-#define PFN_ALIGN(x)    (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
-
-
 struct prom_pmemblock * __init prom_getmdesc(void)
 {
 	unsigned int memsize;
@@ -64,10 +61,10 @@
 
 	mdesc[2].type = simmem_reserved;
 	mdesc[2].base = 0x00100000;
-	mdesc[2].size = CPHYSADDR(PFN_ALIGN(&_end)) - mdesc[2].base;
+	mdesc[2].size = CPHYSADDR(PAGE_ALIGN(&_end)) - mdesc[2].base;
 
 	mdesc[3].type = simmem_free;
-	mdesc[3].base = CPHYSADDR(PFN_ALIGN(&_end));
+	mdesc[3].base = CPHYSADDR(PAGE_ALIGN(&_end));
 	mdesc[3].size = memsize - mdesc[3].base;
 
 	return &mdesc[0];
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 52f7d59..ad89c44 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -25,6 +25,7 @@
 #include <linux/highmem.h>
 #include <linux/swap.h>
 #include <linux/proc_fs.h>
+#include <linux/pfn.h>
 
 #include <asm/bootinfo.h>
 #include <asm/cachectl.h>
@@ -177,9 +178,6 @@
 	free_area_init(zones_size);
 }
 
-#define PFN_UP(x)	(((x) + PAGE_SIZE - 1) >> PAGE_SHIFT)
-#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
-
 static inline int page_is_ram(unsigned long pagenr)
 {
 	int i;
diff --git a/arch/mips/momentum/jaguar_atx/setup.c b/arch/mips/momentum/jaguar_atx/setup.c
index 3784c89..91d9637 100644
--- a/arch/mips/momentum/jaguar_atx/setup.c
+++ b/arch/mips/momentum/jaguar_atx/setup.c
@@ -229,8 +229,8 @@
 	mips_hpt_frequency = cpu_clock / 2;
 	board_timer_setup = momenco_timer_setup;
 
-	rtc_get_time = m48t37y_get_time;
-	rtc_set_time = m48t37y_set_time;
+	rtc_mips_get_time = m48t37y_get_time;
+	rtc_mips_set_time = m48t37y_set_time;
 }
 
 static struct resource mv_pci_io_mem0_resource = {
diff --git a/arch/mips/momentum/ocelot_3/setup.c b/arch/mips/momentum/ocelot_3/setup.c
index f95677f..370e75d 100644
--- a/arch/mips/momentum/ocelot_3/setup.c
+++ b/arch/mips/momentum/ocelot_3/setup.c
@@ -58,6 +58,7 @@
 #include <linux/bootmem.h>
 #include <linux/mv643xx.h>
 #include <linux/pm.h>
+#include <linux/bcd.h>
 
 #include <asm/time.h>
 #include <asm/page.h>
@@ -131,9 +132,6 @@
 	add_wired_entry(ENTRYLO(0xfc000000), ENTRYLO(0xfd000000), (signed)0xfc000000, PM_16M);
 }
 
-#define CONV_BCD_TO_BIN(val)	(((val) & 0xf) + (((val) >> 4) * 10))
-#define CONV_BIN_TO_BCD(val)	(((val) % 10) + (((val) / 10) << 4))
-
 unsigned long m48t37y_get_time(void)
 {
 	unsigned int year, month, day, hour, min, sec;
@@ -143,16 +141,16 @@
 	/* stop the update */
 	rtc_base[0x7ff8] = 0x40;
 
-	year = CONV_BCD_TO_BIN(rtc_base[0x7fff]);
-	year += CONV_BCD_TO_BIN(rtc_base[0x7ff1]) * 100;
+	year = BCD2BIN(rtc_base[0x7fff]);
+	year += BCD2BIN(rtc_base[0x7ff1]) * 100;
 
-	month = CONV_BCD_TO_BIN(rtc_base[0x7ffe]);
+	month = BCD2BIN(rtc_base[0x7ffe]);
 
-	day = CONV_BCD_TO_BIN(rtc_base[0x7ffd]);
+	day = BCD2BIN(rtc_base[0x7ffd]);
 
-	hour = CONV_BCD_TO_BIN(rtc_base[0x7ffb]);
-	min = CONV_BCD_TO_BIN(rtc_base[0x7ffa]);
-	sec = CONV_BCD_TO_BIN(rtc_base[0x7ff9]);
+	hour = BCD2BIN(rtc_base[0x7ffb]);
+	min = BCD2BIN(rtc_base[0x7ffa]);
+	sec = BCD2BIN(rtc_base[0x7ff9]);
 
 	/* start the update */
 	rtc_base[0x7ff8] = 0x00;
@@ -175,22 +173,22 @@
 	rtc_base[0x7ff8] = 0x80;
 
 	/* year */
-	rtc_base[0x7fff] = CONV_BIN_TO_BCD(tm.tm_year % 100);
-	rtc_base[0x7ff1] = CONV_BIN_TO_BCD(tm.tm_year / 100);
+	rtc_base[0x7fff] = BIN2BCD(tm.tm_year % 100);
+	rtc_base[0x7ff1] = BIN2BCD(tm.tm_year / 100);
 
 	/* month */
-	rtc_base[0x7ffe] = CONV_BIN_TO_BCD(tm.tm_mon);
+	rtc_base[0x7ffe] = BIN2BCD(tm.tm_mon);
 
 	/* day */
-	rtc_base[0x7ffd] = CONV_BIN_TO_BCD(tm.tm_mday);
+	rtc_base[0x7ffd] = BIN2BCD(tm.tm_mday);
 
 	/* hour/min/sec */
-	rtc_base[0x7ffb] = CONV_BIN_TO_BCD(tm.tm_hour);
-	rtc_base[0x7ffa] = CONV_BIN_TO_BCD(tm.tm_min);
-	rtc_base[0x7ff9] = CONV_BIN_TO_BCD(tm.tm_sec);
+	rtc_base[0x7ffb] = BIN2BCD(tm.tm_hour);
+	rtc_base[0x7ffa] = BIN2BCD(tm.tm_min);
+	rtc_base[0x7ff9] = BIN2BCD(tm.tm_sec);
 
 	/* day of week -- not really used, but let's keep it up-to-date */
-	rtc_base[0x7ffc] = CONV_BIN_TO_BCD(tm.tm_wday + 1);
+	rtc_base[0x7ffc] = BIN2BCD(tm.tm_wday + 1);
 
 	/* disable writing */
 	rtc_base[0x7ff8] = 0x00;
@@ -215,8 +213,8 @@
 	mips_hpt_frequency = cpu_clock / 2;
 	board_timer_setup = momenco_timer_setup;
 
-	rtc_get_time = m48t37y_get_time;
-	rtc_set_time = m48t37y_set_time;
+	rtc_mips_get_time = m48t37y_get_time;
+	rtc_mips_set_time = m48t37y_set_time;
 }
 
 /*
diff --git a/arch/mips/momentum/ocelot_c/setup.c b/arch/mips/momentum/ocelot_c/setup.c
index bd02e60..a3e6f55 100644
--- a/arch/mips/momentum/ocelot_c/setup.c
+++ b/arch/mips/momentum/ocelot_c/setup.c
@@ -227,8 +227,8 @@
 	printk("momenco_time_init cpu_clock=%d\n", cpu_clock);
 	board_timer_setup = momenco_timer_setup;
 
-	rtc_get_time = m48t37y_get_time;
-	rtc_set_time = m48t37y_set_time;
+	rtc_mips_get_time = m48t37y_get_time;
+	rtc_mips_set_time = m48t37y_set_time;
 }
 
 void __init plat_setup(void)
diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c
index 8bce711..3f724d6 100644
--- a/arch/mips/pmc-sierra/yosemite/setup.c
+++ b/arch/mips/pmc-sierra/yosemite/setup.c
@@ -198,8 +198,8 @@
 	if (!m48t37_base)
 		printk(KERN_ERR "Mapping the RTC failed\n");
 
-	rtc_get_time = m48t37y_get_time;
-	rtc_set_time = m48t37y_set_time;
+	rtc_mips_get_time = m48t37y_get_time;
+	rtc_mips_set_time = m48t37y_set_time;
 
 	write_seqlock(&xtime_lock);
 	xtime.tv_sec = m48t37y_get_time();
diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c
index 92a3b3c..a9c58e0 100644
--- a/arch/mips/sgi-ip22/ip22-reset.c
+++ b/arch/mips/sgi-ip22/ip22-reset.c
@@ -238,7 +238,7 @@
 	request_irq(SGI_PANEL_IRQ, panel_int, 0, "Front Panel", NULL);
 	init_timer(&blink_timer);
 	blink_timer.function = blink_timeout;
-	notifier_chain_register(&panic_notifier_list, &panic_block);
+	atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
 
 	return 0;
 }
diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c
index b7300cc..cca688a 100644
--- a/arch/mips/sgi-ip22/ip22-time.c
+++ b/arch/mips/sgi-ip22/ip22-time.c
@@ -212,8 +212,8 @@
 void __init ip22_time_init(void)
 {
 	/* setup hookup functions */
-	rtc_get_time = indy_rtc_get_time;
-	rtc_set_time = indy_rtc_set_time;
+	rtc_mips_get_time = indy_rtc_get_time;
+	rtc_mips_set_time = indy_rtc_set_time;
 
 	board_time_init = indy_time_init;
 	board_timer_setup = indy_timer_setup;
diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
index e0d095d..6c00dce 100644
--- a/arch/mips/sgi-ip27/ip27-memory.c
+++ b/arch/mips/sgi-ip27/ip27-memory.c
@@ -19,6 +19,7 @@
 #include <linux/nodemask.h>
 #include <linux/swap.h>
 #include <linux/bootmem.h>
+#include <linux/pfn.h>
 #include <asm/page.h>
 #include <asm/sections.h>
 
@@ -28,8 +29,6 @@
 #include <asm/sn/sn_private.h>
 
 
-#define PFN_UP(x)		(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-
 #define SLOT_PFNSHIFT           (SLOT_SHIFT - PAGE_SHIFT)
 #define PFN_NASIDSHFT           (NASID_SHFT - PAGE_SHIFT)
 
diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c
index 0c94800..ab9d9ce 100644
--- a/arch/mips/sgi-ip32/ip32-reset.c
+++ b/arch/mips/sgi-ip32/ip32-reset.c
@@ -193,7 +193,7 @@
 
 	init_timer(&blink_timer);
 	blink_timer.function = blink_timeout;
-	notifier_chain_register(&panic_notifier_list, &panic_block);
+	atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
 
 	request_irq(MACEISA_RTC_IRQ, ip32_rtc_int, 0, "rtc", NULL);
 
diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c
index 2f50c79..a2dd8ae 100644
--- a/arch/mips/sgi-ip32/ip32-setup.c
+++ b/arch/mips/sgi-ip32/ip32-setup.c
@@ -91,8 +91,8 @@
 {
 	board_be_init = ip32_be_init;
 
-	rtc_get_time = mc146818_get_cmos_time;
-	rtc_set_mmss = mc146818_set_rtc_mmss;
+	rtc_mips_get_time = mc146818_get_cmos_time;
+	rtc_mips_set_mmss = mc146818_set_rtc_mmss;
 
 	board_time_init = ip32_time_init;
 	board_timer_setup = ip32_timer_setup;
diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c
index b661d24..4b5f74f 100644
--- a/arch/mips/sibyte/swarm/setup.c
+++ b/arch/mips/sibyte/swarm/setup.c
@@ -121,14 +121,14 @@
 
 	if (xicor_probe()) {
 		printk("swarm setup: Xicor 1241 RTC detected.\n");
-		rtc_get_time = xicor_get_time;
-		rtc_set_time = xicor_set_time;
+		rtc_mips_get_time = xicor_get_time;
+		rtc_mips_set_time = xicor_set_time;
 	}
 
 	if (m41t81_probe()) {
 		printk("swarm setup: M41T81 RTC detected.\n");
-		rtc_get_time = m41t81_get_time;
-		rtc_set_time = m41t81_set_time;
+		rtc_mips_get_time = m41t81_get_time;
+		rtc_mips_set_time = m41t81_set_time;
 	}
 
 	printk("This kernel optimized for "
diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c
index 1141fcd..01ba6c5 100644
--- a/arch/mips/sni/setup.c
+++ b/arch/mips/sni/setup.c
@@ -164,8 +164,8 @@
 
 static inline void sni_pcimt_time_init(void)
 {
-	rtc_get_time = mc146818_get_cmos_time;
-	rtc_set_time = mc146818_set_rtc_mmss;
+	rtc_mips_get_time = mc146818_get_cmos_time;
+	rtc_mips_set_time = mc146818_set_rtc_mmss;
 }
 
 void __init plat_setup(void)
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
index 2ad6401..6dcf077 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
@@ -1036,8 +1036,8 @@
 
 #ifdef CONFIG_RTC_DS1742
 
-	rtc_get_time = rtc_ds1742_get_time;
-	rtc_set_time = rtc_ds1742_set_time;
+	rtc_mips_get_time = rtc_ds1742_get_time;
+	rtc_mips_set_time = rtc_ds1742_set_time;
 
 	TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_TIME_INIT,
 				       ":rtc_ds1742_init()-\n");
diff --git a/arch/mips/tx4938/common/rtc_rx5c348.c b/arch/mips/tx4938/common/rtc_rx5c348.c
index d249edb..07f782f 100644
--- a/arch/mips/tx4938/common/rtc_rx5c348.c
+++ b/arch/mips/tx4938/common/rtc_rx5c348.c
@@ -14,6 +14,7 @@
 #include <linux/string.h>
 #include <linux/rtc.h>
 #include <linux/time.h>
+#include <linux/bcd.h>
 #include <asm/time.h>
 #include <asm/tx4938/spi.h>
 
@@ -77,17 +78,6 @@
 			   inbufs, incounts, outbufs, outcounts, 0);
 }
 
-/*
- * Conversion between binary and BCD.
- */
-#ifndef BCD_TO_BIN
-#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
-#endif
-
-#ifndef BIN_TO_BCD
-#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
-#endif
-
 /* RTC-dependent code for time.c */
 
 static int
@@ -197,6 +187,6 @@
 		srtc_24h = 1;
 
 	/* set the function pointers */
-	rtc_get_time = rtc_rx5c348_get_time;
-	rtc_set_time = rtc_rx5c348_set_time;
+	rtc_mips_get_time = rtc_rx5c348_get_time;
+	rtc_mips_set_time = rtc_rx5c348_set_time;
 }
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index eca33cf..2fdf219 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -25,6 +25,14 @@
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
@@ -169,14 +177,10 @@
 	def_bool y
 	depends on ARCH_DISCONTIGMEM_ENABLE
 
+source "kernel/Kconfig.preempt"
 source "kernel/Kconfig.hz"
 source "mm/Kconfig"
 
-config PREEMPT
-	bool
-#	bool "Preemptible Kernel"
-	default n
-
 config COMPAT
 	def_bool y
 	depends on 64BIT
diff --git a/arch/parisc/configs/712_defconfig b/arch/parisc/configs/712_defconfig
index 3e013f5..41fd069 100644
--- a/arch/parisc/configs/712_defconfig
+++ b/arch/parisc/configs/712_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc5-pa1
-# Fri Oct 21 23:04:34 2005
+# Linux kernel version: 2.6.16-pa6
+# Sun Mar 26 19:59:51 2006
 #
 CONFIG_PARISC=y
 CONFIG_MMU=y
@@ -10,14 +10,11 @@
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_ARCH_MAY_HAVE_PC_FDC=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
@@ -32,17 +29,18 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
@@ -51,8 +49,10 @@
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -66,6 +66,23 @@
 CONFIG_KMOD=y
 
 #
+# Block layer
+#
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
 # Processor type and features
 #
 # CONFIG_PA7000 is not set
@@ -75,6 +92,10 @@
 # CONFIG_PA8X00 is not set
 CONFIG_PA11=y
 # CONFIG_SMP is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
@@ -86,7 +107,7 @@
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_PREEMPT is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
 # CONFIG_HPUX is not set
 
 #
@@ -130,6 +151,7 @@
 #
 # Networking options
 #
+# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
@@ -165,7 +187,12 @@
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
 # CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NETFILTER_XTABLES is not set
 
 #
 # IP: Netfilter Configuration
@@ -182,64 +209,6 @@
 CONFIG_IP_NF_AMANDA=m
 # CONFIG_IP_NF_PPTP is not set
 CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_RECENT=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_OWNER=m
-# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
-# CONFIG_IP_NF_MATCH_REALM is not set
-CONFIG_IP_NF_MATCH_SCTP=m
-# CONFIG_IP_NF_MATCH_DCCP is not set
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
-CONFIG_IP_NF_MATCH_HASHLIMIT=m
-# CONFIG_IP_NF_MATCH_STRING is not set
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-# CONFIG_IP_NF_TARGET_NFQUEUE is not set
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_SAME=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_NAT_TFTP=m
-CONFIG_IP_NF_NAT_AMANDA=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_TOS=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
-# CONFIG_IP_NF_TARGET_TTL is not set
-CONFIG_IP_NF_TARGET_CONNMARK=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
 
 #
 # DCCP Configuration (EXPERIMENTAL)
@@ -250,6 +219,11 @@
 # 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
 # CONFIG_VLAN_8021Q is not set
@@ -263,8 +237,11 @@
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
 # CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -304,6 +281,7 @@
 CONFIG_PARPORT_PC=m
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_NOT_PC=y
 CONFIG_PARPORT_GSC=y
 # CONFIG_PARPORT_1284 is not set
 
@@ -314,7 +292,6 @@
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
@@ -325,14 +302,6 @@
 CONFIG_BLK_DEV_RAM_SIZE=6144
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_ATA_OVER_ETH=m
 
 #
@@ -376,6 +345,7 @@
 #
 # SCSI low-level drivers
 #
+# CONFIG_ISCSI_TCP is not set
 # CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_PPA is not set
 # CONFIG_SCSI_IMM is not set
@@ -407,7 +377,6 @@
 #
 # IEEE 1394 (FireWire) support
 #
-# CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
@@ -471,6 +440,7 @@
 CONFIG_PPP_SYNC_TTY=m
 CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
 CONFIG_PPPOE=m
 # CONFIG_SLIP is not set
 # CONFIG_SHAPER is not set
@@ -516,8 +486,8 @@
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_KEYBOARD_HIL_OLD=y
-# CONFIG_KEYBOARD_HIL is not set
+# CONFIG_KEYBOARD_HIL_OLD is not set
+CONFIG_KEYBOARD_HIL=y
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
 CONFIG_MOUSE_SERIAL=m
@@ -554,6 +524,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=17
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
@@ -598,6 +569,8 @@
 #
 # TPM devices
 #
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
 
 #
 # I2C support
@@ -605,6 +578,12 @@
 # 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
@@ -640,7 +619,6 @@
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_SOFT_CURSOR=y
 # CONFIG_FB_MACMODES is not set
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
@@ -655,6 +633,7 @@
 CONFIG_DUMMY_CONSOLE_COLUMNS=128
 CONFIG_DUMMY_CONSOLE_ROWS=48
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_STI_CONSOLE=y
 CONFIG_FONTS=y
 CONFIG_FONT_8x8=y
@@ -695,6 +674,8 @@
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
 CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 
@@ -724,6 +705,10 @@
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -736,10 +721,9 @@
 #
 # InfiniBand support
 #
-# CONFIG_INFINIBAND is not set
 
 #
-# SN Devices
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
 #
 
 #
@@ -765,6 +749,7 @@
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -800,10 +785,10 @@
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
-# CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -821,7 +806,6 @@
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_SYSV_FS is not set
 CONFIG_UFS_FS=m
-# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
@@ -917,18 +901,22 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_IOREMAP is not set
 # CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_RODATA=y
 
 #
 # Security options
diff --git a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig
index 959ad3c..f3b812f 100644
--- a/arch/parisc/configs/a500_defconfig
+++ b/arch/parisc/configs/a500_defconfig
@@ -1031,8 +1031,8 @@
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ASCII is not set
-# CONFIG_NLS_ISO8859_1 is not set
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
diff --git a/arch/parisc/configs/b180_defconfig b/arch/parisc/configs/b180_defconfig
index 37e9824..3509361 100644
--- a/arch/parisc/configs/b180_defconfig
+++ b/arch/parisc/configs/b180_defconfig
@@ -939,10 +939,10 @@
 #
 CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
+CONFIG_NLS_CODEPAGE_850=m
 # CONFIG_NLS_CODEPAGE_852 is not set
 # CONFIG_NLS_CODEPAGE_855 is not set
 # CONFIG_NLS_CODEPAGE_857 is not set
@@ -962,8 +962,8 @@
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ASCII is not set
-# CONFIG_NLS_ISO8859_1 is not set
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -973,10 +973,10 @@
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_13 is not set
 # CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_ISO8859_15=m
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_UTF8=m
 
 #
 # Kernel hacking
diff --git a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig
index 0b1c8c1..782906b 100644
--- a/arch/parisc/configs/c3000_defconfig
+++ b/arch/parisc/configs/c3000_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc5-pa1
-# Fri Oct 21 23:06:31 2005
+# Linux kernel version: 2.6.16-pa6
+# Sun Mar 26 20:03:29 2006
 #
 CONFIG_PARISC=y
 CONFIG_MMU=y
@@ -10,14 +10,11 @@
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_ARCH_MAY_HAVE_PC_FDC=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
@@ -32,28 +29,30 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -67,6 +66,23 @@
 CONFIG_KMOD=y
 
 #
+# Block layer
+#
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
 # Processor type and features
 #
 # CONFIG_PA7000 is not set
@@ -78,6 +94,10 @@
 CONFIG_PREFETCH=y
 # CONFIG_64BIT is not set
 # CONFIG_SMP is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
@@ -89,7 +109,7 @@
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_PREEMPT is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_HPUX is not set
 
 #
@@ -135,6 +155,7 @@
 #
 # Networking options
 #
+# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
@@ -175,7 +196,12 @@
 CONFIG_IPV6_TUNNEL=m
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_DEBUG=y
+
+#
+# Core Netfilter Configuration
+#
 # CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NETFILTER_XTABLES is not set
 
 #
 # IP: Netfilter Configuration
@@ -192,87 +218,11 @@
 CONFIG_IP_NF_AMANDA=m
 # CONFIG_IP_NF_PPTP is not set
 CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_RECENT=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_OWNER=m
-# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
-# CONFIG_IP_NF_MATCH_REALM is not set
-# CONFIG_IP_NF_MATCH_SCTP is not set
-# CONFIG_IP_NF_MATCH_DCCP is not set
-# CONFIG_IP_NF_MATCH_COMMENT is not set
-# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
-# CONFIG_IP_NF_MATCH_STRING is not set
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-# CONFIG_IP_NF_TARGET_NFQUEUE is not set
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_SAME=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_NAT_TFTP=m
-CONFIG_IP_NF_NAT_AMANDA=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_TOS=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
-# CONFIG_IP_NF_TARGET_TTL is not set
-# CONFIG_IP_NF_RAW is not set
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
 
 #
 # IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 # CONFIG_IP6_NF_QUEUE is not set
-CONFIG_IP6_NF_IPTABLES=m
-# CONFIG_IP6_NF_MATCH_LIMIT is not set
-CONFIG_IP6_NF_MATCH_MAC=m
-CONFIG_IP6_NF_MATCH_RT=m
-# CONFIG_IP6_NF_MATCH_OPTS is not set
-# CONFIG_IP6_NF_MATCH_FRAG is not set
-# CONFIG_IP6_NF_MATCH_HL is not set
-# CONFIG_IP6_NF_MATCH_MULTIPORT is not set
-CONFIG_IP6_NF_MATCH_OWNER=m
-# CONFIG_IP6_NF_MATCH_MARK is not set
-CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-# CONFIG_IP6_NF_MATCH_AHESP is not set
-CONFIG_IP6_NF_MATCH_LENGTH=m
-# CONFIG_IP6_NF_MATCH_EUI64 is not set
-CONFIG_IP6_NF_FILTER=m
-CONFIG_IP6_NF_TARGET_LOG=m
-CONFIG_IP6_NF_TARGET_REJECT=m
-# CONFIG_IP6_NF_TARGET_NFQUEUE is not set
-CONFIG_IP6_NF_MANGLE=m
-# CONFIG_IP6_NF_TARGET_MARK is not set
-# CONFIG_IP6_NF_TARGET_HL is not set
-# CONFIG_IP6_NF_RAW is not set
 
 #
 # DCCP Configuration (EXPERIMENTAL)
@@ -283,6 +233,11 @@
 # 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
 # CONFIG_VLAN_8021Q is not set
@@ -295,8 +250,11 @@
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
 # CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -341,7 +299,6 @@
 #
 # Block devices
 #
-# 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
@@ -355,14 +312,6 @@
 # CONFIG_BLK_DEV_RAM is not set
 CONFIG_BLK_DEV_RAM_COUNT=16
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 # CONFIG_ATA_OVER_ETH is not set
 
 #
@@ -458,6 +407,7 @@
 #
 # SCSI low-level drivers
 #
+# CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
@@ -466,7 +416,6 @@
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
 # CONFIG_MEGARAID_SAS is not set
@@ -476,18 +425,18 @@
 CONFIG_SCSI_ATA_PIIX=m
 # CONFIG_SCSI_SATA_MV is not set
 # CONFIG_SCSI_SATA_NV is not set
-CONFIG_SCSI_SATA_PROMISE=m
+# CONFIG_SCSI_PDC_ADMA is not set
 # CONFIG_SCSI_SATA_QSTOR is not set
+CONFIG_SCSI_SATA_PROMISE=m
 # CONFIG_SCSI_SATA_SX4 is not set
 CONFIG_SCSI_SATA_SIL=m
+# CONFIG_SCSI_SATA_SIL24 is not set
 # CONFIG_SCSI_SATA_SIS is not set
 # CONFIG_SCSI_SATA_ULI is not set
 CONFIG_SCSI_SATA_VIA=m
 # CONFIG_SCSI_SATA_VITESSE is not set
 CONFIG_SCSI_SATA_INTEL_COMBINED=y
-# CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_INITIO is not set
@@ -496,18 +445,11 @@
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+CONFIG_SCSI_SYM53C8XX_MMIO=y
 # CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -633,6 +575,7 @@
 # CONFIG_R8169 is not set
 # 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=m
@@ -668,6 +611,7 @@
 CONFIG_PPP_SYNC_TTY=m
 CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
 CONFIG_PPPOE=m
 # CONFIG_SLIP is not set
 # CONFIG_NET_FC is not set
@@ -744,6 +688,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=13
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
@@ -753,7 +698,6 @@
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_MUX is not set
 # CONFIG_PDC_CONSOLE is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
@@ -788,6 +732,7 @@
 # TPM devices
 #
 # CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
 
 #
 # I2C support
@@ -795,6 +740,12 @@
 # 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
@@ -830,7 +781,6 @@
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_SOFT_CURSOR=y
 # CONFIG_FB_MACMODES is not set
 # CONFIG_FB_MODE_HELPERS is not set
 # CONFIG_FB_TILEBLITTING is not set
@@ -840,6 +790,7 @@
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
 CONFIG_FB_STI=y
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
@@ -853,10 +804,7 @@
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_PM3 is not set
-# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -866,6 +814,7 @@
 CONFIG_DUMMY_CONSOLE_COLUMNS=160
 CONFIG_DUMMY_CONSOLE_ROWS=64
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_STI_CONSOLE=y
 # CONFIG_FONTS is not set
 CONFIG_FONT_8x8=y
@@ -898,23 +847,27 @@
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
 CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 
 #
 # Generic devices
 #
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_AC97_BUS=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_MTPAV is not set
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_MPU401 is not set
-CONFIG_SND_AC97_CODEC=y
-CONFIG_SND_AC97_BUS=y
 
 #
 # PCI devices
 #
+CONFIG_SND_AD1889=y
+# CONFIG_SND_AD1889_OPL3 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
 # CONFIG_SND_ATIIXP_MODEM is not set
@@ -923,39 +876,38 @@
 # CONFIG_SND_AU8830 is not set
 # CONFIG_SND_AZT3328 is not set
 # CONFIG_SND_BT87X is not set
-# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_YMFPCI is not set
-CONFIG_SND_AD1889=y
-# CONFIG_SND_AD1889_OPL3 is not set
-# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_ENS1370 is not set
 # CONFIG_SND_ENS1371 is not set
 # CONFIG_SND_ES1938 is not set
 # CONFIG_SND_ES1968 is not set
-# CONFIG_SND_MAESTRO3 is not set
 # CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
 # CONFIG_SND_INTEL8X0 is not set
 # CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
 # CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
 # CONFIG_SND_VIA82XX is not set
 # CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
-# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_YMFPCI is not set
 
 #
 # USB devices
@@ -998,12 +950,15 @@
 # USB Device Class drivers
 #
 # CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
-# CONFIG_USB_BLUETOOTH_TTY is not set
 # CONFIG_USB_ACM is not set
 CONFIG_USB_PRINTER=m
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
 #
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -1015,12 +970,15 @@
 CONFIG_USB_STORAGE_SDDR09=y
 CONFIG_USB_STORAGE_SDDR55=y
 CONFIG_USB_STORAGE_JUMPSHOT=y
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 CONFIG_USB_HIDDEV=y
 # CONFIG_USB_AIPTEK is not set
@@ -1034,6 +992,7 @@
 # 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
 
@@ -1108,7 +1067,7 @@
 # CONFIG_INFINIBAND is not set
 
 #
-# SN Devices
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
 #
 
 #
@@ -1130,6 +1089,7 @@
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -1164,10 +1124,10 @@
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
-# CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1225,10 +1185,10 @@
 #
 CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
+CONFIG_NLS_CODEPAGE_850=m
 # CONFIG_NLS_CODEPAGE_852 is not set
 # CONFIG_NLS_CODEPAGE_855 is not set
 # CONFIG_NLS_CODEPAGE_857 is not set
@@ -1248,8 +1208,8 @@
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ASCII is not set
-# CONFIG_NLS_ISO8859_1 is not set
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -1259,10 +1219,10 @@
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_13 is not set
 # CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_ISO8859_15=m
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_UTF8=m
 
 #
 # Profiling support
@@ -1274,18 +1234,22 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_IOREMAP is not set
 # CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_RODATA=y
 
 #
 # Security options
diff --git a/arch/parisc/defconfig b/arch/parisc/defconfig
index f38a462..59f7bc3 100644
--- a/arch/parisc/defconfig
+++ b/arch/parisc/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc5-pa1
-# Fri Oct 21 23:01:33 2005
+# Linux kernel version: 2.6.16-pa6
+# Sun Mar 26 19:50:07 2006
 #
 CONFIG_PARISC=y
 CONFIG_MMU=y
@@ -15,7 +15,6 @@
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
@@ -30,17 +29,18 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
@@ -49,8 +49,10 @@
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -58,6 +60,23 @@
 # CONFIG_MODULES is not set
 
 #
+# Block layer
+#
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
 # Processor type and features
 #
 CONFIG_PA7000=y
@@ -67,6 +86,10 @@
 # CONFIG_PA8X00 is not set
 CONFIG_PA11=y
 # CONFIG_SMP is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
@@ -78,7 +101,7 @@
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_PREEMPT is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
 # CONFIG_HPUX is not set
 
 #
@@ -132,6 +155,7 @@
 #
 # Networking options
 #
+# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
@@ -174,6 +198,11 @@
 # 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
 # CONFIG_VLAN_8021Q is not set
@@ -186,8 +215,11 @@
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
 # CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -228,6 +260,7 @@
 # CONFIG_PARPORT_SERIAL is not set
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_NOT_PC=y
 CONFIG_PARPORT_GSC=y
 # CONFIG_PARPORT_1284 is not set
 
@@ -254,14 +287,6 @@
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 # CONFIG_ATA_OVER_ETH is not set
 
 #
@@ -305,6 +330,7 @@
 #
 # SCSI low-level drivers
 #
+# CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
@@ -331,7 +357,7 @@
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+CONFIG_SCSI_SYM53C8XX_MMIO=y
 # CONFIG_SCSI_IPR is not set
 CONFIG_SCSI_ZALON=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
@@ -340,13 +366,7 @@
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_DC395x is not set
@@ -471,6 +491,7 @@
 # CONFIG_R8169 is not set
 # 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
@@ -562,13 +583,13 @@
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_KEYBOARD_HIL_OLD=y
+# CONFIG_KEYBOARD_HIL_OLD is not set
 CONFIG_KEYBOARD_HIL=y
 CONFIG_INPUT_MOUSE=y
 # CONFIG_MOUSE_PS2 is not set
 # CONFIG_MOUSE_SERIAL is not set
 # CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_MOUSE_HIL is not set
+CONFIG_MOUSE_HIL=y
 CONFIG_INPUT_JOYSTICK=y
 # CONFIG_JOYSTICK_ANALOG is not set
 # CONFIG_JOYSTICK_A3D is not set
@@ -628,6 +649,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=13
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
@@ -675,6 +697,7 @@
 # TPM devices
 #
 # CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
 
 #
 # I2C support
@@ -682,6 +705,12 @@
 # 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
@@ -691,6 +720,7 @@
 #
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_F71805F is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -718,7 +748,6 @@
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_SOFT_CURSOR=y
 # CONFIG_FB_MACMODES is not set
 # CONFIG_FB_MODE_HELPERS is not set
 # CONFIG_FB_TILEBLITTING is not set
@@ -728,6 +757,7 @@
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
 CONFIG_FB_STI=y
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
@@ -741,9 +771,7 @@
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -753,15 +781,28 @@
 CONFIG_DUMMY_CONSOLE_COLUMNS=160
 CONFIG_DUMMY_CONSOLE_ROWS=64
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_STI_CONSOLE=y
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
 CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
 
 #
 # Logo configuration
 #
-# CONFIG_LOGO is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_LOGO_PARISC_CLUT224=y
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
@@ -781,23 +822,27 @@
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
 CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 
 #
 # Generic devices
 #
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_AC97_BUS=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_MTPAV is not set
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_MPU401 is not set
-CONFIG_SND_AC97_CODEC=y
-CONFIG_SND_AC97_BUS=y
 
 #
 # PCI devices
 #
+CONFIG_SND_AD1889=y
+# CONFIG_SND_AD1889_OPL3 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
 # CONFIG_SND_ATIIXP_MODEM is not set
@@ -806,39 +851,38 @@
 # CONFIG_SND_AU8830 is not set
 # CONFIG_SND_AZT3328 is not set
 # CONFIG_SND_BT87X is not set
-# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_YMFPCI is not set
-CONFIG_SND_AD1889=y
-# CONFIG_SND_AD1889_OPL3 is not set
-# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_ENS1370 is not set
 # CONFIG_SND_ENS1371 is not set
 # CONFIG_SND_ES1938 is not set
 # CONFIG_SND_ES1968 is not set
-# CONFIG_SND_MAESTRO3 is not set
 # CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
 # CONFIG_SND_INTEL8X0 is not set
 # CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
 # CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
 # CONFIG_SND_VIA82XX is not set
 # CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
-# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_YMFPCI is not set
 
 #
 # USB devices
@@ -888,14 +932,18 @@
 # USB Device Class drivers
 #
 # CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
-# CONFIG_USB_BLUETOOTH_TTY is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
 #
 # CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
@@ -918,6 +966,7 @@
 # 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
 
@@ -994,7 +1043,7 @@
 # CONFIG_INFINIBAND is not set
 
 #
-# SN Devices
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
 #
 
 #
@@ -1011,6 +1060,7 @@
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -1045,6 +1095,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1151,18 +1202,22 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_IOREMAP is not set
 # CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_RODATA=y
 
 #
 # Security options
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index d8a4ca0..360b739 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -89,7 +89,7 @@
 	if (pfn_valid(page_to_pfn(page)) && page_mapping(page) &&
 	    test_bit(PG_dcache_dirty, &page->flags)) {
 
-		flush_kernel_dcache_page(page_address(page));
+		flush_kernel_dcache_page(page);
 		clear_bit(PG_dcache_dirty, &page->flags);
 	}
 }
@@ -278,7 +278,7 @@
 		return;
 	}
 
-	flush_kernel_dcache_page(page_address(page));
+	flush_kernel_dcache_page(page);
 
 	if (!mapping)
 		return;
@@ -317,7 +317,7 @@
 
 /* Defined in arch/parisc/kernel/pacache.S */
 EXPORT_SYMBOL(flush_kernel_dcache_range_asm);
-EXPORT_SYMBOL(flush_kernel_dcache_page);
+EXPORT_SYMBOL(flush_kernel_dcache_page_asm);
 EXPORT_SYMBOL(flush_data_cache_local);
 EXPORT_SYMBOL(flush_kernel_icache_range_asm);
 
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 9af4b22..7c95d76 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -563,10 +563,10 @@
 	extrd,u,*= 	\pte,_PAGE_GATEWAY_BIT+32,1,%r0
 	depd		%r0,11,2,\prot	/* If Gateway, Set PL2 to 0 */
 
-	/* Get rid of prot bits and convert to page addr for iitlbt */
+	/* Get rid of prot bits and convert to page addr for iitlbt and idtlbt */
 
 	depd		%r0,63,PAGE_SHIFT,\pte
-	extrd,u		\pte,56,32,\pte
+	extrd,s		\pte,(63-PAGE_SHIFT)+(63-58),64-PAGE_SHIFT,\pte
 	.endm
 
 	/* Identical macro to make_insert_tlb above, except it
@@ -584,7 +584,7 @@
 
 	/* Get rid of prot bits and convert to page addr for iitlba */
 
-	depi		0,31,12,\pte
+	depi		0,31,PAGE_SHIFT,\pte
 	extru		\pte,24,25,\pte
 
 	.endm
@@ -1014,14 +1014,21 @@
 	nop
 	nop
 
+#ifndef CONFIG_PREEMPT
+# define intr_do_preempt	intr_restore
+#endif /* !CONFIG_PREEMPT */
+
 	.import schedule,code
 intr_do_resched:
-	/* Only do reschedule if we are returning to user space */
+	/* Only call schedule on return to userspace. If we're returning
+	 * to kernel space, we may schedule if CONFIG_PREEMPT, otherwise
+	 * we jump back to intr_restore.
+	 */
 	LDREG	PT_IASQ0(%r16), %r20
-	CMPIB= 0,%r20,intr_restore /* backward */
+	CMPIB=	0, %r20, intr_do_preempt
 	nop
 	LDREG	PT_IASQ1(%r16), %r20
-	CMPIB= 0,%r20,intr_restore /* backward */
+	CMPIB=	0, %r20, intr_do_preempt
 	nop
 
 #ifdef CONFIG_64BIT
@@ -1037,6 +1044,32 @@
 #endif
 	ldo	R%intr_check_sig(%r2), %r2
 
+	/* preempt the current task on returning to kernel
+	 * mode from an interrupt, iff need_resched is set,
+	 * and preempt_count is 0. otherwise, we continue on
+	 * our merry way back to the current running task.
+	 */
+#ifdef CONFIG_PREEMPT
+	.import preempt_schedule_irq,code
+intr_do_preempt:
+	rsm	PSW_SM_I, %r0		/* disable interrupts */
+
+	/* current_thread_info()->preempt_count */
+	mfctl	%cr30, %r1
+	LDREG	TI_PRE_COUNT(%r1), %r19
+	CMPIB<>	0, %r19, intr_restore	/* if preempt_count > 0 */
+	nop				/* prev insn branched backwards */
+
+	/* check if we interrupted a critical path */
+	LDREG	PT_PSW(%r16), %r20
+	bb,<,n	%r20, 31 - PSW_SM_I, intr_restore
+	nop
+
+	BL	preempt_schedule_irq, %r2
+	nop
+
+	b	intr_restore		/* ssm PSW_SM_I done by intr_restore */
+#endif /* CONFIG_PREEMPT */
 
 	.import do_signal,code
 intr_do_signal:
diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S
index 9534ee1..7a4f07e 100644
--- a/arch/parisc/kernel/pacache.S
+++ b/arch/parisc/kernel/pacache.S
@@ -621,9 +621,9 @@
 
 	.procend
 
-	.export flush_kernel_dcache_page
+	.export flush_kernel_dcache_page_asm
 
-flush_kernel_dcache_page:
+flush_kernel_dcache_page_asm:
 	.proc
 	.callinfo NO_CALLS
 	.entry
diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
index 1d00c36..47ca5c0 100644
--- a/arch/parisc/kernel/parisc_ksyms.c
+++ b/arch/parisc/kernel/parisc_ksyms.c
@@ -30,22 +30,7 @@
 #include <linux/syscalls.h>
 
 #include <linux/string.h>
-EXPORT_SYMBOL(memchr);
-EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(memscan);
 EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(strcat);
-EXPORT_SYMBOL(strchr);
-EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strcpy);
-EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strncat);
-EXPORT_SYMBOL(strncmp);
-EXPORT_SYMBOL(strncpy);
-EXPORT_SYMBOL(strnlen);
-EXPORT_SYMBOL(strrchr);
-EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strpbrk);
 
 #include <asm/atomic.h>
@@ -82,16 +67,12 @@
 #endif
 
 #include <asm/io.h>
-EXPORT_SYMBOL(__ioremap);
-EXPORT_SYMBOL(iounmap);
 EXPORT_SYMBOL(memcpy_toio);
 EXPORT_SYMBOL(memcpy_fromio);
 EXPORT_SYMBOL(memset_io);
 
 #include <asm/unistd.h>
-EXPORT_SYMBOL(sys_open);
 EXPORT_SYMBOL(sys_lseek);
-EXPORT_SYMBOL(sys_read);
 EXPORT_SYMBOL(sys_write);
 
 #include <asm/semaphore.h>
diff --git a/arch/parisc/kernel/pdc_chassis.c b/arch/parisc/kernel/pdc_chassis.c
index 2a01fe1..a45e2e2 100644
--- a/arch/parisc/kernel/pdc_chassis.c
+++ b/arch/parisc/kernel/pdc_chassis.c
@@ -5,9 +5,8 @@
  *    Copyright (C) 2002-2004 Thibaut VARENE <varenet@parisc-linux.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.
+ *    it under the terms of the GNU General Public License, version 2, as
+ *    published by the Free Software Foundation.
  *
  *    This program is distributed in the hope that it will be useful,
  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -150,7 +149,8 @@
 
 		if (handle) {
 			/* initialize panic notifier chain */
-			notifier_chain_register(&panic_notifier_list, &pdc_chassis_panic_block);
+			atomic_notifier_chain_register(&panic_notifier_list,
+					&pdc_chassis_panic_block);
 
 			/* initialize reboot notifier chain */
 			register_reboot_notifier(&pdc_chassis_reboot_block);
diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c
index 53f861c..ac8ee20 100644
--- a/arch/parisc/kernel/perf.c
+++ b/arch/parisc/kernel/perf.c
@@ -805,7 +805,7 @@
 		return -1;
 	}
 
-	runway = ioremap(cpu_device->hpa.start, 4096);
+	runway = ioremap_nocache(cpu_device->hpa.start, 4096);
 
 	/* Merge intrigue bits into Runway STATUS 0 */
 	tmp64 = __raw_readq(runway + RUNWAY_STATUS) & 0xffecfffffffffffful;
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
index 6135690..d286f68 100644
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -21,7 +21,6 @@
 #include <linux/times.h>
 #include <linux/utsname.h>
 #include <linux/time.h>
-#include <linux/timex.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/sem.h>
@@ -567,63 +566,6 @@
 }
 
 
-struct timex32 {
-	unsigned int modes;	/* mode selector */
-	int offset;		/* time offset (usec) */
-	int freq;		/* frequency offset (scaled ppm) */
-	int maxerror;		/* maximum error (usec) */
-	int esterror;		/* estimated error (usec) */
-	int status;		/* clock command/status */
-	int constant;		/* pll time constant */
-	int precision;		/* clock precision (usec) (read only) */
-	int tolerance;		/* clock frequency tolerance (ppm)
-				 * (read only)
-				 */
-	struct compat_timeval time;	/* (read only) */
-	int tick;		/* (modified) usecs between clock ticks */
-
-	int ppsfreq;           /* pps frequency (scaled ppm) (ro) */
-	int jitter;            /* pps jitter (us) (ro) */
-	int shift;              /* interval duration (s) (shift) (ro) */
-	int stabil;            /* pps stability (scaled ppm) (ro) */
-	int jitcnt;            /* jitter limit exceeded (ro) */
-	int calcnt;            /* calibration intervals (ro) */
-	int errcnt;            /* calibration errors (ro) */
-	int stbcnt;            /* stability limit exceeded (ro) */
-
-	int  :32; int  :32; int  :32; int  :32;
-	int  :32; int  :32; int  :32; int  :32;
-	int  :32; int  :32; int  :32; int  :32;
-};
-
-asmlinkage long sys32_adjtimex(struct timex32 __user *txc_p32)
-{
-	struct timex txc;
-	struct timex32 t32;
-	int ret;
-	extern int do_adjtimex(struct timex *txc);
-
-	if(copy_from_user(&t32, txc_p32, sizeof(struct timex32)))
-		return -EFAULT;
-#undef CP
-#define CP(x) txc.x = t32.x
-	CP(modes); CP(offset); CP(freq); CP(maxerror); CP(esterror);
-	CP(status); CP(constant); CP(precision); CP(tolerance);
-	CP(time.tv_sec); CP(time.tv_usec); CP(tick); CP(ppsfreq); CP(jitter);
-	CP(shift); CP(stabil); CP(jitcnt); CP(calcnt); CP(errcnt);
-	CP(stbcnt);
-	ret = do_adjtimex(&txc);
-#undef CP
-#define CP(x) t32.x = txc.x
-	CP(modes); CP(offset); CP(freq); CP(maxerror); CP(esterror);
-	CP(status); CP(constant); CP(precision); CP(tolerance);
-	CP(time.tv_sec); CP(time.tv_usec); CP(tick); CP(ppsfreq); CP(jitter);
-	CP(shift); CP(stabil); CP(jitcnt); CP(calcnt); CP(errcnt);
-	CP(stbcnt);
-	return copy_to_user(txc_p32, &t32, sizeof(struct timex32)) ? -EFAULT : ret;
-}
-
-
 struct sysinfo32 {
 	s32 uptime;
 	u32 loads[3];
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 71011ea..bbeeb61 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -207,7 +207,7 @@
 	/* struct sockaddr... */
 	ENTRY_SAME(recvfrom)
 	/* struct timex contains longs */
-	ENTRY_DIFF(adjtimex)
+	ENTRY_COMP(adjtimex)
 	ENTRY_SAME(mprotect)		/* 125 */
 	/* old_sigset_t forced to 32 bits.  Beware glibc sigset_t */
 	ENTRY_COMP(sigprocmask)
@@ -287,7 +287,7 @@
 	ENTRY_SAME(chown)		/* 180 */
 	/* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */
 	ENTRY_COMP(setsockopt)
-	ENTRY_SAME(getsockopt)
+	ENTRY_COMP(getsockopt)
 	ENTRY_COMP(sendmsg)
 	ENTRY_COMP(recvmsg)
 	ENTRY_SAME(semop)		/* 185 */
diff --git a/arch/parisc/lib/iomap.c b/arch/parisc/lib/iomap.c
index 01bec8f..f4a8116 100644
--- a/arch/parisc/lib/iomap.c
+++ b/arch/parisc/lib/iomap.c
@@ -263,11 +263,7 @@
 
 const struct iomap_ops *iomap_ops[8] = {
 	[0] = &ioport_ops,
-#ifdef CONFIG_DEBUG_IOREMAP
-	[6] = &iomem_ops,
-#else
 	[7] = &iomem_ops
-#endif
 };
 
 
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index 852eda3..3796be6 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -1013,9 +1013,9 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-#if 0
-	if (start < end)
-		printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+	if (start >= end)
+		return;
+	printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 	for (; start < end; start += PAGE_SIZE) {
 		ClearPageReserved(virt_to_page(start));
 		init_page_count(virt_to_page(start));
@@ -1023,6 +1023,5 @@
 		num_physpages++;
 		totalram_pages++;
 	}
-#endif
 }
 #endif
diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c
index edd9a95..0db1281 100644
--- a/arch/parisc/mm/ioremap.c
+++ b/arch/parisc/mm/ioremap.c
@@ -72,7 +72,6 @@
 	return 0;
 }
 
-#if USE_HPPA_IOREMAP
 static int 
 remap_area_pages(unsigned long address, unsigned long phys_addr,
 		 unsigned long size, unsigned long flags)
@@ -114,31 +113,6 @@
 
 	return error;
 }
-#endif /* USE_HPPA_IOREMAP */
-
-#ifdef CONFIG_DEBUG_IOREMAP
-static unsigned long last = 0;
-
-void gsc_bad_addr(unsigned long addr)
-{
-	if (time_after(jiffies, last + HZ*10)) {
-		printk("gsc_foo() called with bad address 0x%lx\n", addr);
-		dump_stack();
-		last = jiffies;
-	}
-}
-EXPORT_SYMBOL(gsc_bad_addr);
-
-void __raw_bad_addr(const volatile void __iomem *addr)
-{
-	if (time_after(jiffies, last + HZ*10)) {
-		printk("__raw_foo() called with bad address 0x%p\n", addr);
-		dump_stack();
-		last = jiffies;
-	}
-}
-EXPORT_SYMBOL(__raw_bad_addr);
-#endif
 
 /*
  * Generic mapping function (not visible outside):
@@ -154,26 +128,19 @@
  */
 void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
 {
-#if !(USE_HPPA_IOREMAP)
-
-	unsigned long end = phys_addr + size - 1;
-	/* Support EISA addresses */
-	if ((phys_addr >= 0x00080000 && end < 0x000fffff)
-			|| (phys_addr >= 0x00500000 && end < 0x03bfffff)) {
-		phys_addr |= 0xfc000000;
-	}
-
-#ifdef CONFIG_DEBUG_IOREMAP
-	return (void __iomem *)(phys_addr - (0x1UL << NYBBLE_SHIFT));
-#else
-	return (void __iomem *)phys_addr;
-#endif
-
-#else
 	void *addr;
 	struct vm_struct *area;
 	unsigned long offset, last_addr;
 
+#ifdef CONFIG_EISA
+	unsigned long end = phys_addr + size - 1;
+	/* Support EISA addresses */
+	if ((phys_addr >= 0x00080000 && end < 0x000fffff) ||
+	    (phys_addr >= 0x00500000 && end < 0x03bfffff)) {
+		phys_addr |= F_EXTEND(0xfc000000);
+	}
+#endif
+
 	/* Don't allow wraparound or zero size */
 	last_addr = phys_addr + size - 1;
 	if (!size || last_addr < phys_addr)
@@ -217,15 +184,12 @@
 	}
 
 	return (void __iomem *) (offset + (char *)addr);
-#endif
 }
+EXPORT_SYMBOL(__ioremap);
 
 void iounmap(void __iomem *addr)
 {
-#if !(USE_HPPA_IOREMAP)
-	return;
-#else
 	if (addr > high_memory)
 		return vfree((void *) (PAGE_MASK & (unsigned long __force) addr));
-#endif
 }
+EXPORT_SYMBOL(iounmap);
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index fae42da..2cdc35c 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -37,6 +37,10 @@
 	bool
 	default y
 
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
@@ -487,7 +491,7 @@
 	  If in doubt, say Y here.
 
 config TAU
-	bool "Thermal Management Support"
+	bool "On-chip CPU temperature sensor support"
 	depends on 6xx
 	help
 	  G3 and G4 processors have an on-chip temperature sensor called the
@@ -496,7 +500,7 @@
 	  on-die temperature in /proc/cpuinfo if the cpu supports it.
 
 	  Unfortunately, on some chip revisions, this sensor is very inaccurate
-	  and in some cases, does not work at all, so don't assume the cpu
+	  and in many cases, does not work at all, so don't assume the cpu
 	  temp is actually what /proc/cpuinfo says it is.
 
 config TAU_INT
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index 9254806..8d48e9e 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -110,11 +110,6 @@
 	depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \
 		PPC_GEN550 || PPC_MPC52xx
 
-config PPC_OCP
-	bool
-	depends on IBM_OCP || XILINX_OCP
-	default y
-
 choice
 	prompt "Early debugging (dangerous)"
 	bool
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 829e017..6ec84d3 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -129,13 +129,8 @@
 				   arch/powerpc/lib/ \
 				   arch/powerpc/sysdev/ \
 				   arch/powerpc/platforms/
-core-$(CONFIG_PPC32)		+= arch/ppc/kernel/
-core-$(CONFIG_MATH_EMULATION)	+= arch/ppc/math-emu/
+core-$(CONFIG_MATH_EMULATION)	+= arch/powerpc/math-emu/
 core-$(CONFIG_XMON)		+= arch/powerpc/xmon/
-core-$(CONFIG_APUS)		+= arch/ppc/amiga/
-drivers-$(CONFIG_8xx)		+= arch/ppc/8xx_io/
-drivers-$(CONFIG_4xx)		+= arch/ppc/4xx_io/
-drivers-$(CONFIG_CPM2)		+= arch/ppc/8260_io/
 
 drivers-$(CONFIG_OPROFILE)	+= arch/powerpc/oprofile/
 
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
index 3c2acab..fe22e54 100644
--- a/arch/powerpc/configs/cell_defconfig
+++ b/arch/powerpc/configs/cell_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16-rc6
-# Wed Mar 15 16:19:48 2006
+# Linux kernel version: 2.6.16
+# Thu Mar 23 20:48:09 2006
 #
 CONFIG_PPC64=y
 CONFIG_64BIT=y
@@ -30,6 +30,7 @@
 CONFIG_PPC_FPU=y
 CONFIG_ALTIVEC=y
 CONFIG_PPC_STD_MMU=y
+CONFIG_VIRT_CPU_ACCOUNTING=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=4
 
@@ -51,7 +52,8 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_IKCONFIG is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
 # CONFIG_CPUSETS is not set
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -85,7 +87,7 @@
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-# CONFIG_KMOD is not set
+CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
 
 #
@@ -130,7 +132,8 @@
 #
 # Cell Broadband Engine options
 #
-CONFIG_SPU_FS=y
+CONFIG_SPU_FS=m
+CONFIG_SPUFS_MMAP=y
 
 #
 # Kernel options
@@ -144,7 +147,7 @@
 # CONFIG_PREEMPT is not set
 CONFIG_PREEMPT_BKL=y
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=m
 CONFIG_FORCE_MAX_ZONEORDER=13
 # CONFIG_IOMMU_VMERGE is not set
 CONFIG_KEXEC=y
@@ -155,13 +158,16 @@
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_ARCH_SPARSEMEM_ENABLE=y
 CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
+# CONFIG_FLATMEM_MANUAL is not set
 # CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
 # CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_EXTREME=y
+# CONFIG_MEMORY_HOTPLUG is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
 # CONFIG_PPC_64K_PAGES is not set
 CONFIG_SCHED_SMT=y
 CONFIG_PROC_DEVICETREE=y
@@ -232,6 +238,7 @@
 # CONFIG_IP_VS is not set
 CONFIG_IPV6=y
 # CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
@@ -244,25 +251,7 @@
 # Core Netfilter Configuration
 #
 # CONFIG_NETFILTER_NETLINK is not set
-CONFIG_NETFILTER_XTABLES=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+# CONFIG_NETFILTER_XTABLES is not set
 
 #
 # IP: Netfilter Configuration
@@ -278,51 +267,13 @@
 CONFIG_IP_NF_TFTP=m
 CONFIG_IP_NF_AMANDA=m
 # CONFIG_IP_NF_PPTP is not set
+# CONFIG_IP_NF_H323 is not set
 CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_RECENT=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_HASHLIMIT=m
-CONFIG_IP_NF_MATCH_POLICY=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_SAME=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_NAT_TFTP=m
-CONFIG_IP_NF_NAT_AMANDA=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_TOS=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
 
 #
 # IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 # CONFIG_IP6_NF_QUEUE is not set
-# CONFIG_IP6_NF_IPTABLES is not set
 
 #
 # DCCP Configuration (EXPERIMENTAL)
@@ -355,7 +306,6 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
-CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -408,7 +358,7 @@
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
-CONFIG_BLK_DEV_NBD=y
+# CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
@@ -484,7 +434,23 @@
 #
 # Multi-device support (RAID and LVM)
 #
-# CONFIG_MD is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_RAID6 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
 
 #
 # Fusion MPT device support
@@ -548,7 +514,7 @@
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 CONFIG_E1000=m
-# CONFIG_E1000_NAPI is not set
+CONFIG_E1000_NAPI=y
 # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
@@ -560,7 +526,7 @@
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
-CONFIG_SPIDER_NET=y
+CONFIG_SPIDER_NET=m
 # CONFIG_MV643XX_ETH is not set
 
 #
@@ -678,6 +644,8 @@
 # CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_RTAS=y
 
 #
 # IPMI
@@ -694,14 +662,13 @@
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_WATCHDOG_RTAS is not set
+CONFIG_WATCHDOG_RTAS=y
 
 #
 # PCI-based Watchdog Cards
 #
 # CONFIG_PCIPCWATCHDOG is not set
 # CONFIG_WDTPCI is not set
-# CONFIG_RTC is not set
 CONFIG_GEN_RTC=y
 # CONFIG_GEN_RTC_X is not set
 # CONFIG_DTLK is not set
@@ -833,6 +800,7 @@
 #
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
 # CONFIG_USB is not set
 
 #
@@ -852,7 +820,14 @@
 #
 # InfiniBand support
 #
-# CONFIG_INFINIBAND is not set
+CONFIG_INFINIBAND=y
+CONFIG_INFINIBAND_USER_MAD=m
+CONFIG_INFINIBAND_USER_ACCESS=m
+CONFIG_INFINIBAND_MTHCA=m
+CONFIG_INFINIBAND_MTHCA_DEBUG=y
+CONFIG_INFINIBAND_IPOIB=m
+CONFIG_INFINIBAND_IPOIB_DEBUG=y
+CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y
 
 #
 # EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
@@ -1037,10 +1012,6 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_TEXTSEARCH=y
-CONFIG_TEXTSEARCH_KMP=m
-CONFIG_TEXTSEARCH_BM=m
-CONFIG_TEXTSEARCH_FSM=m
 
 #
 # Instrumentation Support
@@ -1058,7 +1029,7 @@
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_MUTEXES is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 CONFIG_DEBUG_SPINLOCK_SLEEP=y
 # CONFIG_DEBUG_KOBJECT is not set
diff --git a/arch/powerpc/configs/mpc8540_ads_defconfig b/arch/powerpc/configs/mpc8540_ads_defconfig
index 2a8290e..7f0780f 100644
--- a/arch/powerpc/configs/mpc8540_ads_defconfig
+++ b/arch/powerpc/configs/mpc8540_ads_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 
-# Sat Jan 14 15:57:54 2006
+# Linux kernel version: 2.6.16
+# Mon Mar 27 23:37:36 2006
 #
 # CONFIG_PPC64 is not set
 CONFIG_PPC32=y
@@ -9,6 +9,7 @@
 CONFIG_MMU=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_PPC=y
 CONFIG_EARLY_PRINTK=y
@@ -18,6 +19,7 @@
 CONFIG_PPC_OF=y
 CONFIG_PPC_UDBG_16550=y
 # CONFIG_GENERIC_TBSYNC is not set
+CONFIG_DEFAULT_UIMAGE=y
 
 #
 # Processor support
@@ -42,7 +44,6 @@
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
@@ -58,6 +59,7 @@
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
@@ -72,10 +74,6 @@
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
 CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
@@ -90,6 +88,8 @@
 # Block layer
 #
 # CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
 
 #
 # IO Schedulers
@@ -183,6 +183,7 @@
 #
 # Networking options
 #
+# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -220,6 +221,11 @@
 # 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
 # CONFIG_VLAN_8021Q is not set
@@ -229,11 +235,6 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
-# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -487,6 +488,12 @@
 # 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
@@ -496,6 +503,7 @@
 #
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_F71805F is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -503,10 +511,6 @@
 #
 
 #
-# Multimedia Capabilities Port drivers
-#
-
-#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -531,6 +535,7 @@
 #
 # CONFIG_USB_ARCH_HAS_HCD is not set
 # CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
 
 #
 # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
@@ -551,7 +556,7 @@
 #
 
 #
-# SN Devices
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
 #
 
 #
@@ -603,7 +608,6 @@
 CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -658,6 +662,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -695,6 +700,8 @@
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_UNWIND_INFO is not set
+CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_DEBUGGER is not set
 # CONFIG_BDI_SWITCH is not set
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 80e9fe2..0cc0995 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -12,12 +12,12 @@
 
 obj-y				:= semaphore.o cputable.o ptrace.o syscalls.o \
 				   irq.o align.o signal_32.o pmc.o vdso.o \
-				   init_task.o process.o systbl.o
+				   init_task.o process.o systbl.o idle.o
 obj-y				+= vdso32/
 obj-$(CONFIG_PPC64)		+= setup_64.o binfmt_elf32.o sys_ppc32.o \
 				   signal_64.o ptrace32.o \
 				   paca.o cpu_setup_power4.o \
-				   firmware.o sysfs.o idle_64.o
+				   firmware.o sysfs.o
 obj-$(CONFIG_PPC64)		+= vdso64/
 obj-$(CONFIG_ALTIVEC)		+= vecemu.o vector.o
 obj-$(CONFIG_POWER4)		+= idle_power4.o
@@ -34,6 +34,11 @@
 obj-$(CONFIG_GENERIC_TBSYNC)	+= smp-tbsync.o
 obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
+obj-$(CONFIG_6xx)		+= idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
+obj-$(CONFIG_TAU)		+= tau_6xx.o
+obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o
+obj32-$(CONFIG_MODULES)		+= module_32.o
+obj-$(CONFIG_E500)		+= perfmon_fsl_booke.o
 
 ifeq ($(CONFIG_PPC_MERGE),y)
 
@@ -51,7 +56,6 @@
 obj-$(CONFIG_PPC_MULTIPLATFORM)	+= prom_init.o
 obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
 obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
-obj-$(CONFIG_6xx)		+= idle_6xx.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_PPC_UDBG_16550)	+= legacy_serial.o udbg_16550.o
@@ -77,6 +81,7 @@
 
 endif
 
+obj-$(CONFIG_PPC32)		+= $(obj32-y)
 obj-$(CONFIG_PPC64)		+= $(obj64-y)
 
 extra-$(CONFIG_PPC_FPU)		+= fpu.o
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 882889b..54b48f3 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -105,8 +105,6 @@
 	DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size));
 	DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size));
 	DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page));
-	DEFINE(PLATFORM_LPAR, PLATFORM_LPAR);
-
 	/* paca */
 	DEFINE(PACA_SIZE, sizeof(struct paca_struct));
 	DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, paca_index));
diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/powerpc/kernel/cpu_setup_6xx.S
similarity index 100%
rename from arch/ppc/kernel/cpu_setup_6xx.S
rename to arch/powerpc/kernel/cpu_setup_6xx.S
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
index 211d726..764d073 100644
--- a/arch/powerpc/kernel/crash_dump.c
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -61,7 +61,7 @@
 	if (p)
 		elfcorehdr_addr = memparse(p, &p);
 
-	return 0;
+	return 1;
 }
 __setup("elfcorehdr=", parse_elfcorehdr);
 #endif
@@ -71,7 +71,7 @@
 	if (p)
 		saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1;
 
-	return 0;
+	return 1;
 }
 __setup("savemaxmem=", parse_savemaxmem);
 
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 4827ca1..b3a9794 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -135,10 +135,10 @@
 	mfspr	r11,SPRN_HID0
 	mtcr	r11
 BEGIN_FTR_SECTION
-	bt-	8,power_save_6xx_restore	/* Check DOZE */
+	bt-	8,4f			/* Check DOZE */
 END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
 BEGIN_FTR_SECTION
-	bt-	9,power_save_6xx_restore	/* Check NAP */
+	bt-	9,4f			/* Check NAP */
 END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
 #endif /* CONFIG_6xx */
 	.globl transfer_to_handler_cont
@@ -157,6 +157,10 @@
 	SYNC
 	RFI				/* jump to handler, enable MMU */
 
+#ifdef CONFIG_6xx	
+4:	b	power_save_6xx_restore
+#endif
+
 /*
  * On kernel stack overflow, load up an initial stack pointer
  * and call StackOverflow(regs), which should not return.
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 1060155..19ad5c6 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -617,6 +617,12 @@
 	mfsrr1	r10
 	std	r10,_SRR1(r1)
 
+	/* Temporary workaround to clear CR until RTAS can be modified to
+	 * ignore all bits.
+	 */
+	li	r0,0
+	mtcr	r0
+
 	/* There is no way it is acceptable to get here with interrupts enabled,
 	 * check it with the asm equivalent of WARN_ON
 	 */
diff --git a/arch/powerpc/kernel/firmware.c b/arch/powerpc/kernel/firmware.c
index 4d37a3c..0bfe906 100644
--- a/arch/powerpc/kernel/firmware.c
+++ b/arch/powerpc/kernel/firmware.c
@@ -14,7 +14,9 @@
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
 
 #include <asm/firmware.h>
 
-unsigned long ppc64_firmware_features;
+unsigned long powerpc_firmware_features;
+EXPORT_SYMBOL_GPL(powerpc_firmware_features);
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 35084f3..a5ae04a 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -1544,7 +1544,11 @@
 	mr	r28,r6
 	mr	r27,r7
 
-	/* Align the stack to 16-byte boundary for broken yaboot */
+	/*
+	 * Align the stack to 16-byte boundary
+	 * Depending on the size and layout of the ELF sections in the initial
+	 * boot binary, the stack pointer will be unalignet on PowerMac
+	 */
 	rldicr	r1,r1,0,59
 
 	/* Make sure we are running in 64 bits mode */
@@ -1847,21 +1851,6 @@
 	bl	.__save_cpu_setup
 	sync
 
-	/* Setup a valid physical PACA pointer in SPRG3 for early_setup
-	 * note that boot_cpuid can always be 0 nowadays since there is
-	 * nowhere it can be initialized differently before we reach this
-	 * code
-	 */
-	LOAD_REG_IMMEDIATE(r27, boot_cpuid)
-	add	r27,r27,r26
-	lwz	r27,0(r27)
-
-	LOAD_REG_IMMEDIATE(r24, paca) 	/* Get base vaddr of paca array	 */
-	mulli	r13,r27,PACA_SIZE	/* Calculate vaddr of right paca */
-	add	r13,r13,r24		/* for this processor.		 */
-	add	r13,r13,r26		/* convert to physical addr	 */
-	mtspr	SPRN_SPRG3,r13
-	
 	/* Do very early kernel initializations, including initial hash table,
 	 * stab and slb setup before we turn on relocation.	*/
 
@@ -1930,6 +1919,17 @@
 	/* Not reached */
 	BUG_OPCODE
 
+/* Put the paca pointer into r13 and SPRG3 */
+_GLOBAL(setup_boot_paca)
+	LOAD_REG_IMMEDIATE(r3, boot_cpuid)
+	lwz	r3,0(r3)
+	LOAD_REG_IMMEDIATE(r4, paca) 	/* Get base vaddr of paca array	 */
+	mulli	r3,r3,PACA_SIZE		/* Calculate vaddr of right paca */
+	add	r13,r3,r4		/* for this processor.		 */
+	mtspr	SPRN_SPRG3,r13
+
+	blr
+
 /*
  * We put a few things here that have to be page-aligned.
  * This stuff goes at the beginning of the bss, which is page-aligned.
diff --git a/arch/powerpc/kernel/idle_64.c b/arch/powerpc/kernel/idle.c
similarity index 64%
rename from arch/powerpc/kernel/idle_64.c
rename to arch/powerpc/kernel/idle.c
index b879d30..e9f321d 100644
--- a/arch/powerpc/kernel/idle_64.c
+++ b/arch/powerpc/kernel/idle.c
@@ -2,13 +2,17 @@
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
  *
- * Originally Written by Cort Dougan (cort@cs.nmt.edu)
+ * Originally written by Cort Dougan (cort@cs.nmt.edu).
+ * Subsequent 32-bit hacking by Tom Rini, Armin Kuster,
+ * Paul Mackerras and others.
  *
  * iSeries supported added by Mike Corrigan <mikejc@us.ibm.com>
  *
  * Additional shared processor, SMT, and firmware support
  *    Copyright (c) 2003 Dave Engebretsen <engebret@us.ibm.com>
  *
+ * 32-bit and 64-bit versions merged by Paul Mackerras <paulus@samba.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
@@ -29,18 +33,43 @@
 #include <asm/machdep.h>
 #include <asm/smp.h>
 
-extern void power4_idle(void);
+#ifdef CONFIG_HOTPLUG_CPU
+#define cpu_should_die()	(cpu_is_offline(smp_processor_id()) && \
+				 system_state == SYSTEM_RUNNING)
+#else
+#define cpu_should_die()	0
+#endif
 
-void default_idle(void)
+/*
+ * The body of the idle task.
+ */
+void cpu_idle(void)
 {
-	unsigned int cpu = smp_processor_id();
+	if (ppc_md.idle_loop)
+		ppc_md.idle_loop();	/* doesn't return */
+
 	set_thread_flag(TIF_POLLING_NRFLAG);
-
 	while (1) {
-		if (!need_resched()) {
-			while (!need_resched() && !cpu_is_offline(cpu)) {
-				ppc64_runlatch_off();
+		ppc64_runlatch_off();
 
+		while (!need_resched() && !cpu_should_die()) {
+			if (ppc_md.power_save) {
+				clear_thread_flag(TIF_POLLING_NRFLAG);
+				/*
+				 * smp_mb is so clearing of TIF_POLLING_NRFLAG
+				 * is ordered w.r.t. need_resched() test.
+				 */
+				smp_mb();
+				local_irq_disable();
+
+				/* check again after disabling irqs */
+				if (!need_resched() && !cpu_should_die())
+					ppc_md.power_save();
+
+				local_irq_enable();
+				set_thread_flag(TIF_POLLING_NRFLAG);
+
+			} else {
 				/*
 				 * Go into low thread priority and possibly
 				 * low power mode.
@@ -48,46 +77,18 @@
 				HMT_low();
 				HMT_very_low();
 			}
-
-			HMT_medium();
 		}
 
+		HMT_medium();
 		ppc64_runlatch_on();
+		if (cpu_should_die())
+			cpu_die();
 		preempt_enable_no_resched();
 		schedule();
 		preempt_disable();
-		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
-			cpu_die();
 	}
 }
 
-void native_idle(void)
-{
-	while (1) {
-		ppc64_runlatch_off();
-
-		if (!need_resched())
-			power4_idle();
-
-		if (need_resched()) {
-			ppc64_runlatch_on();
-			preempt_enable_no_resched();
-			schedule();
-			preempt_disable();
-		}
-
-		if (cpu_is_offline(smp_processor_id()) &&
-		    system_state == SYSTEM_RUNNING)
-			cpu_die();
-	}
-}
-
-void cpu_idle(void)
-{
-	BUG_ON(NULL == ppc_md.idle_loop);
-	ppc_md.idle_loop();
-}
-
 int powersave_nap;
 
 #ifdef CONFIG_SYSCTL
diff --git a/arch/powerpc/kernel/idle_6xx.S b/arch/powerpc/kernel/idle_6xx.S
index 444fdcc..12a4efb 100644
--- a/arch/powerpc/kernel/idle_6xx.S
+++ b/arch/powerpc/kernel/idle_6xx.S
@@ -87,19 +87,6 @@
 	cmpwi	0,r3,0
 	beqlr
 
-	/* Clear MSR:EE */
-	mfmsr	r7
-	rlwinm	r0,r7,0,17,15
-	mtmsr	r0
-
-	/* Check current_thread_info()->flags */
-	rlwinm	r4,r1,0,0,18
-	lwz	r4,TI_FLAGS(r4)
-	andi.	r0,r4,_TIF_NEED_RESCHED
-	beq	1f
-	mtmsr	r7	/* out of line this ? */
-	blr
-1:	
 	/* Some pre-nap cleanups needed on some CPUs */
 	andis.	r0,r3,HID0_NAP@h
 	beq	2f
@@ -157,7 +144,8 @@
 	DSSALL
 	sync
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-	ori	r7,r7,MSR_EE /* Could be ommited (already set) */
+	mfmsr	r7
+	ori	r7,r7,MSR_EE
 	oris	r7,r7,MSR_POW@h
 	sync
 	isync
@@ -220,8 +208,6 @@
 _GLOBAL(nap_save_hid1)
 	.space	4*NR_CPUS
 
-_GLOBAL(powersave_nap)
-	.long	0
 _GLOBAL(powersave_lowspeed)
 	.long	0
 
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S
index c16b4af..6dad1c0 100644
--- a/arch/powerpc/kernel/idle_power4.S
+++ b/arch/powerpc/kernel/idle_power4.S
@@ -1,11 +1,5 @@
 /*
- *  This file contains the power_save function for 6xx & 7xxx CPUs
- *  rewritten in assembler
- *
- *  Warning ! This code assumes that if your machine has a 750fx
- *  it will have PLL 1 set to low speed mode (used during NAP/DOZE).
- *  if this is not the case some additional changes will have to
- *  be done to check a runtime var (a bit like powersave-nap)
+ *  This file contains the power_save function for 970-family CPUs.
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -26,49 +20,23 @@
 
 	.text
 
-/*
- * Here is the power_save_6xx function. This could eventually be
- * split into several functions & changing the function pointer
- * depending on the various features.
- */
 _GLOBAL(power4_idle)
 BEGIN_FTR_SECTION
 	blr
 END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
-	/* We must dynamically check for the NAP feature as it
-	 * can be cleared by CPU init after the fixups are done
-	 */
-	LOAD_REG_ADDRBASE(r3,cur_cpu_spec)
-	ld	r4,ADDROFF(cur_cpu_spec)(r3)
-	ld	r4,CPU_SPEC_FEATURES(r4)
-	andi.	r0,r4,CPU_FTR_CAN_NAP
-	beqlr
 	/* Now check if user or arch enabled NAP mode */
 	LOAD_REG_ADDRBASE(r3,powersave_nap)
 	lwz	r4,ADDROFF(powersave_nap)(r3)
 	cmpwi	0,r4,0
 	beqlr
 
-	/* Clear MSR:EE */
-	mfmsr	r7
-	li	r4,0
-	ori	r4,r4,MSR_EE
-	andc	r0,r7,r4
-	mtmsrd	r0
-
-	/* Check current_thread_info()->flags */
-	clrrdi	r4,r1,THREAD_SHIFT
-	ld	r4,TI_FLAGS(r4)
-	andi.	r0,r4,_TIF_NEED_RESCHED
-	beq	1f
-	mtmsrd	r7	/* out of line this ? */
-	blr
-1:
 	/* Go to NAP now */
 BEGIN_FTR_SECTION
 	DSSALL
 	sync
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+	mfmsr	r7
+	ori	r7,r7,MSR_EE
 	oris	r7,r7,MSR_POW@h
 	sync
 	isync
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 771a59c..bb5c950 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -379,7 +379,7 @@
 	struct thread_info *tp;
 	int i;
 
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
 		tp = softirq_ctx[i];
 		tp->cpu = i;
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index cb1fe58..ad7a902 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -30,9 +30,11 @@
 #include <linux/kprobes.h>
 #include <linux/ptrace.h>
 #include <linux/preempt.h>
+#include <linux/module.h>
 #include <asm/cacheflush.h>
 #include <asm/kdebug.h>
 #include <asm/sstep.h>
+#include <asm/uaccess.h>
 
 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
 DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -372,17 +374,62 @@
 {
 	struct kprobe *cur = kprobe_running();
 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	const struct exception_table_entry *entry;
 
-	if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-		return 1;
-
-	if (kcb->kprobe_status & KPROBE_HIT_SS) {
-		resume_execution(cur, regs);
+	switch(kcb->kprobe_status) {
+	case KPROBE_HIT_SS:
+	case KPROBE_REENTER:
+		/*
+		 * We are here because the instruction being single
+		 * stepped caused a page fault. We reset the current
+		 * kprobe and the nip points back to the probe address
+		 * and allow the page fault handler to continue as a
+		 * normal page fault.
+		 */
+		regs->nip = (unsigned long)cur->addr;
 		regs->msr &= ~MSR_SE;
 		regs->msr |= kcb->kprobe_saved_msr;
-
-		reset_current_kprobe();
+		if (kcb->kprobe_status == KPROBE_REENTER)
+			restore_previous_kprobe(kcb);
+		else
+			reset_current_kprobe();
 		preempt_enable_no_resched();
+		break;
+	case KPROBE_HIT_ACTIVE:
+	case KPROBE_HIT_SSDONE:
+		/*
+		 * We increment the nmissed count for accounting,
+		 * we can also use npre/npostfault count for accouting
+		 * these specific fault cases.
+		 */
+		kprobes_inc_nmissed_count(cur);
+
+		/*
+		 * We come here because instructions in the pre/post
+		 * handler caused the page_fault, this could happen
+		 * if handler tries to access user space by
+		 * copy_from_user(), get_user() etc. Let the
+		 * user-specified handler try to fix it first.
+		 */
+		if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
+			return 1;
+
+		/*
+		 * In case the user-specified fault handler returned
+		 * zero, try to fix up.
+		 */
+		if ((entry = search_exception_tables(regs->nip)) != NULL) {
+			regs->nip = entry->fixup;
+			return 1;
+		}
+
+		/*
+		 * fixup_exception() could not handle it,
+		 * Let do_page_fault() fix it.
+		 */
+		break;
+	default:
+		break;
 	}
 	return 0;
 }
@@ -396,6 +443,9 @@
 	struct die_args *args = (struct die_args *)data;
 	int ret = NOTIFY_DONE;
 
+	if (args->regs && user_mode(args->regs))
+		return ret;
+
 	switch (val) {
 	case DIE_BPT:
 		if (kprobe_handler(args->regs))
diff --git a/arch/ppc/kernel/l2cr.S b/arch/powerpc/kernel/l2cr_6xx.S
similarity index 100%
rename from arch/ppc/kernel/l2cr.S
rename to arch/powerpc/kernel/l2cr_6xx.S
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index c7a799a..6e67b5b 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -37,7 +37,7 @@
 static int __init add_legacy_port(struct device_node *np, int want_index,
 				  int iotype, phys_addr_t base,
 				  phys_addr_t taddr, unsigned long irq,
-				  unsigned int flags)
+				  upf_t flags)
 {
 	u32 *clk, *spd, clock = BASE_BAUD * 16;
 	int index;
@@ -113,7 +113,7 @@
 {
 	phys_addr_t addr;
 	u32 *addrp;
-	unsigned int flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+	upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
 
 	/* We only support ports that have a clock frequency properly
 	 * encoded in the device-tree.
@@ -236,6 +236,23 @@
 }
 #endif
 
+static void __init setup_legacy_serial_console(int console)
+{
+	struct legacy_serial_info *info =
+		&legacy_serial_infos[console];
+	void __iomem *addr;
+
+	if (info->taddr == 0)
+		return;
+	addr = ioremap(info->taddr, 0x1000);
+	if (addr == NULL)
+		return;
+	if (info->speed == 0)
+		info->speed = udbg_probe_uart_speed(addr, info->clock);
+	DBG("default console speed = %d\n", info->speed);
+	udbg_init_uart(addr, info->speed, info->clock);
+}
+
 /*
  * This is called very early, as part of setup_system() or eventually
  * setup_arch(), basically before anything else in this file. This function
@@ -318,25 +335,8 @@
 #endif
 
 	DBG("legacy_serial_console = %d\n", legacy_serial_console);
-
-	/* udbg is 64 bits only for now, that will change soon though ... */
-	while (legacy_serial_console >= 0) {
-		struct legacy_serial_info *info =
-			&legacy_serial_infos[legacy_serial_console];
-		void __iomem *addr;
-
-		if (info->taddr == 0)
-			break;
-		addr = ioremap(info->taddr, 0x1000);
-		if (addr == NULL)
-			break;
-		if (info->speed == 0)
-			info->speed = udbg_probe_uart_speed(addr, info->clock);
-		DBG("default console speed = %d\n", info->speed);
-		udbg_init_uart(addr, info->speed, info->clock);
-		break;
-	}
-
+	if (legacy_serial_console >= 0)
+		setup_legacy_serial_console(legacy_serial_console);
 	DBG(" <- find_legacy_serial_port()\n");
 }
 
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index e789fef..1b73508 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -56,7 +56,7 @@
 	unsigned long sum_purr = 0;
 	int cpu;
 
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		sum_purr += lppaca[cpu].emulated_time_base;
 
 #ifdef PURR_DEBUG
@@ -222,7 +222,7 @@
 	int cpu;
 	struct cpu_usage *cu;
 
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		cu = &per_cpu(cpu_usage_array, cpu);
 		sum_purr += cu->current_tb;
 	}
diff --git a/arch/ppc/kernel/module.c b/arch/powerpc/kernel/module_32.c
similarity index 100%
rename from arch/ppc/kernel/module.c
rename to arch/powerpc/kernel/module_32.c
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index fd7db8d..ada50aa 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -160,7 +160,7 @@
 	case IOC_NVRAM_GET_OFFSET: {
 		int part, offset;
 
-		if (_machine != PLATFORM_POWERMAC)
+		if (!machine_is(powermac))
 			return -EINVAL;
 		if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0)
 			return -EFAULT;
@@ -174,8 +174,9 @@
 		return 0;
 	}
 #endif /* CONFIG_PPC_PMAC */
+	default:
+		return -EINVAL;
 	}
-	return -EINVAL;
 }
 
 struct file_operations nvram_fops = {
@@ -443,7 +444,7 @@
 	 * in our nvram, as Apple defined partitions use pretty much
 	 * all of the space
 	 */
-	if (_machine == PLATFORM_POWERMAC)
+	if (machine_is(powermac))
 		return -ENOSPC;
 
 	/* see if we have an OS partition that meets our needs.
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index 5d1b708..f505a88 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -56,14 +56,11 @@
  * processors.  The processor VPD array needs one entry per physical
  * processor (not thread).
  */
-#define PACA_INIT_COMMON(number, start, asrr, asrv)			    \
+#define PACA_INIT_COMMON(number)					    \
 	.lppaca_ptr = &lppaca[number],					    \
 	.lock_token = 0x8000,						    \
 	.paca_index = (number),		/* Paca Index */		    \
 	.kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL,		    \
-	.stab_real = (asrr), 		/* Real pointer to segment table */ \
-	.stab_addr = (asrv),		/* Virt pointer to segment table */ \
-	.cpu_start = (start),		/* Processor start */		    \
 	.hw_cpu_id = 0xffff,
 
 #ifdef CONFIG_PPC_ISERIES
@@ -72,30 +69,20 @@
 
 #define PACA_INIT(number)						    \
 {									    \
-	PACA_INIT_COMMON(number, 0, 0, 0)				    \
-	PACA_INIT_ISERIES(number)					    \
-}
-
-#define BOOTCPU_PACA_INIT(number)					    \
-{									    \
-	PACA_INIT_COMMON(number, 1, 0, (u64)&initial_stab)		    \
+	PACA_INIT_COMMON(number)					    \
 	PACA_INIT_ISERIES(number)					    \
 }
 
 #else
 #define PACA_INIT(number)						    \
 {									    \
-	PACA_INIT_COMMON(number, 0, 0, 0)				    \
+	PACA_INIT_COMMON(number)					    \
 }
 
-#define BOOTCPU_PACA_INIT(number)					    \
-{									    \
-	PACA_INIT_COMMON(number, 1, STAB0_PHYS_ADDR, (u64)&initial_stab)    \
-}
 #endif
 
 struct paca_struct paca[] = {
-	BOOTCPU_PACA_INIT(0),
+	PACA_INIT(0),
 #if NR_CPUS > 1
 	PACA_INIT(  1), PACA_INIT(  2), PACA_INIT(  3),
 #if NR_CPUS > 4
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index 704c846..b129d2e 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -787,7 +787,7 @@
 	 * fix has to be done by making the remapping per-host and always
 	 * filling the pci_to_OF map. --BenH
 	 */
-	if (_machine == _MACH_Pmac && busnr >= 0xf0)
+	if (machine_is(powermac) && busnr >= 0xf0)
 		busnr -= 0xf0;
 	else
 #endif
@@ -1728,7 +1728,7 @@
 	 * (bus 0 is HT root), we return the AGP one instead.
 	 */
 #ifdef CONFIG_PPC_PMAC
-	if (_machine == _MACH_Pmac && machine_is_compatible("MacRISC4"))
+	if (machine_is(powermac) && machine_is_compatible("MacRISC4"))
 		if (bus == 0)
 			bus = 0xf0;
 #endif /* CONFIG_PPC_PMAC */
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index ba92bab..4c4449b 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -78,6 +78,7 @@
 
 /* Cached ISA bridge dev. */
 struct pci_dev *ppc64_isabridge_dev = NULL;
+EXPORT_SYMBOL_GPL(ppc64_isabridge_dev);
 
 static void fixup_broken_pcnet32(struct pci_dev* dev)
 {
diff --git a/arch/ppc/kernel/perfmon_fsl_booke.c b/arch/powerpc/kernel/perfmon_fsl_booke.c
similarity index 100%
rename from arch/ppc/kernel/perfmon_fsl_booke.c
rename to arch/powerpc/kernel/perfmon_fsl_booke.c
diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c
index 7ba42a4..3c2cf66 100644
--- a/arch/powerpc/kernel/proc_ppc64.c
+++ b/arch/powerpc/kernel/proc_ppc64.c
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 
+#include <asm/machdep.h>
 #include <asm/vdso_datapage.h>
 #include <asm/rtas.h>
 #include <asm/uaccess.h>
@@ -51,7 +52,7 @@
 	if (!root)
 		return 1;
 
-	if (!(platform_is_pseries() || _machine == PLATFORM_CELL))
+	if (!machine_is(pseries) && !machine_is(cell))
 		return 0;
 
 	if (!proc_mkdir("rtas", root))
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 1770a06..2dd47d2 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -35,7 +35,6 @@
 #include <linux/mqueue.h>
 #include <linux/hardirq.h>
 #include <linux/utsname.h>
-#include <linux/kprobes.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -46,6 +45,7 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/time.h>
+#include <asm/syscalls.h>
 #ifdef CONFIG_PPC64
 #include <asm/firmware.h>
 #endif
@@ -363,7 +363,11 @@
 		if (!(i % 8))
 			printk("\n");
 
-		if (BAD_PC(pc) || __get_user(instr, (unsigned int *)pc)) {
+		/* We use __get_user here *only* to avoid an OOPS on a
+		 * bad address because the pc *should* only be a
+		 * kernel address.
+		 */
+		if (BAD_PC(pc) || __get_user(instr, (unsigned int __user *)pc)) {
 			printk("XXXXXXXX ");
 		} else {
 			if (regs->nip == pc)
@@ -460,7 +464,6 @@
 
 void exit_thread(void)
 {
-	kprobe_flush_task(current);
 	discard_lazy_cpu_state();
 }
 
@@ -767,7 +770,7 @@
 	return error;
 }
 
-static int validate_sp(unsigned long sp, struct task_struct *p,
+int validate_sp(unsigned long sp, struct task_struct *p,
 		       unsigned long nbytes)
 {
 	unsigned long stack_page = (unsigned long)task_stack_page(p);
@@ -805,6 +808,8 @@
 #define FRAME_MARKER	2
 #endif
 
+EXPORT_SYMBOL(validate_sp);
+
 unsigned long get_wchan(struct task_struct *p)
 {
 	unsigned long ip, sp;
@@ -829,7 +834,6 @@
 	} while (count++ < 16);
 	return 0;
 }
-EXPORT_SYMBOL(get_wchan);
 
 static int kstack_depth_to_print = 64;
 
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index d63cd56..4336390 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -383,14 +383,14 @@
 			/* Apple uses bits in there in a different way, let's
 			 * only keep the real sense bit on macs
 			 */
-			if (_machine == PLATFORM_POWERMAC)
+			if (machine_is(powermac))
 				sense &= 0x1;
 			np->intrs[intrcount].sense = map_mpic_senses[sense];
 		}
 
 #ifdef CONFIG_PPC64
 		/* We offset irq numbers for the u3 MPIC by 128 in PowerMac */
-		if (_machine == PLATFORM_POWERMAC && ic && ic->parent) {
+		if (machine_is(powermac) && ic && ic->parent) {
 			char *name = get_property(ic->parent, "name", NULL);
 			if (name && !strcmp(name, "u3"))
 				np->intrs[intrcount].line += 128;
@@ -570,6 +570,18 @@
 	return rc;
 }
 
+unsigned long __init of_get_flat_dt_root(void)
+{
+	unsigned long p = ((unsigned long)initial_boot_params) +
+		initial_boot_params->off_dt_struct;
+
+	while(*((u32 *)p) == OF_DT_NOP)
+		p += 4;
+	BUG_ON (*((u32 *)p) != OF_DT_BEGIN_NODE);
+	p += 4;
+	return _ALIGN(p + strlen((char *)p) + 1, 4);
+}
+
 /**
  * This  function can be used within scan_flattened_dt callback to get
  * access to properties
@@ -612,6 +624,25 @@
 	} while(1);
 }
 
+int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
+{
+	const char* cp;
+	unsigned long cplen, l;
+
+	cp = of_get_flat_dt_prop(node, "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;
+}
+
 static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
 				       unsigned long align)
 {
@@ -686,7 +717,7 @@
 #ifdef DEBUG
 				if ((strlen(p) + l + 1) != allocl) {
 					DBG("%s: p: %d, l: %d, a: %d\n",
-					    pathp, strlen(p), l, allocl);
+					    pathp, (int)strlen(p), l, allocl);
 				}
 #endif
 				p += strlen(p);
@@ -854,35 +885,73 @@
 	DBG(" <- unflatten_device_tree()\n");
 }
 
-
 static int __init early_init_dt_scan_cpus(unsigned long node,
-					  const char *uname, int depth, void *data)
+					  const char *uname, int depth,
+					  void *data)
 {
+	static int logical_cpuid = 0;
+	char *type = of_get_flat_dt_prop(node, "device_type", NULL);
+#ifdef CONFIG_ALTIVEC
 	u32 *prop;
-	unsigned long size;
-	char *type = of_get_flat_dt_prop(node, "device_type", &size);
+#endif
+	u32 *intserv;
+	int i, nthreads;
+	unsigned long len;
+	int found = 0;
 
 	/* We are scanning "cpu" nodes only */
 	if (type == NULL || strcmp(type, "cpu") != 0)
 		return 0;
 
-	boot_cpuid = 0;
-	boot_cpuid_phys = 0;
-	if (initial_boot_params && initial_boot_params->version >= 2) {
-		/* version 2 of the kexec param format adds the phys cpuid
-		 * of booted proc.
-		 */
-		boot_cpuid_phys = initial_boot_params->boot_cpuid_phys;
+	/* Get physical cpuid */
+	intserv = of_get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s", &len);
+	if (intserv) {
+		nthreads = len / sizeof(int);
 	} else {
-		/* Check if it's the boot-cpu, set it's hw index now */
-		if (of_get_flat_dt_prop(node,
-					"linux,boot-cpu", NULL) != NULL) {
-			prop = of_get_flat_dt_prop(node, "reg", NULL);
-			if (prop != NULL)
-				boot_cpuid_phys = *prop;
-		}
+		intserv = of_get_flat_dt_prop(node, "reg", NULL);
+		nthreads = 1;
 	}
-	set_hard_smp_processor_id(0, boot_cpuid_phys);
+
+	/*
+	 * Now see if any of these threads match our boot cpu.
+	 * NOTE: This must match the parsing done in smp_setup_cpu_maps.
+	 */
+	for (i = 0; i < nthreads; i++) {
+		/*
+		 * version 2 of the kexec param format adds the phys cpuid of
+		 * booted proc.
+		 */
+		if (initial_boot_params && initial_boot_params->version >= 2) {
+			if (intserv[i] ==
+					initial_boot_params->boot_cpuid_phys) {
+				found = 1;
+				break;
+			}
+		} else {
+			/*
+			 * Check if it's the boot-cpu, set it's hw index now,
+			 * unfortunately this format did not support booting
+			 * off secondary threads.
+			 */
+			if (of_get_flat_dt_prop(node,
+					"linux,boot-cpu", NULL) != NULL) {
+				found = 1;
+				break;
+			}
+		}
+
+#ifdef CONFIG_SMP
+		/* logical cpu id is always 0 on UP kernels */
+		logical_cpuid++;
+#endif
+	}
+
+	if (found) {
+		DBG("boot cpu: logical %d physical %d\n", logical_cpuid,
+			intserv[i]);
+		boot_cpuid = logical_cpuid;
+		set_hard_smp_processor_id(boot_cpuid, intserv[i]);
+	}
 
 #ifdef CONFIG_ALTIVEC
 	/* Check if we have a VMX and eventually update CPU features */
@@ -901,16 +970,10 @@
 #endif /* CONFIG_ALTIVEC */
 
 #ifdef CONFIG_PPC_PSERIES
-	/*
-	 * Check for an SMT capable CPU and set the CPU feature. We do
-	 * this by looking at the size of the ibm,ppc-interrupt-server#s
-	 * property
-	 */
-	prop = (u32 *)of_get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s",
-				       &size);
-	cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT;
-	if (prop && ((size / sizeof(u32)) > 1))
+	if (nthreads > 1)
 		cur_cpu_spec->cpu_features |= CPU_FTR_SMT;
+	else
+		cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT;
 #endif
 
 	return 0;
@@ -919,7 +982,6 @@
 static int __init early_init_dt_scan_chosen(unsigned long node,
 					    const char *uname, int depth, void *data)
 {
-	u32 *prop;
 	unsigned long *lprop;
 	unsigned long l;
 	char *p;
@@ -930,14 +992,6 @@
 	    (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
 		return 0;
 
-	/* get platform type */
-	prop = (u32 *)of_get_flat_dt_prop(node, "linux,platform", NULL);
-	if (prop == NULL)
-		return 0;
-#ifdef CONFIG_PPC_MULTIPLATFORM
-	_machine = *prop;
-#endif
-
 #ifdef CONFIG_PPC64
 	/* check if iommu is forced on or off */
 	if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL)
@@ -964,15 +1018,15 @@
 	 * set of RTAS infos now if available
 	 */
 	{
-		u64 *basep, *entryp;
+		u64 *basep, *entryp, *sizep;
 
 		basep = of_get_flat_dt_prop(node, "linux,rtas-base", NULL);
 		entryp = of_get_flat_dt_prop(node, "linux,rtas-entry", NULL);
-		prop = of_get_flat_dt_prop(node, "linux,rtas-size", NULL);
-		if (basep && entryp && prop) {
+		sizep = of_get_flat_dt_prop(node, "linux,rtas-size", NULL);
+		if (basep && entryp && sizep) {
 			rtas.base = *basep;
 			rtas.entry = *entryp;
-			rtas.size = *prop;
+			rtas.size = *sizep;
 		}
 	}
 #endif /* CONFIG_PPC_RTAS */
@@ -1001,25 +1055,13 @@
 
 	if (strstr(cmd_line, "mem=")) {
 		char *p, *q;
-		unsigned long maxmem = 0;
 
 		for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) {
 			q = p + 4;
 			if (p > cmd_line && p[-1] != ' ')
 				continue;
-			maxmem = simple_strtoul(q, &q, 0);
-			if (*q == 'k' || *q == 'K') {
-				maxmem <<= 10;
-				++q;
-			} else if (*q == 'm' || *q == 'M') {
-				maxmem <<= 20;
-				++q;
-			} else if (*q == 'g' || *q == 'G') {
-				maxmem <<= 30;
-				++q;
-			}
+			memory_limit = memparse(q, &q);
 		}
-		memory_limit = maxmem;
 	}
 
 	/* break now */
@@ -1755,7 +1797,7 @@
 	/* We don't support that function on PowerMac, at least
 	 * not yet
 	 */
-	if (_machine == PLATFORM_POWERMAC)
+	if (machine_is(powermac))
 		return -ENODEV;
 
 	/* fix up new node's linux_phandle field */
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 813c2cd..d66c5e7 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -180,6 +180,16 @@
 static unsigned long __initdata prom_tce_alloc_end;
 #endif
 
+/* Platforms codes are now obsolete in the kernel. Now only used within this
+ * file and ultimately gone too. Feel free to change them if you need, they
+ * are not shared with anything outside of this file anymore
+ */
+#define PLATFORM_PSERIES	0x0100
+#define PLATFORM_PSERIES_LPAR	0x0101
+#define PLATFORM_LPAR		0x0001
+#define PLATFORM_POWERMAC	0x0400
+#define PLATFORM_GENERIC	0x0500
+
 static int __initdata of_platform;
 
 static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
@@ -397,6 +407,11 @@
 	reason = PTRRELOC(reason);
 #endif
 	prom_print(reason);
+	/* Do not call exit because it clears the screen on pmac
+	 * it also causes some sort of double-fault on early pmacs */
+	if (RELOC(of_platform) == PLATFORM_POWERMAC)
+		asm("trap\n");
+
 	/* ToDo: should put up an SRC here on p/iSeries */
 	call_prom("exit", 0, 0);
 
@@ -1487,7 +1502,10 @@
 	int len, i = 0;
 #ifdef CONFIG_PPC64
 	phandle rtas;
+	int x;
 #endif
+
+	/* Look for a PowerMac */
 	len = prom_getprop(_prom->root, "compatible",
 			   compat, sizeof(compat)-1);
 	if (len > 0) {
@@ -1500,28 +1518,36 @@
 			if (strstr(p, RELOC("Power Macintosh")) ||
 			    strstr(p, RELOC("MacRISC")))
 				return PLATFORM_POWERMAC;
-#ifdef CONFIG_PPC64
-			if (strstr(p, RELOC("Momentum,Maple")))
-				return PLATFORM_MAPLE;
-			if (strstr(p, RELOC("IBM,CPB")))
-				return PLATFORM_CELL;
-#endif
 			i += sl + 1;
 		}
 	}
 #ifdef CONFIG_PPC64
+	/* If not a mac, try to figure out if it's an IBM pSeries or any other
+	 * PAPR compliant platform. We assume it is if :
+	 *  - /device_type is "chrp" (please, do NOT use that for future
+	 *    non-IBM designs !
+	 *  - it has /rtas
+	 */
+	len = prom_getprop(_prom->root, "model",
+			   compat, sizeof(compat)-1);
+	if (len <= 0)
+		return PLATFORM_GENERIC;
+	compat[len] = 0;
+	if (strcmp(compat, "chrp"))
+		return PLATFORM_GENERIC;
+
 	/* Default to pSeries. We need to know if we are running LPAR */
 	rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
-	if (PHANDLE_VALID(rtas)) {
-		int x = prom_getproplen(rtas, "ibm,hypertas-functions");
-		if (x != PROM_ERROR) {
-			prom_printf("Hypertas detected, assuming LPAR !\n");
-			return PLATFORM_PSERIES_LPAR;
-		}
+	if (!PHANDLE_VALID(rtas))
+		return PLATFORM_GENERIC;
+	x = prom_getproplen(rtas, "ibm,hypertas-functions");
+	if (x != PROM_ERROR) {
+		prom_printf("Hypertas detected, assuming LPAR !\n");
+		return PLATFORM_PSERIES_LPAR;
 	}
 	return PLATFORM_PSERIES;
 #else
-	return PLATFORM_CHRP;
+	return PLATFORM_GENERIC;
 #endif
 }
 
@@ -2029,7 +2055,6 @@
 {	
        	struct prom_t *_prom;
 	unsigned long hdr;
-	u32 getprop_rval;
 	unsigned long offset = reloc_offset();
 
 #ifdef CONFIG_PPC32
@@ -2060,6 +2085,12 @@
 	 */
 	prom_init_stdout();
 
+	/*
+	 * Get default machine type. At this point, we do not differentiate
+	 * between pSeries SMP and pSeries LPAR
+	 */
+	RELOC(of_platform) = prom_find_machine_type();
+
 	/* Bail if this is a kdump kernel. */
 	if (PHYSICAL_START > 0)
 		prom_panic("Error: You can't boot a kdump kernel from OF!\n");
@@ -2069,15 +2100,6 @@
 	 */
 	prom_check_initrd(r3, r4);
 
-	/*
-	 * Get default machine type. At this point, we do not differentiate
-	 * between pSeries SMP and pSeries LPAR
-	 */
-	RELOC(of_platform) = prom_find_machine_type();
-	getprop_rval = RELOC(of_platform);
-	prom_setprop(_prom->chosen, "/chosen", "linux,platform",
-		     &getprop_rval, sizeof(getprop_rval));
-
 #ifdef CONFIG_PPC_PSERIES
 	/*
 	 * On pSeries, inform the firmware about our capabilities
diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c
index 1f03fb2..456286c 100644
--- a/arch/powerpc/kernel/rtas-proc.c
+++ b/arch/powerpc/kernel/rtas-proc.c
@@ -257,7 +257,7 @@
 {
 	struct proc_dir_entry *entry;
 
-	if (_machine != PLATFORM_PSERIES && _machine != PLATFORM_PSERIES_LPAR)
+	if (!machine_is(pseries))
 		return 1;
 
 	rtas_node = of_find_node_by_name(NULL, "rtas");
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index b5b2add..06636c9 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -25,6 +25,7 @@
 #include <asm/hvcall.h>
 #include <asm/semaphore.h>
 #include <asm/machdep.h>
+#include <asm/firmware.h>
 #include <asm/page.h>
 #include <asm/param.h>
 #include <asm/system.h>
@@ -32,6 +33,7 @@
 #include <asm/uaccess.h>
 #include <asm/lmb.h>
 #include <asm/udbg.h>
+#include <asm/syscalls.h>
 
 struct rtas_t rtas = {
 	.lock = SPIN_LOCK_UNLOCKED
@@ -591,7 +593,7 @@
 		data->waiting = 0;
 		data->args->args[data->args->nargs] =
 			rtas_call(ibm_suspend_me_token, 0, 1, NULL);
-		for_each_cpu(i)
+		for_each_possible_cpu(i)
 			plpar_hcall_norets(H_PROD,i);
 	} else {
 		data->waiting = -EBUSY;
@@ -624,7 +626,7 @@
 	/* Prod each CPU.  This won't hurt, and will wake
 	 * anyone we successfully put to sleep with H_Join
 	 */
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 		plpar_hcall_norets(H_PROD, i);
 
 	return data.waiting;
@@ -767,7 +769,7 @@
 	 * the stop-self token if any
 	 */
 #ifdef CONFIG_PPC64
-	if (_machine == PLATFORM_PSERIES_LPAR) {
+	if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR)) {
 		rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX);
 		ibm_suspend_me_token = rtas_token("ibm,suspend-me");
 	}
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index c1d62bf..c607f3b 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -9,6 +9,9 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  */
+
+#undef DEBUG
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/string.h>
@@ -41,6 +44,7 @@
 #include <asm/time.h>
 #include <asm/cputable.h>
 #include <asm/sections.h>
+#include <asm/firmware.h>
 #include <asm/btext.h>
 #include <asm/nvram.h>
 #include <asm/setup.h>
@@ -56,8 +60,6 @@
 
 #include "setup.h"
 
-#undef DEBUG
-
 #ifdef DEBUG
 #include <asm/udbg.h>
 #define DBG(fmt...) udbg_printf(fmt)
@@ -65,10 +67,12 @@
 #define DBG(fmt...)
 #endif
 
-#ifdef CONFIG_PPC_MULTIPLATFORM
-int _machine = 0;
-EXPORT_SYMBOL(_machine);
-#endif
+/* The main machine-dep calls structure
+ */
+struct machdep_calls ppc_md;
+EXPORT_SYMBOL(ppc_md);
+struct machdep_calls *machine_id;
+EXPORT_SYMBOL(machine_id);
 
 unsigned long klimit = (unsigned long) _end;
 
@@ -168,7 +172,8 @@
 			   bogosum/(500000/HZ), bogosum/(5000/HZ) % 100);
 #endif /* CONFIG_SMP && CONFIG_PPC32 */
 		seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq);
-
+		if (ppc_md.name)
+			seq_printf(m, "platform\t: %s\n", ppc_md.name);
 		if (ppc_md.show_cpuinfo != NULL)
 			ppc_md.show_cpuinfo(m);
 
@@ -352,12 +357,13 @@
  * must be called before using this.
  *
  * While we're here, we may as well set the "physical" cpu ids in the paca.
+ *
+ * NOTE: This must match the parsing done in early_init_dt_scan_cpus.
  */
 void __init smp_setup_cpu_maps(void)
 {
 	struct device_node *dn = NULL;
 	int cpu = 0;
-	int swap_cpuid = 0;
 
 	while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) {
 		int *intserv;
@@ -376,30 +382,17 @@
 		for (j = 0; j < nthreads && cpu < NR_CPUS; j++) {
 			cpu_set(cpu, cpu_present_map);
 			set_hard_smp_processor_id(cpu, intserv[j]);
-
-			if (intserv[j] == boot_cpuid_phys)
-				swap_cpuid = cpu;
 			cpu_set(cpu, cpu_possible_map);
 			cpu++;
 		}
 	}
 
-	/* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that
-	 * boot cpu is logical 0.
-	 */
-	if (boot_cpuid_phys != get_hard_smp_processor_id(0)) {
-		u32 tmp;
-		tmp = get_hard_smp_processor_id(0);
-		set_hard_smp_processor_id(0, boot_cpuid_phys);
-		set_hard_smp_processor_id(swap_cpuid, tmp);
-	}
-
 #ifdef CONFIG_PPC64
 	/*
 	 * On pSeries LPAR, we need to know how many cpus
 	 * could possibly be added to this partition.
 	 */
-	if (_machine == PLATFORM_PSERIES_LPAR &&
+	if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR) &&
 	    (dn = of_find_node_by_path("/rtas"))) {
 		int num_addr_cell, num_size_cell, maxcpus;
 		unsigned int *ireg;
@@ -438,7 +431,7 @@
 	/*
 	 * Do the sibling map; assume only two threads per processor.
 	 */
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		cpu_set(cpu, cpu_sibling_map[cpu]);
 		if (cpu_has_feature(CPU_FTR_SMT))
 			cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]);
@@ -468,3 +461,34 @@
 }
 early_param("xmon", early_xmon);
 #endif
+
+void probe_machine(void)
+{
+	extern struct machdep_calls __machine_desc_start;
+	extern struct machdep_calls __machine_desc_end;
+
+	/*
+	 * Iterate all ppc_md structures until we find the proper
+	 * one for the current machine type
+	 */
+	DBG("Probing machine type ...\n");
+
+	for (machine_id = &__machine_desc_start;
+	     machine_id < &__machine_desc_end;
+	     machine_id++) {
+		DBG("  %s ...", machine_id->name);
+		memcpy(&ppc_md, machine_id, sizeof(struct machdep_calls));
+		if (ppc_md.probe()) {
+			DBG(" match !\n");
+			break;
+		}
+		DBG("\n");
+	}
+	/* What can we do if we didn't find ? */
+	if (machine_id >= &__machine_desc_end) {
+		DBG("No suitable machine found !\n");
+		for (;;);
+	}
+
+	printk(KERN_INFO "Using %s machine description\n", ppc_md.name);
+}
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index dc2770d..a72bf5d 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -53,9 +53,6 @@
 extern void platform_init(void);
 extern void bootx_init(unsigned long r4, unsigned long phys);
 
-extern void ppc6xx_idle(void);
-extern void power4_idle(void);
-
 boot_infos_t *boot_infos;
 struct ide_machdep_calls ppc_ide_md;
 
@@ -70,10 +67,6 @@
 int have_of = 1;
 
 #ifdef CONFIG_PPC_MULTIPLATFORM
-extern void prep_init(void);
-extern void pmac_init(void);
-extern void chrp_init(void);
-
 dev_t boot_dev;
 #endif /* CONFIG_PPC_MULTIPLATFORM */
 
@@ -85,9 +78,6 @@
 unsigned long vgacon_remap_base;
 #endif
 
-struct machdep_calls ppc_md;
-EXPORT_SYMBOL(ppc_md);
-
 /*
  * These are used in binfmt_elf.c to put aux entries on the stack
  * for each elf executable being started.
@@ -111,7 +101,7 @@
 
 	/* First zero the BSS -- use memset_io, some platforms don't have
 	 * caches on yet */
-	memset_io(PTRRELOC(&__bss_start), 0, _end - __bss_start);
+	memset_io((void __iomem *)PTRRELOC(&__bss_start), 0, _end - __bss_start);
 
 	/*
 	 * Identify the CPU type and fix up code sections
@@ -123,48 +113,6 @@
 	return KERNELBASE + offset;
 }
 
-#ifdef CONFIG_PPC_MULTIPLATFORM
-/*
- * The PPC_MULTIPLATFORM version of platform_init...
- */
-void __init platform_init(void)
-{
-	/* if we didn't get any bootinfo telling us what we are... */
-	if (_machine == 0) {
-		/* prep boot loader tells us if we're prep or not */
-		if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) )
-			_machine = _MACH_prep;
-	}
-
-#ifdef CONFIG_PPC_PREP
-	/* not much more to do here, if prep */
-	if (_machine == _MACH_prep) {
-		prep_init();
-		return;
-	}
-#endif
-
-#ifdef CONFIG_ADB
-	if (strstr(cmd_line, "adb_sync")) {
-		extern int __adb_probe_sync;
-		__adb_probe_sync = 1;
-	}
-#endif /* CONFIG_ADB */
-
-	switch (_machine) {
-#ifdef CONFIG_PPC_PMAC
-	case _MACH_Pmac:
-		pmac_init();
-		break;
-#endif
-#ifdef CONFIG_PPC_CHRP
-	case _MACH_chrp:
-		chrp_init();
-		break;
-#endif
-	}
-}
-#endif
 
 /*
  * Find out what kind of machine we're on and save any data we need
@@ -190,11 +138,17 @@
 		strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
 #endif /* CONFIG_CMDLINE */
 
-	/* Base init based on machine type */
+#ifdef CONFIG_PPC_MULTIPLATFORM
+	probe_machine();
+#else
+	/* Base init based on machine type. Obsoloete, please kill ! */
 	platform_init();
+#endif
 
 #ifdef CONFIG_6xx
-	ppc_md.power_save = ppc6xx_idle;
+	if (cpu_has_feature(CPU_FTR_CAN_DOZE) ||
+	    cpu_has_feature(CPU_FTR_CAN_NAP))
+		ppc_md.power_save = ppc6xx_idle;
 #endif
 
 	if (ppc_md.progress)
@@ -272,7 +226,7 @@
 	if ( ppc_md.progress ) ppc_md.progress("             ", 0xffff);
 
 	/* register CPU devices */
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 		register_cpu(&cpu_devices[i], i, NULL);
 
 	/* call platform init */
@@ -352,12 +306,6 @@
 	do_init_bootmem();
 	if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
 
-#ifdef CONFIG_PPC_OCP
-	/* Initialize OCP device list */
-	ocp_early_init();
-	if ( ppc_md.progress ) ppc_md.progress("ocp: exit", 0x3eab);
-#endif
-
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
@@ -366,7 +314,4 @@
 	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
 
 	paging_init();
-
-	/* this is for modules since _machine can be a define -- Cort */
-	ppc_md.ppc_machine = _machine;
 }
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 2f3fdad..59aa92c 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -73,7 +73,6 @@
 
 int have_of = 1;
 int boot_cpuid = 0;
-int boot_cpuid_phys = 0;
 dev_t boot_dev;
 u64 ppc64_pft_size;
 
@@ -96,11 +95,6 @@
 int icache_bsize;
 int ucache_bsize;
 
-/* The main machine-dep calls structure
- */
-struct machdep_calls ppc_md;
-EXPORT_SYMBOL(ppc_md);
-
 #ifdef CONFIG_MAGIC_SYSRQ
 unsigned long SYSRQ_KEY;
 #endif /* CONFIG_MAGIC_SYSRQ */
@@ -161,32 +155,6 @@
 #define check_smt_enabled()
 #endif /* CONFIG_SMP */
 
-extern struct machdep_calls pSeries_md;
-extern struct machdep_calls pmac_md;
-extern struct machdep_calls maple_md;
-extern struct machdep_calls cell_md;
-extern struct machdep_calls iseries_md;
-
-/* Ultimately, stuff them in an elf section like initcalls... */
-static struct machdep_calls __initdata *machines[] = {
-#ifdef CONFIG_PPC_PSERIES
-	&pSeries_md,
-#endif /* CONFIG_PPC_PSERIES */
-#ifdef CONFIG_PPC_PMAC
-	&pmac_md,
-#endif /* CONFIG_PPC_PMAC */
-#ifdef CONFIG_PPC_MAPLE
-	&maple_md,
-#endif /* CONFIG_PPC_MAPLE */
-#ifdef CONFIG_PPC_CELL
-	&cell_md,
-#endif
-#ifdef CONFIG_PPC_ISERIES
-	&iseries_md,
-#endif
-	NULL
-};
-
 /*
  * Early initialization entry point. This is called by head.S
  * with MMU translation disabled. We rely on the "feature" of
@@ -208,13 +176,10 @@
 
 void __init early_setup(unsigned long dt_ptr)
 {
-	struct paca_struct *lpaca = get_paca();
-	static struct machdep_calls **mach;
-
 	/* Enable early debugging if any specified (see udbg.h) */
 	udbg_early_init();
 
-	DBG(" -> early_setup()\n");
+ 	DBG(" -> early_setup(), dt_ptr: 0x%lx\n", dt_ptr);
 
 	/*
 	 * Do early initializations using the flattened device
@@ -223,22 +188,16 @@
 	 */
 	early_init_devtree(__va(dt_ptr));
 
-	/*
-	 * Iterate all ppc_md structures until we find the proper
-	 * one for the current machine type
-	 */
-	DBG("Probing machine type for platform %x...\n", _machine);
+	/* Now we know the logical id of our boot cpu, setup the paca. */
+	setup_boot_paca();
 
-	for (mach = machines; *mach; mach++) {
-		if ((*mach)->probe(_machine))
-			break;
-	}
-	/* What can we do if we didn't find ? */
-	if (*mach == NULL) {
-		DBG("No suitable machine found !\n");
-		for (;;);
-	}
-	ppc_md = **mach;
+	/* Fix up paca fields required for the boot cpu */
+	get_paca()->cpu_start = 1;
+	get_paca()->stab_real = __pa((u64)&initial_stab);
+	get_paca()->stab_addr = (u64)&initial_stab;
+
+	/* Probe the machine type */
+	probe_machine();
 
 #ifdef CONFIG_CRASH_DUMP
 	kdump_setup();
@@ -260,7 +219,7 @@
 		if (cpu_has_feature(CPU_FTR_SLB))
 			slb_initialize();
 		else
-			stab_initialize(lpaca->stab_real);
+			stab_initialize(get_paca()->stab_real);
 	}
 
 	DBG(" <- early_setup()\n");
@@ -340,7 +299,7 @@
 			const char *dc, *ic;
 
 			/* Then read cache informations */
-			if (_machine == PLATFORM_POWERMAC) {
+			if (machine_is(powermac)) {
 				dc = "d-cache-block-size";
 				ic = "i-cache-block-size";
 			} else {
@@ -484,7 +443,6 @@
 	printk("ppc64_pft_size                = 0x%lx\n", ppc64_pft_size);
 	printk("ppc64_interrupt_controller    = 0x%ld\n",
 	       ppc64_interrupt_controller);
-	printk("platform                      = 0x%x\n", _machine);
 	printk("physicalMemorySize            = 0x%lx\n", lmb_phys_mem_size());
 	printk("ppc64_caches.dcache_line_size = 0x%x\n",
 	       ppc64_caches.dline_size);
@@ -516,7 +474,7 @@
 	 * interrupt stacks must be under 256MB, we cannot afford to take
 	 * SLB misses on them.
 	 */
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		softirq_ctx[i] = (struct thread_info *)
 			__va(lmb_alloc_base(THREAD_SIZE,
 					    THREAD_SIZE, 0x10000000));
@@ -549,7 +507,7 @@
 	 */
 	limit = min(0x10000000UL, lmb.rmo_size);
 
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 		paca[i].emergency_sp =
 		__va(lmb_alloc_base(HW_PAGE_SIZE, 128, limit)) + HW_PAGE_SIZE;
 }
@@ -579,7 +537,8 @@
 	panic_timeout = 180;
 
 	if (ppc_md.panic)
-		notifier_chain_register(&panic_notifier_list, &ppc64_panic_block);
+		atomic_notifier_chain_register(&panic_notifier_list,
+				&ppc64_panic_block);
 
 	init_mm.start_code = PAGE_OFFSET;
 	init_mm.end_code = (unsigned long) _etext;
@@ -601,12 +560,6 @@
 
 	ppc_md.setup_arch();
 
-	/* Use the default idle loop if the platform hasn't provided one. */
-	if (NULL == ppc_md.idle_loop) {
-		ppc_md.idle_loop = default_idle;
-		printk(KERN_INFO "Using default idle loop\n");
-	}
-
 	paging_init();
 	ppc64_boot_msg(0x15, "Setup Done");
 }
@@ -671,7 +624,7 @@
 		size = PERCPU_ENOUGH_ROOM;
 #endif
 
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size);
 		if (!ptr)
 			panic("Cannot allocate cpu data for CPU %d\n", i);
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index d7a4e81..01e3c08 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -42,6 +42,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
+#include <asm/syscalls.h>
 #include <asm/sigcontext.h>
 #include <asm/vdso.h>
 #ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 47f9103..27f65b9 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -33,6 +33,7 @@
 #include <asm/pgtable.h>
 #include <asm/unistd.h>
 #include <asm/cacheflush.h>
+#include <asm/syscalls.h>
 #include <asm/vdso.h>
 
 #define DEBUG_SIG 0
@@ -211,7 +212,7 @@
         /* Default to using normal stack */
         newsp = regs->gpr[1];
 
-	if (ka->sa.sa_flags & SA_ONSTACK) {
+	if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size) {
 		if (! on_sig_stack(regs->gpr[1]))
 			newsp = (current->sas_ss_sp + current->sas_ss_size);
 	}
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 805eaed..530f7db 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -362,7 +362,7 @@
  
 	smp_space_timers(max_cpus);
 
-	for_each_cpu(cpu)
+	for_each_possible_cpu(cpu)
 		if (cpu != boot_cpuid)
 			smp_create_idle(cpu);
 }
diff --git a/arch/ppc/kernel/swsusp.S b/arch/powerpc/kernel/swsusp_32.S
similarity index 100%
rename from arch/ppc/kernel/swsusp.S
rename to arch/powerpc/kernel/swsusp_32.S
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index cd75ab2..ec274e6 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -24,7 +24,6 @@
 #include <linux/resource.h>
 #include <linux/times.h>
 #include <linux/utsname.h>
-#include <linux/timex.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/sem.h>
@@ -161,78 +160,6 @@
 	return sys_sysfs((int)option, arg1, arg2);
 }
 
-/* Handle adjtimex compatibility. */
-struct timex32 {
-	u32 modes;
-	s32 offset, freq, maxerror, esterror;
-	s32 status, constant, precision, tolerance;
-	struct compat_timeval time;
-	s32 tick;
-	s32 ppsfreq, jitter, shift, stabil;
-	s32 jitcnt, calcnt, errcnt, stbcnt;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-};
-
-extern int do_adjtimex(struct timex *);
-
-asmlinkage long compat_sys_adjtimex(struct timex32 __user *utp)
-{
-	struct timex txc;
-	int ret;
-	
-	memset(&txc, 0, sizeof(struct timex));
-
-	if(get_user(txc.modes, &utp->modes) ||
-	   __get_user(txc.offset, &utp->offset) ||
-	   __get_user(txc.freq, &utp->freq) ||
-	   __get_user(txc.maxerror, &utp->maxerror) ||
-	   __get_user(txc.esterror, &utp->esterror) ||
-	   __get_user(txc.status, &utp->status) ||
-	   __get_user(txc.constant, &utp->constant) ||
-	   __get_user(txc.precision, &utp->precision) ||
-	   __get_user(txc.tolerance, &utp->tolerance) ||
-	   __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	   __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	   __get_user(txc.tick, &utp->tick) ||
-	   __get_user(txc.ppsfreq, &utp->ppsfreq) ||
-	   __get_user(txc.jitter, &utp->jitter) ||
-	   __get_user(txc.shift, &utp->shift) ||
-	   __get_user(txc.stabil, &utp->stabil) ||
-	   __get_user(txc.jitcnt, &utp->jitcnt) ||
-	   __get_user(txc.calcnt, &utp->calcnt) ||
-	   __get_user(txc.errcnt, &utp->errcnt) ||
-	   __get_user(txc.stbcnt, &utp->stbcnt))
-		return -EFAULT;
-
-	ret = do_adjtimex(&txc);
-
-	if(put_user(txc.modes, &utp->modes) ||
-	   __put_user(txc.offset, &utp->offset) ||
-	   __put_user(txc.freq, &utp->freq) ||
-	   __put_user(txc.maxerror, &utp->maxerror) ||
-	   __put_user(txc.esterror, &utp->esterror) ||
-	   __put_user(txc.status, &utp->status) ||
-	   __put_user(txc.constant, &utp->constant) ||
-	   __put_user(txc.precision, &utp->precision) ||
-	   __put_user(txc.tolerance, &utp->tolerance) ||
-	   __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	   __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	   __put_user(txc.tick, &utp->tick) ||
-	   __put_user(txc.ppsfreq, &utp->ppsfreq) ||
-	   __put_user(txc.jitter, &utp->jitter) ||
-	   __put_user(txc.shift, &utp->shift) ||
-	   __put_user(txc.stabil, &utp->stabil) ||
-	   __put_user(txc.jitcnt, &utp->jitcnt) ||
-	   __put_user(txc.calcnt, &utp->calcnt) ||
-	   __put_user(txc.errcnt, &utp->errcnt) ||
-	   __put_user(txc.stbcnt, &utp->stbcnt))
-		ret = -EFAULT;
-
-	return ret;
-}
-
 asmlinkage long compat_sys_pause(void)
 {
 	current->state = TASK_INTERRUPTIBLE;
diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c
index ad895c9..9b69d99 100644
--- a/arch/powerpc/kernel/syscalls.c
+++ b/arch/powerpc/kernel/syscalls.c
@@ -40,6 +40,7 @@
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
 #include <asm/semaphore.h>
+#include <asm/syscalls.h>
 #include <asm/time.h>
 #include <asm/unistd.h>
 
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index 0f0c3a9..73560ef 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -65,20 +65,20 @@
 	unsigned int cpu;
 
 	if (!cpu_has_feature(CPU_FTR_SMT))
-		return 1;
+		return -ENODEV;
 
 	options = find_path_device("/options");
 	if (!options)
-		return 1;
+		return -ENODEV;
 
 	val = (unsigned int *)get_property(options, "ibm,smt-snooze-delay",
 					   NULL);
 	if (!smt_snooze_cmdline && val) {
-		for_each_cpu(cpu)
+		for_each_possible_cpu(cpu)
 			per_cpu(smt_snooze_delay, cpu) = *val;
 	}
 
-	return 1;
+	return 0;
 }
 __initcall(smt_setup);
 
@@ -93,7 +93,7 @@
 	smt_snooze_cmdline = 1;
 
 	if (get_option(&str, &snooze)) {
-		for_each_cpu(cpu)
+		for_each_possible_cpu(cpu)
 			per_cpu(smt_snooze_delay, cpu) = snooze;
 	}
 
@@ -347,7 +347,7 @@
 
 	register_cpu_notifier(&sysfs_cpu_nb);
 
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		struct cpu *c = &per_cpu(cpu_devices, cpu);
 
 #ifdef CONFIG_NUMA
diff --git a/arch/ppc/kernel/temp.c b/arch/powerpc/kernel/tau_6xx.c
similarity index 100%
rename from arch/ppc/kernel/temp.c
rename to arch/powerpc/kernel/tau_6xx.c
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 4a27218..24e3ad7 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -261,7 +261,7 @@
 
 	if (!cpu_has_feature(CPU_FTR_PURR))
 		return;
-	for_each_cpu(cpu)
+	for_each_possible_cpu(cpu)
 		spin_lock_init(&per_cpu(cpu_purr_data, cpu).lock);
 	on_each_cpu(snapshot_tb_and_purr, NULL, 0, 1);
 }
@@ -751,7 +751,7 @@
 	 * systems works better if the two threads' timebase interrupts
 	 * are staggered by half a jiffy with respect to each other.
 	 */
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		if (i == boot_cpuid)
 			continue;
 		if (i == (boot_cpuid ^ 1))
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 98660ae..4cbde21 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -74,19 +74,19 @@
 EXPORT_SYMBOL(__debugger_fault_handler);
 #endif
 
-struct notifier_block *powerpc_die_chain;
-static DEFINE_SPINLOCK(die_notifier_lock);
+ATOMIC_NOTIFIER_HEAD(powerpc_die_chain);
 
 int register_die_notifier(struct notifier_block *nb)
 {
-	int err = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&die_notifier_lock, flags);
-	err = notifier_chain_register(&powerpc_die_chain, nb);
-	spin_unlock_irqrestore(&die_notifier_lock, flags);
-	return err;
+	return atomic_notifier_chain_register(&powerpc_die_chain, nb);
 }
+EXPORT_SYMBOL(register_die_notifier);
+
+int unregister_die_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&powerpc_die_chain, nb);
+}
+EXPORT_SYMBOL(unregister_die_notifier);
 
 /*
  * Trap & Exception support
@@ -97,7 +97,6 @@
 int die(const char *str, struct pt_regs *regs, long err)
 {
 	static int die_counter, crash_dump_start = 0;
-	int nl = 0;
 
 	if (debugger(regs))
 		return 1;
@@ -106,7 +105,7 @@
 	spin_lock_irq(&die_lock);
 	bust_spinlocks(1);
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if (_machine == _MACH_Pmac) {
+	if (machine_is(powermac)) {
 		set_backlight_enable(1);
 		set_backlight_level(BACKLIGHT_MAX);
 	}
@@ -114,46 +113,18 @@
 	printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
 #ifdef CONFIG_PREEMPT
 	printk("PREEMPT ");
-	nl = 1;
 #endif
 #ifdef CONFIG_SMP
 	printk("SMP NR_CPUS=%d ", NR_CPUS);
-	nl = 1;
 #endif
 #ifdef CONFIG_DEBUG_PAGEALLOC
 	printk("DEBUG_PAGEALLOC ");
-	nl = 1;
 #endif
 #ifdef CONFIG_NUMA
 	printk("NUMA ");
-	nl = 1;
 #endif
-#ifdef CONFIG_PPC64
-	switch (_machine) {
-	case PLATFORM_PSERIES:
-		printk("PSERIES ");
-		nl = 1;
-		break;
-	case PLATFORM_PSERIES_LPAR:
-		printk("PSERIES LPAR ");
-		nl = 1;
-		break;
-	case PLATFORM_ISERIES_LPAR:
-		printk("ISERIES LPAR ");
-		nl = 1;
-		break;
-	case PLATFORM_POWERMAC:
-		printk("POWERMAC ");
-		nl = 1;
-		break;
-	case PLATFORM_CELL:
-		printk("CELL ");
-		nl = 1;
-		break;
-	}
-#endif
-	if (nl)
-		printk("\n");
+	printk("%s\n", ppc_md.name ? "" : ppc_md.name);
+
 	print_modules();
 	show_regs(regs);
 	bust_spinlocks(0);
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index ec83703..573afb6 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -33,6 +33,7 @@
 #include <asm/machdep.h>
 #include <asm/cputable.h>
 #include <asm/sections.h>
+#include <asm/firmware.h>
 #include <asm/vdso.h>
 #include <asm/vdso_datapage.h>
 
@@ -667,7 +668,13 @@
 	vdso_data->version.major = SYSTEMCFG_MAJOR;
 	vdso_data->version.minor = SYSTEMCFG_MINOR;
 	vdso_data->processor = mfspr(SPRN_PVR);
-	vdso_data->platform = _machine;
+	/*
+	 * Fake the old platform number for pSeries and iSeries and add
+	 * in LPAR bit if necessary
+	 */
+	vdso_data->platform = machine_is(iseries) ? 0x200 : 0x100;
+	if (firmware_has_feature(FW_FEATURE_LPAR))
+		vdso_data->platform |= 1;
 	vdso_data->physicalMemorySize = lmb_phys_mem_size();
 	vdso_data->dcache_size = ppc64_caches.dsize;
 	vdso_data->dcache_line_size = ppc64_caches.dline_size;
diff --git a/arch/powerpc/kernel/vdso32/sigtramp.S b/arch/powerpc/kernel/vdso32/sigtramp.S
index e046427..0c6a37b 100644
--- a/arch/powerpc/kernel/vdso32/sigtramp.S
+++ b/arch/powerpc/kernel/vdso32/sigtramp.S
@@ -261,7 +261,7 @@
 .Lcie_start:
 	.long 0			/* CIE ID */
 	.byte 1			/* Version number */
-	.string "zR"		/* NUL-terminated augmentation string */
+	.string "zRS"		/* NUL-terminated augmentation string */
 	.uleb128 4		/* Code alignment factor */
 	.sleb128 -4		/* Data alignment factor */
 	.byte 67		/* Return address register column, ap */
diff --git a/arch/powerpc/kernel/vdso64/sigtramp.S b/arch/powerpc/kernel/vdso64/sigtramp.S
index 31b604a..7479edb 100644
--- a/arch/powerpc/kernel/vdso64/sigtramp.S
+++ b/arch/powerpc/kernel/vdso64/sigtramp.S
@@ -263,7 +263,7 @@
 .Lcie_start:
 	.long 0			/* CIE ID */
 	.byte 1			/* Version number */
-	.string "zR"		/* NUL-terminated augmentation string */
+	.string "zRS"		/* NUL-terminated augmentation string */
 	.uleb128 4		/* Code alignment factor */
 	.sleb128 -8		/* Data alignment factor */
 	.byte 67		/* Return address register column, ap */
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 7fa7b15..fe79c258 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -1,9 +1,11 @@
 #include <linux/config.h>
 #ifdef CONFIG_PPC64
 #include <asm/page.h>
+#define PROVIDE32(x)	PROVIDE(__unused__##x)
 #else
 #define PAGE_SIZE	4096
 #define KERNELBASE	CONFIG_KERNEL_START
+#define PROVIDE32(x)	PROVIDE(x)
 #endif
 #include <asm-generic/vmlinux.lds.h>
 
@@ -18,43 +20,42 @@
 #endif
 SECTIONS
 {
-  /* Sections to be discarded. */
-  /DISCARD/ : {
-    *(.exitcall.exit)
-    *(.exit.data)
-  }
+	/* Sections to be discarded. */
+	/DISCARD/ : {
+	*(.exitcall.exit)
+	*(.exit.data)
+	}
 
-  . = KERNELBASE;
+	. = KERNELBASE;
 
-  /* Read-only sections, merged into text segment: */
-  .text : {
-    *(.text .text.*)
-    SCHED_TEXT
-    LOCK_TEXT
-    KPROBES_TEXT
-    *(.fixup)
+/*
+ * Text, read only data and other permanent read-only sections
+ */
+
+	/* Text and gots */
+	.text : {
+		*(.text .text.*)
+		SCHED_TEXT
+		LOCK_TEXT
+		KPROBES_TEXT
+		*(.fixup)
+
 #ifdef CONFIG_PPC32
-    *(.got1)
-    __got2_start = .;
-    *(.got2)
-    __got2_end = .;
-#else
-    . = ALIGN(PAGE_SIZE);
-    _etext = .;
-#endif
-  }
-#ifdef CONFIG_PPC32
-  _etext = .;
-  PROVIDE (etext = .);
+		*(.got1)
+		__got2_start = .;
+		*(.got2)
+		__got2_end = .;
+#endif /* CONFIG_PPC32 */
 
-  RODATA
-  .fini      : { *(.fini)    } =0
-  .ctors     : { *(.ctors)   }
-  .dtors     : { *(.dtors)   }
+		. = ALIGN(PAGE_SIZE);
+		_etext = .;
+		PROVIDE32 (etext = .);
+	}
 
-  .fixup   : { *(.fixup) }
-#endif
+	/* Read-only data */
+	RODATA
 
+	/* Exception & bug tables */
 	__ex_table : {
 		__start___ex_table = .;
 		*(__ex_table)
@@ -67,192 +68,172 @@
 		__stop___bug_table = .;
 	}
 
-#ifdef CONFIG_PPC64
+/*
+ * Init sections discarded at runtime
+ */
+	. = ALIGN(PAGE_SIZE);
+	__init_begin = .;
+
+	.init.text : {
+		_sinittext = .;
+		*(.init.text)
+		_einittext = .;
+	}
+
+	/* .exit.text is discarded at runtime, not link time,
+	 * to deal with references from __bug_table
+	 */
+	.exit.text : { *(.exit.text) }
+
+	.init.data : {
+		*(.init.data);
+		__vtop_table_begin = .;
+		*(.vtop_fixup);
+		__vtop_table_end = .;
+		__ptov_table_begin = .;
+		*(.ptov_fixup);
+		__ptov_table_end = .;
+	}
+
+	. = ALIGN(16);
+	.init.setup : {
+		__setup_start = .;
+		*(.init.setup)
+		__setup_end = .;
+	}
+
+	.initcall.init : {
+		__initcall_start = .;
+		*(.initcall1.init)
+		*(.initcall2.init)
+		*(.initcall3.init)
+		*(.initcall4.init)
+		*(.initcall5.init)
+		*(.initcall6.init)
+		*(.initcall7.init)
+		__initcall_end = .;
+		}
+
+	.con_initcall.init : {
+		__con_initcall_start = .;
+		*(.con_initcall.init)
+		__con_initcall_end = .;
+	}
+
+	SECURITY_INIT
+
+	. = ALIGN(8);
 	__ftr_fixup : {
 		__start___ftr_fixup = .;
 		*(__ftr_fixup)
 		__stop___ftr_fixup = .;
 	}
 
-  RODATA
-#endif
+	. = ALIGN(PAGE_SIZE);
+	.init.ramfs : {
+		__initramfs_start = .;
+		*(.init.ramfs)
+		__initramfs_end = .;
+	}
 
 #ifdef CONFIG_PPC32
-  /* Read-write section, merged into data segment: */
-  . = ALIGN(PAGE_SIZE);
-  _sdata = .;
-  .data    :
-  {
-    *(.data)
-    *(.data1)
-    *(.sdata)
-    *(.sdata2)
-    *(.got.plt) *(.got)
-    *(.dynamic)
-    CONSTRUCTORS
-  }
-
-  . = ALIGN(PAGE_SIZE);
-  __nosave_begin = .;
-  .data_nosave : { *(.data.nosave) }
-  . = ALIGN(PAGE_SIZE);
-  __nosave_end = .;
-
-  . = ALIGN(32);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
-  _edata  =  .;
-  PROVIDE (edata = .);
-
-  . = ALIGN(8192);
-  .data.init_task : { *(.data.init_task) }
-#endif
-
-  /* will be freed after init */
-  . = ALIGN(PAGE_SIZE);
-  __init_begin = .;
-  .init.text : {
-	_sinittext = .;
-	*(.init.text)
-	_einittext = .;
-  }
-#ifdef CONFIG_PPC32
-  /* .exit.text is discarded at runtime, not link time,
-     to deal with references from __bug_table */
-  .exit.text : { *(.exit.text) }
-#endif
-  .init.data : {
-    *(.init.data);
-    __vtop_table_begin = .;
-    *(.vtop_fixup);
-    __vtop_table_end = .;
-    __ptov_table_begin = .;
-    *(.ptov_fixup);
-    __ptov_table_end = .;
-  }
-
-  . = ALIGN(16);
-  .init.setup : {
-    __setup_start = .;
-    *(.init.setup)
-    __setup_end = .;
-  }
-
-  .initcall.init : {
-	__initcall_start = .;
-	*(.initcall1.init)
-	*(.initcall2.init)
-	*(.initcall3.init)
-	*(.initcall4.init)
-	*(.initcall5.init)
-	*(.initcall6.init)
-	*(.initcall7.init)
-	__initcall_end = .;
-  }
-
-  .con_initcall.init : {
-    __con_initcall_start = .;
-    *(.con_initcall.init)
-    __con_initcall_end = .;
-  }
-
-  SECURITY_INIT
-
-#ifdef CONFIG_PPC32
-  __start___ftr_fixup = .;
-  __ftr_fixup : { *(__ftr_fixup) }
-  __stop___ftr_fixup = .;
+	. = ALIGN(32);
 #else
-  . = ALIGN(PAGE_SIZE);
-  .init.ramfs : {
-    __initramfs_start = .;
-    *(.init.ramfs)
-    __initramfs_end = .;
-  }
+	. = ALIGN(128);
 #endif
+	.data.percpu : {
+		__per_cpu_start = .;
+		*(.data.percpu)
+		__per_cpu_end = .;
+	}
+
+	. = ALIGN(8);
+	.machine.desc : {
+		__machine_desc_start = . ;
+		*(.machine.desc)
+		__machine_desc_end = . ;
+	}
+
+	/* freed after init ends here */
+	. = ALIGN(PAGE_SIZE);
+	__init_end = .;
+
+/*
+ * And now the various read/write data
+ */
+
+	. = ALIGN(PAGE_SIZE);
+	_sdata = .;
 
 #ifdef CONFIG_PPC32
-  . = ALIGN(32);
-#endif
-  .data.percpu : {
-    __per_cpu_start = .;
-    *(.data.percpu)
-    __per_cpu_end = .;
-  }
-
- . = ALIGN(PAGE_SIZE);
-#ifdef CONFIG_PPC64
- . = ALIGN(16384);
- __init_end = .;
- /* freed after init ends here */
-
- /* Read/write sections */
- . = ALIGN(PAGE_SIZE);
- . = ALIGN(16384);
- _sdata = .;
- /* The initial task and kernel stack */
- .data.init_task : {
-      *(.data.init_task)
-      }
-
- . = ALIGN(PAGE_SIZE);
- .data.page_aligned : {
-      *(.data.page_aligned)
-      }
-
- .data.cacheline_aligned : {
-      *(.data.cacheline_aligned)
-      }
-
- .data : {
-      *(.data .data.rel* .toc1)
-      *(.branch_lt)
-      }
-
- .opd : {
-      *(.opd)
-      }
-
- .got : {
-      __toc_start = .;
-      *(.got)
-      *(.toc)
-      . = ALIGN(PAGE_SIZE);
-      _edata = .;
-      }
-
-  . = ALIGN(PAGE_SIZE);
+	.data    :
+	{
+		*(.data)
+		*(.sdata)
+		*(.got.plt) *(.got)
+	}
 #else
-  __initramfs_start = .;
-  .init.ramfs : {
-    *(.init.ramfs)
-  }
-  __initramfs_end = .;
+	.data : {
+		*(.data .data.rel* .toc1)
+		*(.branch_lt)
+	}
 
-  . = ALIGN(4096);
-  __init_end = .;
+	.opd : {
+		*(.opd)
+	}
 
-  . = ALIGN(4096);
-  _sextratext = .;
-  _eextratext = .;
-
-  __bss_start = .;
+	.got : {
+		__toc_start = .;
+		*(.got)
+		*(.toc)
+	}
 #endif
 
-  .bss : {
-    __bss_start = .;
-   *(.sbss) *(.scommon)
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-  __bss_stop = .;
-  }
+	. = ALIGN(PAGE_SIZE);
+	_edata  =  .;
+	PROVIDE32 (edata = .);
 
-#ifdef CONFIG_PPC64
-  . = ALIGN(PAGE_SIZE);
-#endif
-  _end = . ;
+	/* The initial task and kernel stack */
 #ifdef CONFIG_PPC32
-  PROVIDE (end = .);
+	. = ALIGN(8192);
+#else
+	. = ALIGN(16384);
 #endif
+	.data.init_task : {
+		*(.data.init_task)
+	}
+
+	. = ALIGN(PAGE_SIZE);
+	.data.page_aligned : {
+		*(.data.page_aligned)
+	}
+
+	.data.cacheline_aligned : {
+		*(.data.cacheline_aligned)
+	}
+
+	. = ALIGN(PAGE_SIZE);
+	__data_nosave : {
+		__nosave_begin = .;
+		*(.data.nosave)
+		. = ALIGN(PAGE_SIZE);
+		__nosave_end = .;
+	}
+
+/*
+ * And finally the bss
+ */
+
+	.bss : {
+		__bss_start = .;
+		*(.sbss) *(.scommon)
+		*(.dynbss)
+		*(.bss)
+		*(COMMON)
+		__bss_stop = .;
+	}
+
+	. = ALIGN(PAGE_SIZE);
+	_end = . ;
+	PROVIDE32 (end = .);
 }
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 666c2aa..c251d99 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -18,7 +18,7 @@
 
 #ifdef CONFIG_PPC64
 /* Bits in SRR1 that are copied from MSR */
-#define MSR_MASK	0xffffffff87c0ffff
+#define MSR_MASK	0xffffffff87c0ffffUL
 #else
 #define MSR_MASK	0x87c0ffff
 #endif
diff --git a/arch/ppc/math-emu/Makefile b/arch/powerpc/math-emu/Makefile
similarity index 100%
rename from arch/ppc/math-emu/Makefile
rename to arch/powerpc/math-emu/Makefile
diff --git a/arch/ppc/math-emu/double.h b/arch/powerpc/math-emu/double.h
similarity index 100%
rename from arch/ppc/math-emu/double.h
rename to arch/powerpc/math-emu/double.h
diff --git a/arch/ppc/math-emu/fabs.c b/arch/powerpc/math-emu/fabs.c
similarity index 100%
rename from arch/ppc/math-emu/fabs.c
rename to arch/powerpc/math-emu/fabs.c
diff --git a/arch/ppc/math-emu/fadd.c b/arch/powerpc/math-emu/fadd.c
similarity index 100%
rename from arch/ppc/math-emu/fadd.c
rename to arch/powerpc/math-emu/fadd.c
diff --git a/arch/ppc/math-emu/fadds.c b/arch/powerpc/math-emu/fadds.c
similarity index 100%
rename from arch/ppc/math-emu/fadds.c
rename to arch/powerpc/math-emu/fadds.c
diff --git a/arch/ppc/math-emu/fcmpo.c b/arch/powerpc/math-emu/fcmpo.c
similarity index 100%
rename from arch/ppc/math-emu/fcmpo.c
rename to arch/powerpc/math-emu/fcmpo.c
diff --git a/arch/ppc/math-emu/fcmpu.c b/arch/powerpc/math-emu/fcmpu.c
similarity index 100%
rename from arch/ppc/math-emu/fcmpu.c
rename to arch/powerpc/math-emu/fcmpu.c
diff --git a/arch/ppc/math-emu/fctiw.c b/arch/powerpc/math-emu/fctiw.c
similarity index 100%
rename from arch/ppc/math-emu/fctiw.c
rename to arch/powerpc/math-emu/fctiw.c
diff --git a/arch/ppc/math-emu/fctiwz.c b/arch/powerpc/math-emu/fctiwz.c
similarity index 100%
rename from arch/ppc/math-emu/fctiwz.c
rename to arch/powerpc/math-emu/fctiwz.c
diff --git a/arch/ppc/math-emu/fdiv.c b/arch/powerpc/math-emu/fdiv.c
similarity index 100%
rename from arch/ppc/math-emu/fdiv.c
rename to arch/powerpc/math-emu/fdiv.c
diff --git a/arch/ppc/math-emu/fdivs.c b/arch/powerpc/math-emu/fdivs.c
similarity index 100%
rename from arch/ppc/math-emu/fdivs.c
rename to arch/powerpc/math-emu/fdivs.c
diff --git a/arch/ppc/math-emu/fmadd.c b/arch/powerpc/math-emu/fmadd.c
similarity index 100%
rename from arch/ppc/math-emu/fmadd.c
rename to arch/powerpc/math-emu/fmadd.c
diff --git a/arch/ppc/math-emu/fmadds.c b/arch/powerpc/math-emu/fmadds.c
similarity index 100%
rename from arch/ppc/math-emu/fmadds.c
rename to arch/powerpc/math-emu/fmadds.c
diff --git a/arch/ppc/math-emu/fmr.c b/arch/powerpc/math-emu/fmr.c
similarity index 100%
rename from arch/ppc/math-emu/fmr.c
rename to arch/powerpc/math-emu/fmr.c
diff --git a/arch/ppc/math-emu/fmsub.c b/arch/powerpc/math-emu/fmsub.c
similarity index 100%
rename from arch/ppc/math-emu/fmsub.c
rename to arch/powerpc/math-emu/fmsub.c
diff --git a/arch/ppc/math-emu/fmsubs.c b/arch/powerpc/math-emu/fmsubs.c
similarity index 100%
rename from arch/ppc/math-emu/fmsubs.c
rename to arch/powerpc/math-emu/fmsubs.c
diff --git a/arch/ppc/math-emu/fmul.c b/arch/powerpc/math-emu/fmul.c
similarity index 100%
rename from arch/ppc/math-emu/fmul.c
rename to arch/powerpc/math-emu/fmul.c
diff --git a/arch/ppc/math-emu/fmuls.c b/arch/powerpc/math-emu/fmuls.c
similarity index 100%
rename from arch/ppc/math-emu/fmuls.c
rename to arch/powerpc/math-emu/fmuls.c
diff --git a/arch/ppc/math-emu/fnabs.c b/arch/powerpc/math-emu/fnabs.c
similarity index 100%
rename from arch/ppc/math-emu/fnabs.c
rename to arch/powerpc/math-emu/fnabs.c
diff --git a/arch/ppc/math-emu/fneg.c b/arch/powerpc/math-emu/fneg.c
similarity index 100%
rename from arch/ppc/math-emu/fneg.c
rename to arch/powerpc/math-emu/fneg.c
diff --git a/arch/ppc/math-emu/fnmadd.c b/arch/powerpc/math-emu/fnmadd.c
similarity index 100%
rename from arch/ppc/math-emu/fnmadd.c
rename to arch/powerpc/math-emu/fnmadd.c
diff --git a/arch/ppc/math-emu/fnmadds.c b/arch/powerpc/math-emu/fnmadds.c
similarity index 100%
rename from arch/ppc/math-emu/fnmadds.c
rename to arch/powerpc/math-emu/fnmadds.c
diff --git a/arch/ppc/math-emu/fnmsub.c b/arch/powerpc/math-emu/fnmsub.c
similarity index 100%
rename from arch/ppc/math-emu/fnmsub.c
rename to arch/powerpc/math-emu/fnmsub.c
diff --git a/arch/ppc/math-emu/fnmsubs.c b/arch/powerpc/math-emu/fnmsubs.c
similarity index 100%
rename from arch/ppc/math-emu/fnmsubs.c
rename to arch/powerpc/math-emu/fnmsubs.c
diff --git a/arch/ppc/math-emu/fres.c b/arch/powerpc/math-emu/fres.c
similarity index 100%
rename from arch/ppc/math-emu/fres.c
rename to arch/powerpc/math-emu/fres.c
diff --git a/arch/ppc/math-emu/frsp.c b/arch/powerpc/math-emu/frsp.c
similarity index 100%
rename from arch/ppc/math-emu/frsp.c
rename to arch/powerpc/math-emu/frsp.c
diff --git a/arch/ppc/math-emu/frsqrte.c b/arch/powerpc/math-emu/frsqrte.c
similarity index 100%
rename from arch/ppc/math-emu/frsqrte.c
rename to arch/powerpc/math-emu/frsqrte.c
diff --git a/arch/ppc/math-emu/fsel.c b/arch/powerpc/math-emu/fsel.c
similarity index 100%
rename from arch/ppc/math-emu/fsel.c
rename to arch/powerpc/math-emu/fsel.c
diff --git a/arch/ppc/math-emu/fsqrt.c b/arch/powerpc/math-emu/fsqrt.c
similarity index 100%
rename from arch/ppc/math-emu/fsqrt.c
rename to arch/powerpc/math-emu/fsqrt.c
diff --git a/arch/ppc/math-emu/fsqrts.c b/arch/powerpc/math-emu/fsqrts.c
similarity index 100%
rename from arch/ppc/math-emu/fsqrts.c
rename to arch/powerpc/math-emu/fsqrts.c
diff --git a/arch/ppc/math-emu/fsub.c b/arch/powerpc/math-emu/fsub.c
similarity index 100%
rename from arch/ppc/math-emu/fsub.c
rename to arch/powerpc/math-emu/fsub.c
diff --git a/arch/ppc/math-emu/fsubs.c b/arch/powerpc/math-emu/fsubs.c
similarity index 100%
rename from arch/ppc/math-emu/fsubs.c
rename to arch/powerpc/math-emu/fsubs.c
diff --git a/arch/ppc/math-emu/lfd.c b/arch/powerpc/math-emu/lfd.c
similarity index 100%
rename from arch/ppc/math-emu/lfd.c
rename to arch/powerpc/math-emu/lfd.c
diff --git a/arch/ppc/math-emu/lfs.c b/arch/powerpc/math-emu/lfs.c
similarity index 100%
rename from arch/ppc/math-emu/lfs.c
rename to arch/powerpc/math-emu/lfs.c
diff --git a/arch/ppc/math-emu/math.c b/arch/powerpc/math-emu/math.c
similarity index 100%
rename from arch/ppc/math-emu/math.c
rename to arch/powerpc/math-emu/math.c
diff --git a/arch/ppc/math-emu/mcrfs.c b/arch/powerpc/math-emu/mcrfs.c
similarity index 100%
rename from arch/ppc/math-emu/mcrfs.c
rename to arch/powerpc/math-emu/mcrfs.c
diff --git a/arch/ppc/math-emu/mffs.c b/arch/powerpc/math-emu/mffs.c
similarity index 100%
rename from arch/ppc/math-emu/mffs.c
rename to arch/powerpc/math-emu/mffs.c
diff --git a/arch/ppc/math-emu/mtfsb0.c b/arch/powerpc/math-emu/mtfsb0.c
similarity index 100%
rename from arch/ppc/math-emu/mtfsb0.c
rename to arch/powerpc/math-emu/mtfsb0.c
diff --git a/arch/ppc/math-emu/mtfsb1.c b/arch/powerpc/math-emu/mtfsb1.c
similarity index 100%
rename from arch/ppc/math-emu/mtfsb1.c
rename to arch/powerpc/math-emu/mtfsb1.c
diff --git a/arch/ppc/math-emu/mtfsf.c b/arch/powerpc/math-emu/mtfsf.c
similarity index 100%
rename from arch/ppc/math-emu/mtfsf.c
rename to arch/powerpc/math-emu/mtfsf.c
diff --git a/arch/ppc/math-emu/mtfsfi.c b/arch/powerpc/math-emu/mtfsfi.c
similarity index 100%
rename from arch/ppc/math-emu/mtfsfi.c
rename to arch/powerpc/math-emu/mtfsfi.c
diff --git a/arch/ppc/math-emu/op-1.h b/arch/powerpc/math-emu/op-1.h
similarity index 100%
rename from arch/ppc/math-emu/op-1.h
rename to arch/powerpc/math-emu/op-1.h
diff --git a/arch/ppc/math-emu/op-2.h b/arch/powerpc/math-emu/op-2.h
similarity index 100%
rename from arch/ppc/math-emu/op-2.h
rename to arch/powerpc/math-emu/op-2.h
diff --git a/arch/ppc/math-emu/op-4.h b/arch/powerpc/math-emu/op-4.h
similarity index 100%
rename from arch/ppc/math-emu/op-4.h
rename to arch/powerpc/math-emu/op-4.h
diff --git a/arch/ppc/math-emu/op-common.h b/arch/powerpc/math-emu/op-common.h
similarity index 100%
rename from arch/ppc/math-emu/op-common.h
rename to arch/powerpc/math-emu/op-common.h
diff --git a/arch/ppc/math-emu/sfp-machine.h b/arch/powerpc/math-emu/sfp-machine.h
similarity index 100%
rename from arch/ppc/math-emu/sfp-machine.h
rename to arch/powerpc/math-emu/sfp-machine.h
diff --git a/arch/ppc/math-emu/single.h b/arch/powerpc/math-emu/single.h
similarity index 100%
rename from arch/ppc/math-emu/single.h
rename to arch/powerpc/math-emu/single.h
diff --git a/arch/ppc/math-emu/soft-fp.h b/arch/powerpc/math-emu/soft-fp.h
similarity index 100%
rename from arch/ppc/math-emu/soft-fp.h
rename to arch/powerpc/math-emu/soft-fp.h
diff --git a/arch/ppc/math-emu/stfd.c b/arch/powerpc/math-emu/stfd.c
similarity index 100%
rename from arch/ppc/math-emu/stfd.c
rename to arch/powerpc/math-emu/stfd.c
diff --git a/arch/ppc/math-emu/stfiwx.c b/arch/powerpc/math-emu/stfiwx.c
similarity index 100%
rename from arch/ppc/math-emu/stfiwx.c
rename to arch/powerpc/math-emu/stfiwx.c
diff --git a/arch/ppc/math-emu/stfs.c b/arch/powerpc/math-emu/stfs.c
similarity index 100%
rename from arch/ppc/math-emu/stfs.c
rename to arch/powerpc/math-emu/stfs.c
diff --git a/arch/ppc/math-emu/types.c b/arch/powerpc/math-emu/types.c
similarity index 100%
rename from arch/ppc/math-emu/types.c
rename to arch/powerpc/math-emu/types.c
diff --git a/arch/ppc/math-emu/udivmodti4.c b/arch/powerpc/math-emu/udivmodti4.c
similarity index 100%
rename from arch/ppc/math-emu/udivmodti4.c
rename to arch/powerpc/math-emu/udivmodti4.c
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index ec4adcb..5aea090 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -267,25 +267,29 @@
 #endif
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
 		pte_t *ptep;
+		pmd_t *pmdp;
 
 		/* Since 4xx/Book-E supports per-page execute permission,
 		 * we lazily flush dcache to icache. */
 		ptep = NULL;
-		if (get_pteptr(mm, address, &ptep) && pte_present(*ptep)) {
-			struct page *page = pte_page(*ptep);
+		if (get_pteptr(mm, address, &ptep, &pmdp)) {
+			spinlock_t *ptl = pte_lockptr(mm, pmdp);
+			spin_lock(ptl);
+			if (pte_present(*ptep)) {
+				struct page *page = pte_page(*ptep);
 
-			if (! test_bit(PG_arch_1, &page->flags)) {
-				flush_dcache_icache_page(page);
-				set_bit(PG_arch_1, &page->flags);
+				if (!test_bit(PG_arch_1, &page->flags)) {
+					flush_dcache_icache_page(page);
+					set_bit(PG_arch_1, &page->flags);
+				}
+				pte_update(ptep, 0, _PAGE_HWEXEC);
+				_tlbie(address);
+				pte_unmap_unlock(ptep, ptl);
+				up_read(&mm->mmap_sem);
+				return 0;
 			}
-			pte_update(ptep, 0, _PAGE_HWEXEC);
-			_tlbie(address);
-			pte_unmap(ptep);
-			up_read(&mm->mmap_sem);
-			return 0;
+			pte_unmap_unlock(ptep, ptl);
 		}
-		if (ptep != NULL)
-			pte_unmap(ptep);
 #endif
 	/* a write */
 	} else if (is_write) {
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 89b35c1..c006d90 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -167,7 +167,7 @@
 		 * normal insert callback here.
 		 */
 #ifdef CONFIG_PPC_ISERIES
-		if (_machine == PLATFORM_ISERIES_LPAR)
+		if (machine_is(iseries))
 			ret = iSeries_hpte_insert(hpteg, va,
 						  paddr,
 						  tmp_mode,
@@ -176,7 +176,7 @@
 		else
 #endif
 #ifdef CONFIG_PPC_PSERIES
-		if (_machine & PLATFORM_LPAR)
+		if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR))
 			ret = pSeries_lpar_hpte_insert(hpteg, va,
 						       paddr,
 						       tmp_mode,
@@ -295,8 +295,7 @@
 	 * Not in the device-tree, let's fallback on known size
 	 * list for 16M capable GP & GR
 	 */
-	if ((_machine != PLATFORM_ISERIES_LPAR) &&
-	    cpu_has_feature(CPU_FTR_16M_PAGE))
+	if (cpu_has_feature(CPU_FTR_16M_PAGE) && !machine_is(iseries))
 		memcpy(mmu_psize_defs, mmu_psize_defaults_gp,
 		       sizeof(mmu_psize_defaults_gp));
  found:
diff --git a/arch/powerpc/mm/imalloc.c b/arch/powerpc/mm/imalloc.c
index 8b0c132..add8c1a 100644
--- a/arch/powerpc/mm/imalloc.c
+++ b/arch/powerpc/mm/imalloc.c
@@ -13,12 +13,12 @@
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/cacheflush.h>
 
 #include "mmu_decl.h"
 
-static DECLARE_MUTEX(imlist_sem);
+static DEFINE_MUTEX(imlist_mutex);
 struct vm_struct * imlist = NULL;
 
 static int get_free_im_addr(unsigned long size, unsigned long *im_addr)
@@ -257,7 +257,7 @@
 	struct vm_struct *area;
 	unsigned long addr;
 	
-	down(&imlist_sem);
+	mutex_lock(&imlist_mutex);
 	if (get_free_im_addr(size, &addr)) {
 		printk(KERN_ERR "%s() cannot obtain addr for size 0x%lx\n",
 				__FUNCTION__, size);
@@ -272,7 +272,7 @@
 			__FUNCTION__, addr, size);
 	}
 next_im_done:
-	up(&imlist_sem);
+	mutex_unlock(&imlist_mutex);
 	return area;
 }
 
@@ -281,9 +281,9 @@
 {
 	struct vm_struct *area;
 
-	down(&imlist_sem);
+	mutex_lock(&imlist_mutex);
 	area = __im_get_area(v_addr, size, criteria);
-	up(&imlist_sem);
+	mutex_unlock(&imlist_mutex);
 	return area;
 }
 
@@ -297,17 +297,17 @@
 		printk(KERN_ERR "Trying to %s bad address (%p)\n", __FUNCTION__,			addr);
 		return;
 	}
-	down(&imlist_sem);
+	mutex_lock(&imlist_mutex);
 	for (p = &imlist ; (tmp = *p) ; p = &tmp->next) {
 		if (tmp->addr == addr) {
 			*p = tmp->next;
 			unmap_vm_area(tmp);
 			kfree(tmp);
-			up(&imlist_sem);
+			mutex_unlock(&imlist_mutex);
 			return;
 		}
 	}
-	up(&imlist_sem);
+	mutex_unlock(&imlist_mutex);
 	printk(KERN_ERR "Trying to %s nonexistent area (%p)\n", __FUNCTION__,
 			addr);
 }
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index badac10..741dd88 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -195,7 +195,7 @@
 	printk("Mem-info:\n");
 	show_free_areas();
 	printk("Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
-	for_each_pgdat(pgdat) {
+	for_each_online_pgdat(pgdat) {
 		unsigned long flags;
 		pgdat_resize_lock(pgdat, &flags);
 		for (i = 0; i < pgdat->node_spanned_pages; i++) {
@@ -342,7 +342,7 @@
 #ifdef CONFIG_NEED_MULTIPLE_NODES
         for_each_online_node(nid) {
 		if (NODE_DATA(nid)->node_spanned_pages != 0) {
-			printk("freeing bootmem node %x\n", nid);
+			printk("freeing bootmem node %d\n", nid);
 			totalram_pages +=
 				free_all_bootmem_node(NODE_DATA(nid));
 		}
@@ -351,7 +351,7 @@
 	max_mapnr = max_pfn;
 	totalram_pages += free_all_bootmem();
 #endif
-	for_each_pgdat(pgdat) {
+	for_each_online_pgdat(pgdat) {
 		for (i = 0; i < pgdat->node_spanned_pages; i++) {
 			if (!pfn_valid(pgdat->node_start_pfn + i))
 				continue;
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index e89b22a..0a335f3 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -756,6 +756,7 @@
 	struct device_node *memory = NULL;
 	nodemask_t nodes;
 	int default_nid = any_online_node(NODE_MASK_ALL);
+	int nid;
 
 	if (!numa_enabled || (min_common_depth < 0))
 		return default_nid;
@@ -790,6 +791,7 @@
 			goto ha_new_range;
 	}
 	BUG();	/* section address should be found above */
+	return 0;
 
 	/* Temporary code to ensure that returned node is not empty */
 got_nid:
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index d296eb6..9062860 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -372,7 +372,7 @@
  * the PTE pointer is unmodified if PTE is not found.
  */
 int
-get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep)
+get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp)
 {
         pgd_t	*pgd;
         pmd_t	*pmd;
@@ -387,6 +387,8 @@
                         if (pte) {
 				retval = 1;
 				*ptep = pte;
+				if (pmdp)
+					*pmdp = pmd;
 				/* XXX caller needs to do pte_unmap, yuck */
                         }
                 }
@@ -424,7 +426,7 @@
 		mm = &init_mm;
 
 	pa = 0;
-	if (get_pteptr(mm, addr, &pte)) {
+	if (get_pteptr(mm, addr, &pte, NULL)) {
 		pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK);
 		pte_unmap(pte);
 	}
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c
index 91d25fb..4a9291d 100644
--- a/arch/powerpc/mm/stab.c
+++ b/arch/powerpc/mm/stab.c
@@ -239,7 +239,7 @@
 	if (cpu_has_feature(CPU_FTR_SLB))
 		return;
 
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		unsigned long newstab;
 
 		if (cpu == 0)
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index 554cd7c..f5f9859 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -6,7 +6,7 @@
 		oprofilefs.o oprofile_stats.o \
 		timer_int.o )
 
-oprofile-y := $(DRIVER_OBJS) common.o
+oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
 oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o
 oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
 oprofile-$(CONFIG_PPC32) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/backtrace.c b/arch/powerpc/oprofile/backtrace.c
new file mode 100644
index 0000000..75f57bc
--- /dev/null
+++ b/arch/powerpc/oprofile/backtrace.c
@@ -0,0 +1,126 @@
+/**
+ * Copyright (C) 2005 Brian Rogan <bcr6@cornell.edu>, IBM
+ *
+ * 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/oprofile.h>
+#include <linux/sched.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+
+#define STACK_SP(STACK)		*(STACK)
+
+#define STACK_LR64(STACK)	*((unsigned long *)(STACK) + 2)
+#define STACK_LR32(STACK)	*((unsigned int *)(STACK) + 1)
+
+#ifdef CONFIG_PPC64
+#define STACK_LR(STACK)		STACK_LR64(STACK)
+#else
+#define STACK_LR(STACK)		STACK_LR32(STACK)
+#endif
+
+static unsigned int user_getsp32(unsigned int sp, int is_first)
+{
+	unsigned int stack_frame[2];
+
+	if (!access_ok(VERIFY_READ, sp, sizeof(stack_frame)))
+		return 0;
+
+	/*
+	 * The most likely reason for this is that we returned -EFAULT,
+	 * which means that we've done all that we can do from
+	 * interrupt context.
+	 */
+	if (__copy_from_user_inatomic(stack_frame, (void *)(long)sp,
+					sizeof(stack_frame)))
+		return 0;
+
+	if (!is_first)
+		oprofile_add_trace(STACK_LR32(stack_frame));
+
+	/*
+	 * We do not enforce increasing stack addresses here because
+	 * we may transition to a different stack, eg a signal handler.
+	 */
+	return STACK_SP(stack_frame);
+}
+
+#ifdef CONFIG_PPC64
+static unsigned long user_getsp64(unsigned long sp, int is_first)
+{
+	unsigned long stack_frame[3];
+
+	if (!access_ok(VERIFY_READ, sp, sizeof(stack_frame)))
+		return 0;
+
+	if (__copy_from_user_inatomic(stack_frame, (void *)sp,
+					sizeof(stack_frame)))
+		return 0;
+
+	if (!is_first)
+		oprofile_add_trace(STACK_LR64(stack_frame));
+
+	return STACK_SP(stack_frame);
+}
+#endif
+
+static unsigned long kernel_getsp(unsigned long sp, int is_first)
+{
+	unsigned long *stack_frame = (unsigned long *)sp;
+
+	if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
+		return 0;
+
+	if (!is_first)
+		oprofile_add_trace(STACK_LR(stack_frame));
+
+	/*
+	 * We do not enforce increasing stack addresses here because
+	 * we might be transitioning from an interrupt stack to a kernel
+	 * stack. validate_sp() is designed to understand this, so just
+	 * use it.
+	 */
+	return STACK_SP(stack_frame);
+}
+
+void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth)
+{
+	unsigned long sp = regs->gpr[1];
+	int first_frame = 1;
+
+	/* We ditch the top stackframe so need to loop through an extra time */
+	depth += 1;
+
+	if (!user_mode(regs)) {
+		while (depth--) {
+			sp = kernel_getsp(sp, first_frame);
+			if (!sp)
+				break;
+			first_frame = 0;
+		}
+	} else {
+#ifdef CONFIG_PPC64
+		if (!test_thread_flag(TIF_32BIT)) {
+			while (depth--) {
+				sp = user_getsp64(sp, first_frame);
+				if (!sp)
+					break;
+				first_frame = 0;
+			}
+
+			return;
+		}
+#endif
+
+		while (depth--) {
+			sp = user_getsp32(sp, first_frame);
+			if (!sp)
+				break;
+			first_frame = 0;
+		}
+	}
+}
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index cc2535b..5b1de7e 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -117,18 +117,10 @@
 
 	oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel);
 	oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user);
-#ifdef CONFIG_PPC64
-	oprofilefs_create_ulong(sb, root, "backtrace_spinlocks",
-				&sys.backtrace_spinlocks);
-#endif
 
 	/* Default to tracing both kernel and user */
 	sys.enable_kernel = 1;
 	sys.enable_user = 1;
-#ifdef CONFIG_PPC64
-	/* Turn on backtracing through spinlocks by default */
-	sys.backtrace_spinlocks = 1;
-#endif
 
 	return 0;
 }
@@ -168,6 +160,7 @@
 	ops->shutdown = op_powerpc_shutdown;
 	ops->start = op_powerpc_start;
 	ops->stop = op_powerpc_stop;
+	ops->backtrace = op_powerpc_backtrace;
 
 	printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
 	       ops->cpu_type);
diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c
index 32abfdb..e0491c3 100644
--- a/arch/powerpc/oprofile/op_model_7450.c
+++ b/arch/powerpc/oprofile/op_model_7450.c
@@ -176,13 +176,13 @@
 	mtmsr(mfmsr() | MSR_PMM);
 
 	pc = mfspr(SPRN_SIAR);
-	is_kernel = (pc >= KERNELBASE);
+	is_kernel = is_kernel_addr(pc);
 
 	for (i = 0; i < NUM_CTRS; ++i) {
 		val = ctr_read(i);
 		if (val < 0) {
 			if (oprofile_running && ctr[i].enabled) {
-				oprofile_add_pc(pc, is_kernel, i);
+				oprofile_add_ext_sample(pc, regs, i, is_kernel);
 				ctr_write(i, reset_value[i]);
 			} else {
 				ctr_write(i, 0);
diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c
index 26539cd..93d63e6 100644
--- a/arch/powerpc/oprofile/op_model_fsl_booke.c
+++ b/arch/powerpc/oprofile/op_model_fsl_booke.c
@@ -154,13 +154,13 @@
 	mtmsr(mfmsr() | MSR_PMM);
 
 	pc = regs->nip;
-	is_kernel = (pc >= KERNELBASE);
+	is_kernel = is_kernel_addr(pc);
 
 	for (i = 0; i < num_counters; ++i) {
 		val = ctr_read(i);
 		if (val < 0) {
 			if (oprofile_running && ctr[i].enabled) {
-				oprofile_add_pc(pc, is_kernel, i);
+				oprofile_add_ext_sample(pc, regs, i, is_kernel);
 				ctr_write(i, reset_value[i]);
 			} else {
 				ctr_write(i, 0);
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index 4b06e53..4c2beab 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -25,18 +25,14 @@
 
 static int oprofile_running;
 static int mmcra_has_sihv;
+/* Unfortunately these bits vary between CPUs */
+static unsigned long mmcra_sihv = MMCRA_SIHV;
+static unsigned long mmcra_sipr = MMCRA_SIPR;
 
 /* mmcr values are set in power4_reg_setup, used in power4_cpu_setup */
 static u32 mmcr0_val;
 static u64 mmcr1_val;
-static u32 mmcra_val;
-
-/*
- * Since we do not have an NMI, backtracing through spinlocks is
- * only a best guess. In light of this, allow it to be disabled at
- * runtime.
- */
-static int backtrace_spinlocks;
+static u64 mmcra_val;
 
 static void power4_reg_setup(struct op_counter_config *ctr,
 			     struct op_system_config *sys,
@@ -63,8 +59,6 @@
 	mmcr1_val = sys->mmcr1;
 	mmcra_val = sys->mmcra;
 
-	backtrace_spinlocks = sys->backtrace_spinlocks;
-
 	for (i = 0; i < cur_cpu_spec->num_pmcs; ++i)
 		reset_value[i] = 0x80000000UL - ctr[i].count;
 
@@ -197,25 +191,6 @@
 {
 }
 
-static unsigned long check_spinlock_pc(struct pt_regs *regs,
-				       unsigned long profile_pc)
-{
-	unsigned long pc = instruction_pointer(regs);
-
-	/*
-	 * If both the SIAR (sampled instruction) and the perfmon exception
-	 * occurred in a spinlock region then we account the sample to the
-	 * calling function. This isnt 100% correct, we really need soft
-	 * IRQ disable so we always get the perfmon exception at the
-	 * point at which the SIAR is set.
-	 */
-	if (backtrace_spinlocks && in_lock_functions(pc) &&
-			in_lock_functions(profile_pc))
-		return regs->link;
-	else
-		return profile_pc;
-}
-
 /*
  * On GQ and newer the MMCRA stores the HV and PR bits at the time
  * the SIAR was sampled. We use that to work out if the SIAR was sampled in
@@ -228,17 +203,17 @@
 
 	/* Cant do much about it */
 	if (!mmcra_has_sihv)
-		return check_spinlock_pc(regs, pc);
+		return pc;
 
 	mmcra = mfspr(SPRN_MMCRA);
 
 	/* Were we in the hypervisor? */
-	if (firmware_has_feature(FW_FEATURE_LPAR) && (mmcra & MMCRA_SIHV))
+	if (firmware_has_feature(FW_FEATURE_LPAR) && (mmcra & mmcra_sihv))
 		/* function descriptor madness */
 		return *((unsigned long *)hypervisor_bucket);
 
 	/* We were in userspace, nothing to do */
-	if (mmcra & MMCRA_SIPR)
+	if (mmcra & mmcra_sipr)
 		return pc;
 
 #ifdef CONFIG_PPC_RTAS
@@ -257,7 +232,7 @@
 		/* function descriptor madness */
 		return *((unsigned long *)kernel_unknown_bucket);
 
-	return check_spinlock_pc(regs, pc);
+	return pc;
 }
 
 static int get_kernel(unsigned long pc)
@@ -268,7 +243,7 @@
 		is_kernel = is_kernel_addr(pc);
 	} else {
 		unsigned long mmcra = mfspr(SPRN_MMCRA);
-		is_kernel = ((mmcra & MMCRA_SIPR) == 0);
+		is_kernel = ((mmcra & mmcra_sipr) == 0);
 	}
 
 	return is_kernel;
@@ -293,7 +268,7 @@
 		val = ctr_read(i);
 		if (val < 0) {
 			if (oprofile_running && ctr[i].enabled) {
-				oprofile_add_pc(pc, is_kernel, i);
+				oprofile_add_ext_sample(pc, regs, i, is_kernel);
 				ctr_write(i, reset_value[i]);
 			} else {
 				ctr_write(i, 0);
diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c
index 5c909ee..042f8f4 100644
--- a/arch/powerpc/oprofile/op_model_rs64.c
+++ b/arch/powerpc/oprofile/op_model_rs64.c
@@ -175,10 +175,13 @@
 				  struct op_counter_config *ctr)
 {
 	unsigned int mmcr0;
+	int is_kernel;
 	int val;
 	int i;
 	unsigned long pc = mfspr(SPRN_SIAR);
 
+	is_kernel = is_kernel_addr(pc);
+
 	/* set the PMM bit (see comment below) */
 	mtmsrd(mfmsr() | MSR_PMM);
 
@@ -186,7 +189,7 @@
 		val = ctr_read(i);
 		if (val < 0) {
 			if (ctr[i].enabled) {
-				oprofile_add_pc(pc, is_kernel_addr(pc), i);
+				oprofile_add_ext_sample(pc, regs, i, is_kernel);
 				ctr_write(i, reset_value[i]);
 			} else {
 				ctr_write(i, 0);
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index d3d0ff7..06e3712 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -7,6 +7,7 @@
 
 config MPC8540_ADS
 	bool "Freescale MPC8540 ADS"
+	select DEFAULT_UIMAGE
 	help
 	  This option enables support for the MPC 8540 ADS board
 
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 3157071..c2a3db8 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -10,4 +10,9 @@
 	  Units on machines implementing the Broadband Processor
 	  Architecture.
 
+config SPUFS_MMAP
+	bool
+	depends on SPU_FS && SPARSEMEM && !PPC_64K_PAGES
+	default y
+
 endmenu
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index 3b998a3..e570bad 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -6,5 +6,11 @@
 
 spu-base-y		+= spu_base.o spu_priv1.o
 
-builtin-spufs-$(CONFIG_SPU_FS)	+= spu_syscalls.o
-obj-y			+= $(builtin-spufs-m)
+# needed only when building loadable spufs.ko
+spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o
+obj-y			+= $(spufs-modular-m)
+
+# always needed in kernel
+spufs-builtin-$(CONFIG_SPU_FS) += spu_callbacks.o
+obj-y			+= $(spufs-builtin-y) $(spufs-builtin-m)
+
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 63aa52a..978be1c 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -63,7 +63,24 @@
 
 void iic_local_enable(void)
 {
-	out_be64(&__get_cpu_var(iic).regs->prio, 0xff);
+	struct iic *iic = &__get_cpu_var(iic);
+	u64 tmp;
+
+	/*
+	 * There seems to be a bug that is present in DD2.x CPUs
+	 * and still only partially fixed in DD3.1.
+	 * This bug causes a value written to the priority register
+	 * not to make it there, resulting in a system hang unless we
+	 * write it again.
+	 * Masking with 0xf0 is done because the Cell BE does not
+	 * implement the lower four bits of the interrupt priority,
+	 * they always read back as zeroes, although future CPUs
+	 * might implement different bits.
+	 */
+	do {
+		out_be64(&iic->regs->prio, 0xff);
+		tmp = in_be64(&iic->regs->prio);
+	} while ((tmp & 0xf0) != 0xf0);
 }
 
 void iic_local_disable(void)
@@ -123,7 +140,7 @@
 		    pending.class != 2)
 			break;
 		irq = IIC_EXT_OFFSET
-			+ spider_get_irq(pending.prio + node * IIC_NODE_STRIDE)
+			+ spider_get_irq(node)
 			+ node * IIC_NODE_STRIDE;
 		break;
 	case 0x01 ... 0x04:
@@ -174,40 +191,100 @@
 	return irq;
 }
 
-static int setup_iic(int cpu, struct iic *iic)
+/* hardcoded part to be compatible with older firmware */
+
+static int setup_iic_hardcoded(void)
 {
 	struct device_node *np;
-	int nodeid = cpu / 2;
+	int nodeid, cpu;
 	unsigned long regs;
+	struct iic *iic;
 
-	for (np = of_find_node_by_type(NULL, "cpu");
-	     np;
-	     np = of_find_node_by_type(np, "cpu")) {
-		if (nodeid == *(int *)get_property(np, "node-id", NULL))
-			break;
+	for_each_cpu(cpu) {
+		iic = &per_cpu(iic, cpu);
+		nodeid = cpu/2;
+
+		for (np = of_find_node_by_type(NULL, "cpu");
+		     np;
+		     np = of_find_node_by_type(np, "cpu")) {
+			if (nodeid == *(int *)get_property(np, "node-id", NULL))
+				break;
+			}
+
+		if (!np) {
+			printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
+			iic->regs = NULL;
+			iic->target_id = 0xff;
+			return -ENODEV;
+			}
+
+		regs = *(long *)get_property(np, "iic", NULL);
+
+		/* hack until we have decided on the devtree info */
+		regs += 0x400;
+		if (cpu & 1)
+			regs += 0x20;
+
+		printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
+		iic->regs = ioremap(regs, sizeof(struct iic_regs));
+		iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
 	}
 
-	if (!np) {
-		printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
-		iic->regs = NULL;
-		iic->target_id = 0xff;
-		return -ENODEV;
-	}
-
-	regs = *(long *)get_property(np, "iic", NULL);
-
-	/* hack until we have decided on the devtree info */
-	regs += 0x400;
-	if (cpu & 1)
-		regs += 0x20;
-
-	printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs);
-	iic->regs = __ioremap(regs, sizeof(struct iic_regs),
-					 _PAGE_NO_CACHE);
-	iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
 	return 0;
 }
 
+static int setup_iic(void)
+{
+	struct device_node *dn;
+	unsigned long *regs;
+	char *compatible;
+ 	unsigned *np, found = 0;
+	struct iic *iic = NULL;
+
+	for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
+		compatible = (char *)get_property(dn, "compatible", NULL);
+
+		if (!compatible) {
+			printk(KERN_WARNING "no compatible property found !\n");
+			continue;
+		}
+
+ 		if (strstr(compatible, "IBM,CBEA-Internal-Interrupt-Controller"))
+ 			regs = (unsigned long *)get_property(dn,"reg", NULL);
+ 		else
+			continue;
+
+ 		if (!regs)
+ 			printk(KERN_WARNING "IIC: no reg property\n");
+
+ 		np = (unsigned int *)get_property(dn, "ibm,interrupt-server-ranges", NULL);
+
+ 		if (!np) {
+			printk(KERN_WARNING "IIC: CPU association not found\n");
+			iic->regs = NULL;
+			iic->target_id = 0xff;
+			return -ENODEV;
+		}
+
+ 		iic = &per_cpu(iic, np[0]);
+ 		iic->regs = ioremap(regs[0], sizeof(struct iic_regs));
+		iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
+ 		printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);
+
+ 		iic = &per_cpu(iic, np[1]);
+ 		iic->regs = ioremap(regs[2], sizeof(struct iic_regs));
+		iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
+ 		printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);
+
+		found++;
+  	}
+
+	if (found)
+		return 0;
+	else
+		return -ENODEV;
+}
+
 #ifdef CONFIG_SMP
 
 /* Use the highest interrupt priorities for IPI */
@@ -283,10 +360,12 @@
 	int cpu, irq_offset;
 	struct iic *iic;
 
+	if (setup_iic() < 0)
+		setup_iic_hardcoded();
+
 	irq_offset = 0;
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		iic = &per_cpu(iic, cpu);
-		setup_iic(cpu, iic);
 		if (iic->regs)
 			out_be64(&iic->regs->prio, 0xff);
 	}
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h
index a14bd38..799f77d 100644
--- a/arch/powerpc/platforms/cell/interrupt.h
+++ b/arch/powerpc/platforms/cell/interrupt.h
@@ -57,7 +57,7 @@
 extern u8 iic_get_target_id(int cpu);
 
 extern void spider_init_IRQ(void);
-extern int spider_get_irq(unsigned long int_pending);
+extern int spider_get_irq(int node);
 
 #endif
 #endif /* ASM_CELL_PIC_H */
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 46e7cb9..a49ceb7 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -289,7 +289,7 @@
 	ioc_base = iommu->mapped_base;
 	ioc_mmio_base = iommu->mapped_mmio_base;
 
-	for (real_address = 0, io_address = 0;
+	for (real_address = 0, io_address = map_start;
 	     io_address <= map_start + map_size;
 	     real_address += io_page_size, io_address += io_page_size) {
 		ioste = get_iost_entry(fake_iopt, io_address, io_page_size);
@@ -302,7 +302,7 @@
 		set_iopt_cache(ioc_mmio_base,
 			get_ioc_hash_1way(ioste, io_address),
 			get_ioc_tag(ioste, io_address),
-			get_iopt_entry(real_address-map_start, ioid, IOPT_PROT_RW));
+			get_iopt_entry(real_address, ioid, IOPT_PROT_RW));
 	}
 }
 
@@ -344,8 +344,8 @@
 
 	/* node 0 */
 	iommu = &cell_iommus[0];
-	iommu->mapped_base = __ioremap(0x20000511000, 0x1000, _PAGE_NO_CACHE);
-	iommu->mapped_mmio_base = __ioremap(0x20000510000, 0x1000, _PAGE_NO_CACHE);
+	iommu->mapped_base = ioremap(0x20000511000, 0x1000);
+	iommu->mapped_mmio_base = ioremap(0x20000510000, 0x1000);
 
 	enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
 
@@ -357,8 +357,8 @@
 
 	/* node 1 */
 	iommu = &cell_iommus[1];
-	iommu->mapped_base = __ioremap(0x30000511000, 0x1000, _PAGE_NO_CACHE);
-	iommu->mapped_mmio_base = __ioremap(0x30000510000, 0x1000, _PAGE_NO_CACHE);
+	iommu->mapped_base = ioremap(0x30000511000, 0x1000);
+	iommu->mapped_mmio_base = ioremap(0x30000510000, 0x1000);
 
 	enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
 
@@ -407,8 +407,8 @@
 		iommu->base = *base;
 		iommu->mmio_base = *mmio_base;
 
-		iommu->mapped_base = __ioremap(*base, 0x1000, _PAGE_NO_CACHE);
-		iommu->mapped_mmio_base = __ioremap(*mmio_base, 0x1000, _PAGE_NO_CACHE);
+		iommu->mapped_base = ioremap(*base, 0x1000);
+		iommu->mapped_mmio_base = ioremap(*mmio_base, 0x1000);
 
 		enable_mapping(iommu->mapped_base,
 			       iommu->mapped_mmio_base);
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c
index e0e051c..7eed8c6 100644
--- a/arch/powerpc/platforms/cell/pervasive.c
+++ b/arch/powerpc/platforms/cell/pervasive.c
@@ -203,7 +203,7 @@
 
 	pr_debug("pervasive area for CPU %d at %lx, size %x\n",
 			cpu, real_address, size);
-	p->regs = __ioremap(real_address, size, _PAGE_NO_CACHE);
+	p->regs = ioremap(real_address, size);
 	p->thread = thread;
 	return 0;
 }
@@ -217,7 +217,7 @@
 	if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
 		return;
 
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		p = &cbe_pervasive[cpu];
 		ret = cbe_find_pmd_mmio(cpu, p);
 		if (ret)
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index fec8e65..dac5d03 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -195,9 +195,13 @@
 }
 
 
-static int __init cell_probe(int platform)
+static int __init cell_probe(void)
 {
-	if (platform != PLATFORM_CELL)
+	/* XXX This is temporary, the Cell maintainer will come up with
+	 * more appropriate detection logic
+	 */
+	unsigned long root = of_get_flat_dt_root();
+	if (!of_flat_dt_is_compatible(root, "IBM,CPBW-1.0"))
 		return 0;
 
 	return 1;
@@ -212,7 +216,8 @@
 	return -ENODEV;
 }
 
-struct machdep_calls __initdata cell_md = {
+define_machine(cell) {
+	.name			= "Cell",
 	.probe			= cell_probe,
 	.setup_arch		= cell_setup_arch,
 	.init_early		= cell_init_early,
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index e741321..55cbdd7 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -84,10 +84,11 @@
 
 static void spider_enable_irq(unsigned int irq)
 {
+	int nodeid = (irq / IIC_NODE_STRIDE) * 0x10;
 	void __iomem *cfg = spider_get_irq_config(irq);
 	irq = spider_get_nr(irq);
 
-	out_be32(cfg, in_be32(cfg) | 0x3107000eu);
+	out_be32(cfg, (in_be32(cfg) & ~0xf0)| 0x3107000eu | nodeid);
 	out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq);
 }
 
@@ -131,61 +132,108 @@
 	.end = spider_end_irq,
 };
 
-
-int spider_get_irq(unsigned long int_pending)
+int spider_get_irq(int node)
 {
-	void __iomem *regs = spider_get_pic(int_pending);
 	unsigned long cs;
-	int irq;
+	void __iomem *regs = spider_pics[node];
 
-	cs = in_be32(regs + TIR_CS);
+	cs = in_be32(regs + TIR_CS) >> 24;
 
-	irq = cs >> 24;
-	if (irq != 63)
-		return irq;
-
-	return -1;
+	if (cs == 63)
+		return -1;
+	else
+		return cs;
 }
- 
-void spider_init_IRQ(void)
+
+/* hardcoded part to be compatible with older firmware */
+
+void spider_init_IRQ_hardcoded(void)
 {
 	int node;
-	struct device_node *dn;
-	unsigned int *property;
 	long spiderpic;
+	long pics[] = { 0x24000008000, 0x34000008000 };
 	int n;
 
-/* FIXME: detect multiple PICs as soon as the device tree has them */
-	for (node = 0; node < 1; node++) {
-		dn = of_find_node_by_path("/");
-		n = prom_n_addr_cells(dn);
-		property = (unsigned int *) get_property(dn,
-				"platform-spider-pic", NULL);
+	pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
 
-		if (!property)
-			continue;
-		for (spiderpic = 0; n > 0; --n)
-			spiderpic = (spiderpic << 32) + *property++;
+	for (node = 0; node < num_present_cpus()/2; node++) {
+		spiderpic = pics[node];
 		printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic);
-		spider_pics[node] = __ioremap(spiderpic, 0x800, _PAGE_NO_CACHE);
+		spider_pics[node] = ioremap(spiderpic, 0x800);
 		for (n = 0; n < IIC_NUM_EXT; n++) {
 			int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
 			get_irq_desc(irq)->handler = &spider_pic;
+		}
 
  		/* do not mask any interrupts because of level */
  		out_be32(spider_pics[node] + TIR_MSK, 0x0);
- 		
+
  		/* disable edge detection clear */
  		/* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
- 		
+
  		/* enable interrupt packets to be output */
  		out_be32(spider_pics[node] + TIR_PIEN,
 			in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
- 		
+
  		/* Enable the interrupt detection enable bit. Do this last! */
  		out_be32(spider_pics[node] + TIR_DEN,
-			in_be32(spider_pics[node] +TIR_DEN) | 0x1);
+			in_be32(spider_pics[node] + TIR_DEN) | 0x1);
+	}
+}
 
+void spider_init_IRQ(void)
+{
+	long spider_reg;
+	struct device_node *dn;
+	char *compatible;
+	int n, node = 0;
+
+	for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
+		compatible = (char *)get_property(dn, "compatible", NULL);
+
+		if (!compatible)
+			continue;
+
+		if (strstr(compatible, "CBEA,platform-spider-pic"))
+			spider_reg = *(long *)get_property(dn,"reg", NULL);
+		else if (strstr(compatible, "sti,platform-spider-pic")) {
+			spider_init_IRQ_hardcoded();
+			return;
+		} else
+			continue;
+
+		if (!spider_reg)
+			printk("interrupt controller does not have reg property !\n");
+
+		n = prom_n_addr_cells(dn);
+
+		if ( n != 2)
+			printk("reg property with invalid number of elements \n");
+
+		spider_pics[node] = ioremap(spider_reg, 0x800);
+
+		printk("SPIDER addr: %lx with %i addr_cells mapped to %p\n",
+		       spider_reg, n, spider_pics[node]);
+
+		for (n = 0; n < IIC_NUM_EXT; n++) {
+			int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
+			get_irq_desc(irq)->handler = &spider_pic;
 		}
+
+		/* do not mask any interrupts because of level */
+		out_be32(spider_pics[node] + TIR_MSK, 0x0);
+
+		/* disable edge detection clear */
+		/* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
+
+		/* enable interrupt packets to be output */
+		out_be32(spider_pics[node] + TIR_PIEN,
+			in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
+
+		/* Enable the interrupt detection enable bit. Do this last! */
+		out_be32(spider_pics[node] + TIR_DEN,
+			in_be32(spider_pics[node] + TIR_DEN) | 0x1);
+
+		node++;
 	}
 }
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index d75ae03..269dda4 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -32,7 +32,7 @@
 
 #include <asm/io.h>
 #include <asm/prom.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/spu.h>
 #include <asm/mmu_context.h>
 
@@ -111,7 +111,7 @@
 extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX
 static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
 {
-	pr_debug("%s\n", __FUNCTION__);
+	pr_debug("%s, %lx, %lx\n", __FUNCTION__, dsisr, ea);
 
 	/* Handle kernel space hash faults immediately.
 	   User hash faults need to be deferred to process context. */
@@ -168,7 +168,7 @@
 static int __spu_trap_tag_group(struct spu *spu)
 {
 	pr_debug("%s\n", __FUNCTION__);
-	/* wake_up(&spu->dma_wq); */
+	spu->mfc_callback(spu);
 	return 0;
 }
 
@@ -242,6 +242,8 @@
 		spu_mfc_dsisr_set(spu, 0ul);
 	spu_int_stat_clear(spu, 1, stat);
 	spin_unlock(&spu->register_lock);
+	pr_debug("%s: %lx %lx %lx %lx\n", __FUNCTION__, mask, stat,
+			dar, dsisr);
 
 	if (stat & 1) /* segment fault */
 		__spu_trap_data_seg(spu, dar);
@@ -342,7 +344,7 @@
 }
 
 static LIST_HEAD(spu_list);
-static DECLARE_MUTEX(spu_mutex);
+static DEFINE_MUTEX(spu_mutex);
 
 static void spu_init_channels(struct spu *spu)
 {
@@ -382,7 +384,7 @@
 {
 	struct spu *spu;
 
-	down(&spu_mutex);
+	mutex_lock(&spu_mutex);
 	if (!list_empty(&spu_list)) {
 		spu = list_entry(spu_list.next, struct spu, list);
 		list_del_init(&spu->list);
@@ -391,7 +393,7 @@
 		pr_debug("No SPU left\n");
 		spu = NULL;
 	}
-	up(&spu_mutex);
+	mutex_unlock(&spu_mutex);
 
 	if (spu)
 		spu_init_channels(spu);
@@ -402,9 +404,9 @@
 
 void spu_free(struct spu *spu)
 {
-	down(&spu_mutex);
+	mutex_lock(&spu_mutex);
 	list_add_tail(&spu->list, &spu_list);
-	up(&spu_mutex);
+	mutex_unlock(&spu_mutex);
 }
 EXPORT_SYMBOL_GPL(spu_free);
 
@@ -484,14 +486,13 @@
 
 	ea = spu->dar;
 	dsisr = spu->dsisr;
-	if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {
+	if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) {
 		access = (_PAGE_PRESENT | _PAGE_USER);
 		access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
 		if (hash_page(ea, access, 0x300) != 0)
 			error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
 	}
-	if ((error & CLASS1_ENABLE_STORAGE_FAULT_INTR) ||
-	    (dsisr & MFC_DSISR_ACCESS_DENIED)) {
+	if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) {
 		if ((ret = spu_handle_mm_fault(spu)) != 0)
 			error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
 		else
@@ -568,6 +569,11 @@
 	if (!spu->local_store)
 		goto out;
 
+	prop = get_property(spe, "problem", NULL);
+	if (!prop)
+		goto out_unmap;
+	spu->problem_phys = *(unsigned long *)prop;
+
 	spu->problem= map_spe_prop(spe, "problem");
 	if (!spu->problem)
 		goto out_unmap;
@@ -632,15 +638,16 @@
 	spu->ibox_callback = NULL;
 	spu->wbox_callback = NULL;
 	spu->stop_callback = NULL;
+	spu->mfc_callback = NULL;
 
-	down(&spu_mutex);
+	mutex_lock(&spu_mutex);
 	spu->number = number++;
 	ret = spu_request_irqs(spu);
 	if (ret)
 		goto out_unmap;
 
 	list_add(&spu->list, &spu_list);
-	up(&spu_mutex);
+	mutex_unlock(&spu_mutex);
 
 	pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n",
 		spu->name, spu->isrc, spu->local_store,
@@ -648,7 +655,7 @@
 	goto out;
 
 out_unmap:
-	up(&spu_mutex);
+	mutex_unlock(&spu_mutex);
 	spu_unmap(spu);
 out_free:
 	kfree(spu);
@@ -668,10 +675,10 @@
 static void cleanup_spu_base(void)
 {
 	struct spu *spu, *tmp;
-	down(&spu_mutex);
+	mutex_lock(&spu_mutex);
 	list_for_each_entry_safe(spu, tmp, &spu_list, list)
 		destroy_spu(spu);
-	up(&spu_mutex);
+	mutex_unlock(&spu_mutex);
 }
 module_exit(cleanup_spu_base);
 
diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c
new file mode 100644
index 0000000..3a4245c
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_callbacks.c
@@ -0,0 +1,345 @@
+/*
+ * System call callback functions for SPUs
+ */
+
+#define DEBUG
+
+#include <linux/kallsyms.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+
+#include <asm/spu.h>
+#include <asm/syscalls.h>
+#include <asm/unistd.h>
+
+/*
+ * This table defines the system calls that an SPU can call.
+ * It is currently a subset of the 64 bit powerpc system calls,
+ * with the exact semantics.
+ *
+ * The reasons for disabling some of the system calls are:
+ * 1. They interact with the way SPU syscalls are handled
+ *    and we can't let them execute ever:
+ *	restart_syscall, exit, for, execve, ptrace, ...
+ * 2. They are deprecated and replaced by other means:
+ *	uselib, pciconfig_*, sysfs, ...
+ * 3. They are somewhat interacting with the system in a way
+ *    we don't want an SPU to:
+ *	reboot, init_module, mount, kexec_load
+ * 4. They are optional and we can't rely on them being
+ *    linked into the kernel. Unfortunately, the cond_syscall
+ *    helper does not work here as it does not add the necessary
+ *    opd symbols:
+ *	mbind, mq_open, ipc, ...
+ */
+
+void *spu_syscall_table[] = {
+	[__NR_restart_syscall]		sys_ni_syscall, /* sys_restart_syscall */
+	[__NR_exit]			sys_ni_syscall, /* sys_exit */
+	[__NR_fork]			sys_ni_syscall, /* ppc_fork */
+	[__NR_read]			sys_read,
+	[__NR_write]			sys_write,
+	[__NR_open]			sys_open,
+	[__NR_close]			sys_close,
+	[__NR_waitpid]			sys_waitpid,
+	[__NR_creat]			sys_creat,
+	[__NR_link]			sys_link,
+	[__NR_unlink]			sys_unlink,
+	[__NR_execve]			sys_ni_syscall, /* sys_execve */
+	[__NR_chdir]			sys_chdir,
+	[__NR_time]			sys_time,
+	[__NR_mknod]			sys_mknod,
+	[__NR_chmod]			sys_chmod,
+	[__NR_lchown]			sys_lchown,
+	[__NR_break]			sys_ni_syscall,
+	[__NR_oldstat]			sys_ni_syscall,
+	[__NR_lseek]			sys_lseek,
+	[__NR_getpid]			sys_getpid,
+	[__NR_mount]			sys_ni_syscall, /* sys_mount */
+	[__NR_umount]			sys_ni_syscall,
+	[__NR_setuid]			sys_setuid,
+	[__NR_getuid]			sys_getuid,
+	[__NR_stime]			sys_stime,
+	[__NR_ptrace]			sys_ni_syscall, /* sys_ptrace */
+	[__NR_alarm]			sys_alarm,
+	[__NR_oldfstat]			sys_ni_syscall,
+	[__NR_pause]			sys_ni_syscall, /* sys_pause */
+	[__NR_utime]			sys_ni_syscall, /* sys_utime */
+	[__NR_stty]			sys_ni_syscall,
+	[__NR_gtty]			sys_ni_syscall,
+	[__NR_access]			sys_access,
+	[__NR_nice]			sys_nice,
+	[__NR_ftime]			sys_ni_syscall,
+	[__NR_sync]			sys_sync,
+	[__NR_kill]			sys_kill,
+	[__NR_rename]			sys_rename,
+	[__NR_mkdir]			sys_mkdir,
+	[__NR_rmdir]			sys_rmdir,
+	[__NR_dup]			sys_dup,
+	[__NR_pipe]			sys_pipe,
+	[__NR_times]			sys_times,
+	[__NR_prof]			sys_ni_syscall,
+	[__NR_brk]			sys_brk,
+	[__NR_setgid]			sys_setgid,
+	[__NR_getgid]			sys_getgid,
+	[__NR_signal]			sys_ni_syscall, /* sys_signal */
+	[__NR_geteuid]			sys_geteuid,
+	[__NR_getegid]			sys_getegid,
+	[__NR_acct]			sys_ni_syscall, /* sys_acct */
+	[__NR_umount2]			sys_ni_syscall, /* sys_umount */
+	[__NR_lock]			sys_ni_syscall,
+	[__NR_ioctl]			sys_ioctl,
+	[__NR_fcntl]			sys_fcntl,
+	[__NR_mpx]			sys_ni_syscall,
+	[__NR_setpgid]			sys_setpgid,
+	[__NR_ulimit]			sys_ni_syscall,
+	[__NR_oldolduname]		sys_ni_syscall,
+	[__NR_umask]			sys_umask,
+	[__NR_chroot]			sys_chroot,
+	[__NR_ustat]			sys_ni_syscall, /* sys_ustat */
+	[__NR_dup2]			sys_dup2,
+	[__NR_getppid]			sys_getppid,
+	[__NR_getpgrp]			sys_getpgrp,
+	[__NR_setsid]			sys_setsid,
+	[__NR_sigaction]		sys_ni_syscall,
+	[__NR_sgetmask]			sys_sgetmask,
+	[__NR_ssetmask]			sys_ssetmask,
+	[__NR_setreuid]			sys_setreuid,
+	[__NR_setregid]			sys_setregid,
+	[__NR_sigsuspend]		sys_ni_syscall,
+	[__NR_sigpending]		sys_ni_syscall,
+	[__NR_sethostname]		sys_sethostname,
+	[__NR_setrlimit]		sys_setrlimit,
+	[__NR_getrlimit]		sys_ni_syscall,
+	[__NR_getrusage]		sys_getrusage,
+	[__NR_gettimeofday]		sys_gettimeofday,
+	[__NR_settimeofday]		sys_settimeofday,
+	[__NR_getgroups]		sys_getgroups,
+	[__NR_setgroups]		sys_setgroups,
+	[__NR_select]			sys_ni_syscall,
+	[__NR_symlink]			sys_symlink,
+	[__NR_oldlstat]			sys_ni_syscall,
+	[__NR_readlink]			sys_readlink,
+	[__NR_uselib]			sys_ni_syscall, /* sys_uselib */
+	[__NR_swapon]			sys_ni_syscall, /* sys_swapon */
+	[__NR_reboot]			sys_ni_syscall, /* sys_reboot */
+	[__NR_readdir]			sys_ni_syscall,
+	[__NR_mmap]			sys_mmap,
+	[__NR_munmap]			sys_munmap,
+	[__NR_truncate]			sys_truncate,
+	[__NR_ftruncate]		sys_ftruncate,
+	[__NR_fchmod]			sys_fchmod,
+	[__NR_fchown]			sys_fchown,
+	[__NR_getpriority]		sys_getpriority,
+	[__NR_setpriority]		sys_setpriority,
+	[__NR_profil]			sys_ni_syscall,
+	[__NR_statfs]			sys_ni_syscall, /* sys_statfs */
+	[__NR_fstatfs]			sys_ni_syscall, /* sys_fstatfs */
+	[__NR_ioperm]			sys_ni_syscall,
+	[__NR_socketcall]		sys_socketcall,
+	[__NR_syslog]			sys_syslog,
+	[__NR_setitimer]		sys_setitimer,
+	[__NR_getitimer]		sys_getitimer,
+	[__NR_stat]			sys_newstat,
+	[__NR_lstat]			sys_newlstat,
+	[__NR_fstat]			sys_newfstat,
+	[__NR_olduname]			sys_ni_syscall,
+	[__NR_iopl]			sys_ni_syscall,
+	[__NR_vhangup]			sys_vhangup,
+	[__NR_idle]			sys_ni_syscall,
+	[__NR_vm86]			sys_ni_syscall,
+	[__NR_wait4]			sys_wait4,
+	[__NR_swapoff]			sys_ni_syscall, /* sys_swapoff */
+	[__NR_sysinfo]			sys_sysinfo,
+	[__NR_ipc]			sys_ni_syscall, /* sys_ipc */
+	[__NR_fsync]			sys_fsync,
+	[__NR_sigreturn]		sys_ni_syscall,
+	[__NR_clone]			sys_ni_syscall, /* ppc_clone */
+	[__NR_setdomainname]		sys_setdomainname,
+	[__NR_uname]			ppc_newuname,
+	[__NR_modify_ldt]		sys_ni_syscall,
+	[__NR_adjtimex]			sys_adjtimex,
+	[__NR_mprotect]			sys_mprotect,
+	[__NR_sigprocmask]		sys_ni_syscall,
+	[__NR_create_module]		sys_ni_syscall,
+	[__NR_init_module]		sys_ni_syscall, /* sys_init_module */
+	[__NR_delete_module]		sys_ni_syscall, /* sys_delete_module */
+	[__NR_get_kernel_syms]		sys_ni_syscall,
+	[__NR_quotactl]			sys_ni_syscall, /* sys_quotactl */
+	[__NR_getpgid]			sys_getpgid,
+	[__NR_fchdir]			sys_fchdir,
+	[__NR_bdflush]			sys_bdflush,
+	[__NR_sysfs]			sys_ni_syscall, /* sys_sysfs */
+	[__NR_personality]		ppc64_personality,
+	[__NR_afs_syscall]		sys_ni_syscall,
+	[__NR_setfsuid]			sys_setfsuid,
+	[__NR_setfsgid]			sys_setfsgid,
+	[__NR__llseek]			sys_llseek,
+	[__NR_getdents]			sys_getdents,
+	[__NR__newselect]		sys_select,
+	[__NR_flock]			sys_flock,
+	[__NR_msync]			sys_msync,
+	[__NR_readv]			sys_readv,
+	[__NR_writev]			sys_writev,
+	[__NR_getsid]			sys_getsid,
+	[__NR_fdatasync]		sys_fdatasync,
+	[__NR__sysctl]			sys_ni_syscall, /* sys_sysctl */
+	[__NR_mlock]			sys_mlock,
+	[__NR_munlock]			sys_munlock,
+	[__NR_mlockall]			sys_mlockall,
+	[__NR_munlockall]		sys_munlockall,
+	[__NR_sched_setparam]		sys_sched_setparam,
+	[__NR_sched_getparam]		sys_sched_getparam,
+	[__NR_sched_setscheduler]	sys_sched_setscheduler,
+	[__NR_sched_getscheduler]	sys_sched_getscheduler,
+	[__NR_sched_yield]		sys_sched_yield,
+	[__NR_sched_get_priority_max]	sys_sched_get_priority_max,
+	[__NR_sched_get_priority_min]	sys_sched_get_priority_min,
+	[__NR_sched_rr_get_interval]	sys_sched_rr_get_interval,
+	[__NR_nanosleep]		sys_nanosleep,
+	[__NR_mremap]			sys_mremap,
+	[__NR_setresuid]		sys_setresuid,
+	[__NR_getresuid]		sys_getresuid,
+	[__NR_query_module]		sys_ni_syscall,
+	[__NR_poll]			sys_poll,
+	[__NR_nfsservctl]		sys_ni_syscall, /* sys_nfsservctl */
+	[__NR_setresgid]		sys_setresgid,
+	[__NR_getresgid]		sys_getresgid,
+	[__NR_prctl]			sys_prctl,
+	[__NR_rt_sigreturn]		sys_ni_syscall, /* ppc64_rt_sigreturn */
+	[__NR_rt_sigaction]		sys_ni_syscall, /* sys_rt_sigaction */
+	[__NR_rt_sigprocmask]		sys_ni_syscall, /* sys_rt_sigprocmask */
+	[__NR_rt_sigpending]		sys_ni_syscall, /* sys_rt_sigpending */
+	[__NR_rt_sigtimedwait]		sys_ni_syscall, /* sys_rt_sigtimedwait */
+	[__NR_rt_sigqueueinfo]		sys_ni_syscall, /* sys_rt_sigqueueinfo */
+	[__NR_rt_sigsuspend]		sys_ni_syscall, /* sys_rt_sigsuspend */
+	[__NR_pread64]			sys_pread64,
+	[__NR_pwrite64]			sys_pwrite64,
+	[__NR_chown]			sys_chown,
+	[__NR_getcwd]			sys_getcwd,
+	[__NR_capget]			sys_capget,
+	[__NR_capset]			sys_capset,
+	[__NR_sigaltstack]		sys_ni_syscall, /* sys_sigaltstack */
+	[__NR_sendfile]			sys_sendfile64,
+	[__NR_getpmsg]			sys_ni_syscall,
+	[__NR_putpmsg]			sys_ni_syscall,
+	[__NR_vfork]			sys_ni_syscall, /* ppc_vfork */
+	[__NR_ugetrlimit]		sys_getrlimit,
+	[__NR_readahead]		sys_readahead,
+	[192]				sys_ni_syscall,
+	[193]				sys_ni_syscall,
+	[194]				sys_ni_syscall,
+	[195]				sys_ni_syscall,
+	[196]				sys_ni_syscall,
+	[197]				sys_ni_syscall,
+	[__NR_pciconfig_read]		sys_ni_syscall, /* sys_pciconfig_read */
+	[__NR_pciconfig_write]		sys_ni_syscall, /* sys_pciconfig_write */
+	[__NR_pciconfig_iobase]		sys_ni_syscall, /* sys_pciconfig_iobase */
+	[__NR_multiplexer]		sys_ni_syscall,
+	[__NR_getdents64]		sys_getdents64,
+	[__NR_pivot_root]		sys_pivot_root,
+	[204]				sys_ni_syscall,
+	[__NR_madvise]			sys_madvise,
+	[__NR_mincore]			sys_mincore,
+	[__NR_gettid]			sys_gettid,
+	[__NR_tkill]			sys_tkill,
+	[__NR_setxattr]			sys_setxattr,
+	[__NR_lsetxattr]		sys_lsetxattr,
+	[__NR_fsetxattr]		sys_fsetxattr,
+	[__NR_getxattr]			sys_getxattr,
+	[__NR_lgetxattr]		sys_lgetxattr,
+	[__NR_fgetxattr]		sys_fgetxattr,
+	[__NR_listxattr]		sys_listxattr,
+	[__NR_llistxattr]		sys_llistxattr,
+	[__NR_flistxattr]		sys_flistxattr,
+	[__NR_removexattr]		sys_removexattr,
+	[__NR_lremovexattr]		sys_lremovexattr,
+	[__NR_fremovexattr]		sys_fremovexattr,
+	[__NR_futex]			sys_futex,
+	[__NR_sched_setaffinity]	sys_sched_setaffinity,
+	[__NR_sched_getaffinity]	sys_sched_getaffinity,
+	[__NR_tuxcall]			sys_ni_syscall,
+	[226]				sys_ni_syscall,
+	[__NR_io_setup]			sys_io_setup,
+	[__NR_io_destroy]		sys_io_destroy,
+	[__NR_io_getevents]		sys_io_getevents,
+	[__NR_io_submit]		sys_io_submit,
+	[__NR_io_cancel]		sys_io_cancel,
+	[__NR_set_tid_address]		sys_ni_syscall, /* sys_set_tid_address */
+	[__NR_fadvise64]		sys_fadvise64,
+	[__NR_exit_group]		sys_ni_syscall, /* sys_exit_group */
+	[__NR_lookup_dcookie]		sys_ni_syscall, /* sys_lookup_dcookie */
+	[__NR_epoll_create]		sys_epoll_create,
+	[__NR_epoll_ctl]		sys_epoll_ctl,
+	[__NR_epoll_wait]		sys_epoll_wait,
+	[__NR_remap_file_pages]		sys_remap_file_pages,
+	[__NR_timer_create]		sys_timer_create,
+	[__NR_timer_settime]		sys_timer_settime,
+	[__NR_timer_gettime]		sys_timer_gettime,
+	[__NR_timer_getoverrun]		sys_timer_getoverrun,
+	[__NR_timer_delete]		sys_timer_delete,
+	[__NR_clock_settime]		sys_clock_settime,
+	[__NR_clock_gettime]		sys_clock_gettime,
+	[__NR_clock_getres]		sys_clock_getres,
+	[__NR_clock_nanosleep]		sys_clock_nanosleep,
+	[__NR_swapcontext]		sys_ni_syscall, /* ppc64_swapcontext */
+	[__NR_tgkill]			sys_tgkill,
+	[__NR_utimes]			sys_utimes,
+	[__NR_statfs64]			sys_statfs64,
+	[__NR_fstatfs64]		sys_fstatfs64,
+	[254]				sys_ni_syscall,
+	[__NR_rtas]			ppc_rtas,
+	[256]				sys_ni_syscall,
+	[257]				sys_ni_syscall,
+	[258]				sys_ni_syscall,
+	[__NR_mbind]			sys_ni_syscall, /* sys_mbind */
+	[__NR_get_mempolicy]		sys_ni_syscall, /* sys_get_mempolicy */
+	[__NR_set_mempolicy]		sys_ni_syscall, /* sys_set_mempolicy */
+	[__NR_mq_open]			sys_ni_syscall, /* sys_mq_open */
+	[__NR_mq_unlink]		sys_ni_syscall, /* sys_mq_unlink */
+	[__NR_mq_timedsend]		sys_ni_syscall, /* sys_mq_timedsend */
+	[__NR_mq_timedreceive]		sys_ni_syscall, /* sys_mq_timedreceive */
+	[__NR_mq_notify]		sys_ni_syscall, /* sys_mq_notify */
+	[__NR_mq_getsetattr]		sys_ni_syscall, /* sys_mq_getsetattr */
+	[__NR_kexec_load]		sys_ni_syscall, /* sys_kexec_load */
+	[__NR_add_key]			sys_ni_syscall, /* sys_add_key */
+	[__NR_request_key]		sys_ni_syscall, /* sys_request_key */
+	[__NR_keyctl]			sys_ni_syscall, /* sys_keyctl */
+	[__NR_waitid]			sys_ni_syscall, /* sys_waitid */
+	[__NR_ioprio_set]		sys_ni_syscall, /* sys_ioprio_set */
+	[__NR_ioprio_get]		sys_ni_syscall, /* sys_ioprio_get */
+	[__NR_inotify_init]		sys_ni_syscall, /* sys_inotify_init */
+	[__NR_inotify_add_watch]	sys_ni_syscall, /* sys_inotify_add_watch */
+	[__NR_inotify_rm_watch]		sys_ni_syscall, /* sys_inotify_rm_watch */
+	[__NR_spu_run]			sys_ni_syscall, /* sys_spu_run */
+	[__NR_spu_create]		sys_ni_syscall, /* sys_spu_create */
+	[__NR_pselect6]			sys_ni_syscall, /* sys_pselect */
+	[__NR_ppoll]			sys_ni_syscall, /* sys_ppoll */
+	[__NR_unshare]			sys_unshare,
+};
+
+long spu_sys_callback(struct spu_syscall_block *s)
+{
+	long (*syscall)(u64 a1, u64 a2, u64 a3, u64 a4, u64 a5, u64 a6);
+
+	BUILD_BUG_ON(ARRAY_SIZE(spu_syscall_table) != __NR_syscalls);
+
+	syscall = spu_syscall_table[s->nr_ret];
+
+	if (s->nr_ret >= __NR_syscalls) {
+		pr_debug("%s: invalid syscall #%ld", __FUNCTION__, s->nr_ret);
+		return -ENOSYS;
+	}
+
+#ifdef DEBUG
+	print_symbol(KERN_DEBUG "SPU-syscall %s:", (unsigned long)syscall);
+	printk("syscall%ld(%lx, %lx, %lx, %lx, %lx, %lx)\n",
+			s->nr_ret,
+			s->parm[0], s->parm[1], s->parm[2],
+			s->parm[3], s->parm[4], s->parm[5]);
+#endif
+
+	return syscall(s->parm[0], s->parm[1], s->parm[2],
+		       s->parm[3], s->parm[4], s->parm[5]);
+}
+EXPORT_SYMBOL_GPL(spu_sys_callback);
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c
index a5c489a5..f1d35dd 100644
--- a/arch/powerpc/platforms/cell/spufs/backing_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -285,6 +285,49 @@
 	spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP);
 }
 
+static int spu_backing_set_mfc_query(struct spu_context * ctx, u32 mask,
+					u32 mode)
+{
+	struct spu_problem_collapsed *prob = &ctx->csa.prob;
+	int ret;
+
+	spin_lock(&ctx->csa.register_lock);
+	ret = -EAGAIN;
+	if (prob->dma_querytype_RW)
+		goto out;
+	ret = 0;
+	/* FIXME: what are the side-effects of this? */
+	prob->dma_querymask_RW = mask;
+	prob->dma_querytype_RW = mode;
+out:
+	spin_unlock(&ctx->csa.register_lock);
+
+	return ret;
+}
+
+static u32 spu_backing_read_mfc_tagstatus(struct spu_context * ctx)
+{
+	return ctx->csa.prob.dma_tagstatus_R;
+}
+
+static u32 spu_backing_get_mfc_free_elements(struct spu_context *ctx)
+{
+	return ctx->csa.prob.dma_qstatus_R;
+}
+
+static int spu_backing_send_mfc_command(struct spu_context *ctx,
+					struct mfc_dma_command *cmd)
+{
+	int ret;
+
+	spin_lock(&ctx->csa.register_lock);
+	ret = -EAGAIN;
+	/* FIXME: set up priv2->puq */
+	spin_unlock(&ctx->csa.register_lock);
+
+	return ret;
+}
+
 struct spu_context_ops spu_backing_ops = {
 	.mbox_read = spu_backing_mbox_read,
 	.mbox_stat_read = spu_backing_mbox_stat_read,
@@ -305,4 +348,8 @@
 	.get_ls = spu_backing_get_ls,
 	.runcntl_write = spu_backing_runcntl_write,
 	.runcntl_stop = spu_backing_runcntl_stop,
+	.set_mfc_query = spu_backing_set_mfc_query,
+	.read_mfc_tagstatus = spu_backing_read_mfc_tagstatus,
+	.get_mfc_free_elements = spu_backing_get_mfc_free_elements,
+	.send_mfc_command = spu_backing_send_mfc_command,
 };
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 336f238..8bb33ab 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -27,7 +27,7 @@
 #include <asm/spu_csa.h>
 #include "spufs.h"
 
-struct spu_context *alloc_spu_context(struct address_space *local_store)
+struct spu_context *alloc_spu_context(void)
 {
 	struct spu_context *ctx;
 	ctx = kmalloc(sizeof *ctx, GFP_KERNEL);
@@ -47,10 +47,17 @@
 	init_waitqueue_head(&ctx->ibox_wq);
 	init_waitqueue_head(&ctx->wbox_wq);
 	init_waitqueue_head(&ctx->stop_wq);
+	init_waitqueue_head(&ctx->mfc_wq);
 	ctx->ibox_fasync = NULL;
 	ctx->wbox_fasync = NULL;
+	ctx->mfc_fasync = NULL;
+	ctx->mfc = NULL;
+	ctx->tagwait = 0;
 	ctx->state = SPU_STATE_SAVED;
-	ctx->local_store = local_store;
+	ctx->local_store = NULL;
+	ctx->cntl = NULL;
+	ctx->signal1 = NULL;
+	ctx->signal2 = NULL;
 	ctx->spu = NULL;
 	ctx->ops = &spu_backing_ops;
 	ctx->owner = get_task_mm(current);
@@ -68,8 +75,6 @@
 	ctx = container_of(kref, struct spu_context, kref);
 	down_write(&ctx->state_sema);
 	spu_deactivate(ctx);
-	ctx->ibox_fasync = NULL;
-	ctx->wbox_fasync = NULL;
 	up_write(&ctx->state_sema);
 	spu_fini_csa(&ctx->csa);
 	kfree(ctx);
@@ -109,7 +114,16 @@
 
 void spu_unmap_mappings(struct spu_context *ctx)
 {
-	unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1);
+	if (ctx->local_store)
+		unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1);
+	if (ctx->mfc)
+		unmap_mapping_range(ctx->mfc, 0, 0x4000, 1);
+	if (ctx->cntl)
+		unmap_mapping_range(ctx->cntl, 0, 0x4000, 1);
+	if (ctx->signal1)
+		unmap_mapping_range(ctx->signal1, 0, 0x4000, 1);
+	if (ctx->signal2)
+		unmap_mapping_range(ctx->signal2, 0, 0x4000, 1);
 }
 
 int spu_acquire_runnable(struct spu_context *ctx)
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index dfa649c..366185e 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -20,6 +20,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#undef DEBUG
+
 #include <linux/fs.h>
 #include <linux/ioctl.h>
 #include <linux/module.h>
@@ -39,8 +41,10 @@
 spufs_mem_open(struct inode *inode, struct file *file)
 {
 	struct spufs_inode_info *i = SPUFS_I(inode);
-	file->private_data = i->i_ctx;
-	file->f_mapping = i->i_ctx->local_store;
+	struct spu_context *ctx = i->i_ctx;
+	file->private_data = ctx;
+	file->f_mapping = inode->i_mapping;
+	ctx->local_store = inode->i_mapping;
 	return 0;
 }
 
@@ -84,7 +88,7 @@
 	return ret;
 }
 
-#ifdef CONFIG_SPARSEMEM
+#ifdef CONFIG_SPUFS_MMAP
 static struct page *
 spufs_mem_mmap_nopage(struct vm_area_struct *vma,
 		      unsigned long address, int *type)
@@ -136,11 +140,113 @@
 	.read    = spufs_mem_read,
 	.write   = spufs_mem_write,
 	.llseek  = generic_file_llseek,
-#ifdef CONFIG_SPARSEMEM
+#ifdef CONFIG_SPUFS_MMAP
 	.mmap    = spufs_mem_mmap,
 #endif
 };
 
+#ifdef CONFIG_SPUFS_MMAP
+static struct page *spufs_ps_nopage(struct vm_area_struct *vma,
+				    unsigned long address,
+				    int *type, unsigned long ps_offs)
+{
+	struct page *page = NOPAGE_SIGBUS;
+	int fault_type = VM_FAULT_SIGBUS;
+	struct spu_context *ctx = vma->vm_file->private_data;
+	unsigned long offset = address - vma->vm_start;
+	unsigned long area;
+	int ret;
+
+	offset += vma->vm_pgoff << PAGE_SHIFT;
+	if (offset >= 0x4000)
+		goto out;
+
+	ret = spu_acquire_runnable(ctx);
+	if (ret)
+		goto out;
+
+	area = ctx->spu->problem_phys + ps_offs;
+	page = pfn_to_page((area + offset) >> PAGE_SHIFT);
+	fault_type = VM_FAULT_MINOR;
+	page_cache_get(page);
+
+	spu_release(ctx);
+
+      out:
+	if (type)
+		*type = fault_type;
+
+	return page;
+}
+
+static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma,
+					   unsigned long address, int *type)
+{
+	return spufs_ps_nopage(vma, address, type, 0x4000);
+}
+
+static struct vm_operations_struct spufs_cntl_mmap_vmops = {
+	.nopage = spufs_cntl_mmap_nopage,
+};
+
+/*
+ * mmap support for problem state control area [0x4000 - 0x4fff].
+ * Mapping this area requires that the application have CAP_SYS_RAWIO,
+ * as these registers require special care when read/writing.
+ */
+static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	if (!(vma->vm_flags & VM_SHARED))
+		return -EINVAL;
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+				     | _PAGE_NO_CACHE);
+
+	vma->vm_ops = &spufs_cntl_mmap_vmops;
+	return 0;
+}
+#endif
+
+static int spufs_cntl_open(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	struct spu_context *ctx = i->i_ctx;
+
+	file->private_data = ctx;
+	file->f_mapping = inode->i_mapping;
+	ctx->cntl = inode->i_mapping;
+	return 0;
+}
+
+static ssize_t
+spufs_cntl_read(struct file *file, char __user *buffer,
+		size_t size, loff_t *pos)
+{
+	/* FIXME: read from spu status */
+	return -EINVAL;
+}
+
+static ssize_t
+spufs_cntl_write(struct file *file, const char __user *buffer,
+		 size_t size, loff_t *pos)
+{
+	/* FIXME: write to runctl bit */
+	return -EINVAL;
+}
+
+static struct file_operations spufs_cntl_fops = {
+	.open = spufs_cntl_open,
+	.read = spufs_cntl_read,
+	.write = spufs_cntl_write,
+#ifdef CONFIG_SPUFS_MMAP
+	.mmap = spufs_cntl_mmap,
+#endif
+};
+
 static int
 spufs_regs_open(struct inode *inode, struct file *file)
 {
@@ -501,6 +607,16 @@
 	.read	= spufs_wbox_stat_read,
 };
 
+static int spufs_signal1_open(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	struct spu_context *ctx = i->i_ctx;
+	file->private_data = ctx;
+	file->f_mapping = inode->i_mapping;
+	ctx->signal1 = inode->i_mapping;
+	return nonseekable_open(inode, file);
+}
+
 static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
 			size_t len, loff_t *pos)
 {
@@ -541,12 +657,50 @@
 	return 4;
 }
 
+#ifdef CONFIG_SPUFS_MMAP
+static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma,
+					      unsigned long address, int *type)
+{
+	return spufs_ps_nopage(vma, address, type, 0x14000);
+}
+
+static struct vm_operations_struct spufs_signal1_mmap_vmops = {
+	.nopage = spufs_signal1_mmap_nopage,
+};
+
+static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	if (!(vma->vm_flags & VM_SHARED))
+		return -EINVAL;
+
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+				     | _PAGE_NO_CACHE);
+
+	vma->vm_ops = &spufs_signal1_mmap_vmops;
+	return 0;
+}
+#endif
+
 static struct file_operations spufs_signal1_fops = {
-	.open = spufs_pipe_open,
+	.open = spufs_signal1_open,
 	.read = spufs_signal1_read,
 	.write = spufs_signal1_write,
+#ifdef CONFIG_SPUFS_MMAP
+	.mmap = spufs_signal1_mmap,
+#endif
 };
 
+static int spufs_signal2_open(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	struct spu_context *ctx = i->i_ctx;
+	file->private_data = ctx;
+	file->f_mapping = inode->i_mapping;
+	ctx->signal2 = inode->i_mapping;
+	return nonseekable_open(inode, file);
+}
+
 static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
 			size_t len, loff_t *pos)
 {
@@ -589,10 +743,39 @@
 	return 4;
 }
 
+#ifdef CONFIG_SPUFS_MMAP
+static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma,
+					      unsigned long address, int *type)
+{
+	return spufs_ps_nopage(vma, address, type, 0x1c000);
+}
+
+static struct vm_operations_struct spufs_signal2_mmap_vmops = {
+	.nopage = spufs_signal2_mmap_nopage,
+};
+
+static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	if (!(vma->vm_flags & VM_SHARED))
+		return -EINVAL;
+
+	/* FIXME: */
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+				     | _PAGE_NO_CACHE);
+
+	vma->vm_ops = &spufs_signal2_mmap_vmops;
+	return 0;
+}
+#endif
+
 static struct file_operations spufs_signal2_fops = {
-	.open = spufs_pipe_open,
+	.open = spufs_signal2_open,
 	.read = spufs_signal2_read,
 	.write = spufs_signal2_write,
+#ifdef CONFIG_SPUFS_MMAP
+	.mmap = spufs_signal2_mmap,
+#endif
 };
 
 static void spufs_signal1_type_set(void *data, u64 val)
@@ -641,6 +824,332 @@
 DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
 					spufs_signal2_type_set, "%llu");
 
+#ifdef CONFIG_SPUFS_MMAP
+static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma,
+					   unsigned long address, int *type)
+{
+	return spufs_ps_nopage(vma, address, type, 0x3000);
+}
+
+static struct vm_operations_struct spufs_mfc_mmap_vmops = {
+	.nopage = spufs_mfc_mmap_nopage,
+};
+
+/*
+ * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
+ * Mapping this area requires that the application have CAP_SYS_RAWIO,
+ * as these registers require special care when read/writing.
+ */
+static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	if (!(vma->vm_flags & VM_SHARED))
+		return -EINVAL;
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+				     | _PAGE_NO_CACHE);
+
+	vma->vm_ops = &spufs_mfc_mmap_vmops;
+	return 0;
+}
+#endif
+
+static int spufs_mfc_open(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	struct spu_context *ctx = i->i_ctx;
+
+	/* we don't want to deal with DMA into other processes */
+	if (ctx->owner != current->mm)
+		return -EINVAL;
+
+	if (atomic_read(&inode->i_count) != 1)
+		return -EBUSY;
+
+	file->private_data = ctx;
+	return nonseekable_open(inode, file);
+}
+
+/* interrupt-level mfc callback function. */
+void spufs_mfc_callback(struct spu *spu)
+{
+	struct spu_context *ctx = spu->ctx;
+
+	wake_up_all(&ctx->mfc_wq);
+
+	pr_debug("%s %s\n", __FUNCTION__, spu->name);
+	if (ctx->mfc_fasync) {
+		u32 free_elements, tagstatus;
+		unsigned int mask;
+
+		/* no need for spu_acquire in interrupt context */
+		free_elements = ctx->ops->get_mfc_free_elements(ctx);
+		tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
+
+		mask = 0;
+		if (free_elements & 0xffff)
+			mask |= POLLOUT;
+		if (tagstatus & ctx->tagwait)
+			mask |= POLLIN;
+
+		kill_fasync(&ctx->mfc_fasync, SIGIO, mask);
+	}
+}
+
+static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status)
+{
+	/* See if there is one tag group is complete */
+	/* FIXME we need locking around tagwait */
+	*status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait;
+	ctx->tagwait &= ~*status;
+	if (*status)
+		return 1;
+
+	/* enable interrupt waiting for any tag group,
+	   may silently fail if interrupts are already enabled */
+	ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
+	return 0;
+}
+
+static ssize_t spufs_mfc_read(struct file *file, char __user *buffer,
+			size_t size, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	int ret = -EINVAL;
+	u32 status;
+
+	if (size != 4)
+		goto out;
+
+	spu_acquire(ctx);
+	if (file->f_flags & O_NONBLOCK) {
+		status = ctx->ops->read_mfc_tagstatus(ctx);
+		if (!(status & ctx->tagwait))
+			ret = -EAGAIN;
+		else
+			ctx->tagwait &= ~status;
+	} else {
+		ret = spufs_wait(ctx->mfc_wq,
+			   spufs_read_mfc_tagstatus(ctx, &status));
+	}
+	spu_release(ctx);
+
+	if (ret)
+		goto out;
+
+	ret = 4;
+	if (copy_to_user(buffer, &status, 4))
+		ret = -EFAULT;
+
+out:
+	return ret;
+}
+
+static int spufs_check_valid_dma(struct mfc_dma_command *cmd)
+{
+	pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa,
+		 cmd->ea, cmd->size, cmd->tag, cmd->cmd);
+
+	switch (cmd->cmd) {
+	case MFC_PUT_CMD:
+	case MFC_PUTF_CMD:
+	case MFC_PUTB_CMD:
+	case MFC_GET_CMD:
+	case MFC_GETF_CMD:
+	case MFC_GETB_CMD:
+		break;
+	default:
+		pr_debug("invalid DMA opcode %x\n", cmd->cmd);
+		return -EIO;
+	}
+
+	if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) {
+		pr_debug("invalid DMA alignment, ea %lx lsa %x\n",
+				cmd->ea, cmd->lsa);
+		return -EIO;
+	}
+
+	switch (cmd->size & 0xf) {
+	case 1:
+		break;
+	case 2:
+		if (cmd->lsa & 1)
+			goto error;
+		break;
+	case 4:
+		if (cmd->lsa & 3)
+			goto error;
+		break;
+	case 8:
+		if (cmd->lsa & 7)
+			goto error;
+		break;
+	case 0:
+		if (cmd->lsa & 15)
+			goto error;
+		break;
+	error:
+	default:
+		pr_debug("invalid DMA alignment %x for size %x\n",
+			cmd->lsa & 0xf, cmd->size);
+		return -EIO;
+	}
+
+	if (cmd->size > 16 * 1024) {
+		pr_debug("invalid DMA size %x\n", cmd->size);
+		return -EIO;
+	}
+
+	if (cmd->tag & 0xfff0) {
+		/* we reserve the higher tag numbers for kernel use */
+		pr_debug("invalid DMA tag\n");
+		return -EIO;
+	}
+
+	if (cmd->class) {
+		/* not supported in this version */
+		pr_debug("invalid DMA class\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int spu_send_mfc_command(struct spu_context *ctx,
+				struct mfc_dma_command cmd,
+				int *error)
+{
+	*error = ctx->ops->send_mfc_command(ctx, &cmd);
+	if (*error == -EAGAIN) {
+		/* wait for any tag group to complete
+		   so we have space for the new command */
+		ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
+		/* try again, because the queue might be
+		   empty again */
+		*error = ctx->ops->send_mfc_command(ctx, &cmd);
+		if (*error == -EAGAIN)
+			return 0;
+	}
+	return 1;
+}
+
+static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer,
+			size_t size, loff_t *pos)
+{
+	struct spu_context *ctx = file->private_data;
+	struct mfc_dma_command cmd;
+	int ret = -EINVAL;
+
+	if (size != sizeof cmd)
+		goto out;
+
+	ret = -EFAULT;
+	if (copy_from_user(&cmd, buffer, sizeof cmd))
+		goto out;
+
+	ret = spufs_check_valid_dma(&cmd);
+	if (ret)
+		goto out;
+
+	spu_acquire_runnable(ctx);
+	if (file->f_flags & O_NONBLOCK) {
+		ret = ctx->ops->send_mfc_command(ctx, &cmd);
+	} else {
+		int status;
+		ret = spufs_wait(ctx->mfc_wq,
+				 spu_send_mfc_command(ctx, cmd, &status));
+		if (status)
+			ret = status;
+	}
+	spu_release(ctx);
+
+	if (ret)
+		goto out;
+
+	ctx->tagwait |= 1 << cmd.tag;
+
+out:
+	return ret;
+}
+
+static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait)
+{
+	struct spu_context *ctx = file->private_data;
+	u32 free_elements, tagstatus;
+	unsigned int mask;
+
+	spu_acquire(ctx);
+	ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2);
+	free_elements = ctx->ops->get_mfc_free_elements(ctx);
+	tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
+	spu_release(ctx);
+
+	poll_wait(file, &ctx->mfc_wq, wait);
+
+	mask = 0;
+	if (free_elements & 0xffff)
+		mask |= POLLOUT | POLLWRNORM;
+	if (tagstatus & ctx->tagwait)
+		mask |= POLLIN | POLLRDNORM;
+
+	pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__,
+		free_elements, tagstatus, ctx->tagwait);
+
+	return mask;
+}
+
+static int spufs_mfc_flush(struct file *file)
+{
+	struct spu_context *ctx = file->private_data;
+	int ret;
+
+	spu_acquire(ctx);
+#if 0
+/* this currently hangs */
+	ret = spufs_wait(ctx->mfc_wq,
+			 ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2));
+	if (ret)
+		goto out;
+	ret = spufs_wait(ctx->mfc_wq,
+			 ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait);
+out:
+#else
+	ret = 0;
+#endif
+	spu_release(ctx);
+
+	return ret;
+}
+
+static int spufs_mfc_fsync(struct file *file, struct dentry *dentry,
+			   int datasync)
+{
+	return spufs_mfc_flush(file);
+}
+
+static int spufs_mfc_fasync(int fd, struct file *file, int on)
+{
+	struct spu_context *ctx = file->private_data;
+
+	return fasync_helper(fd, file, on, &ctx->mfc_fasync);
+}
+
+static struct file_operations spufs_mfc_fops = {
+	.open	 = spufs_mfc_open,
+	.read	 = spufs_mfc_read,
+	.write	 = spufs_mfc_write,
+	.poll	 = spufs_mfc_poll,
+	.flush	 = spufs_mfc_flush,
+	.fsync	 = spufs_mfc_fsync,
+	.fasync	 = spufs_mfc_fasync,
+#ifdef CONFIG_SPUFS_MMAP
+	.mmap	 = spufs_mfc_mmap,
+#endif
+};
+
 static void spufs_npc_set(void *data, u64 val)
 {
 	struct spu_context *ctx = data;
@@ -783,6 +1292,8 @@
 	{ "signal2", &spufs_signal2_fops, 0666, },
 	{ "signal1_type", &spufs_signal1_type, 0666, },
 	{ "signal2_type", &spufs_signal2_type, 0666, },
+	{ "mfc", &spufs_mfc_fops, 0666, },
+	{ "cntl", &spufs_cntl_fops,  0666, },
 	{ "npc", &spufs_npc_ops, 0666, },
 	{ "fpcr", &spufs_fpcr_fops, 0666, },
 	{ "decr", &spufs_decr_ops, 0666, },
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
index 5445719..a13a8b5 100644
--- a/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -232,6 +232,59 @@
 	spin_unlock_irq(&ctx->spu->register_lock);
 }
 
+static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)
+{
+	struct spu_problem *prob = ctx->spu->problem;
+	int ret;
+
+	spin_lock_irq(&ctx->spu->register_lock);
+	ret = -EAGAIN;
+	if (in_be32(&prob->dma_querytype_RW))
+		goto out;
+	ret = 0;
+	out_be32(&prob->dma_querymask_RW, mask);
+	out_be32(&prob->dma_querytype_RW, mode);
+out:
+	spin_unlock_irq(&ctx->spu->register_lock);
+	return ret;
+}
+
+static u32 spu_hw_read_mfc_tagstatus(struct spu_context * ctx)
+{
+	return in_be32(&ctx->spu->problem->dma_tagstatus_R);
+}
+
+static u32 spu_hw_get_mfc_free_elements(struct spu_context *ctx)
+{
+	return in_be32(&ctx->spu->problem->dma_qstatus_R);
+}
+
+static int spu_hw_send_mfc_command(struct spu_context *ctx,
+					struct mfc_dma_command *cmd)
+{
+	u32 status;
+	struct spu_problem *prob = ctx->spu->problem;
+
+	spin_lock_irq(&ctx->spu->register_lock);
+	out_be32(&prob->mfc_lsa_W, cmd->lsa);
+	out_be64(&prob->mfc_ea_W, cmd->ea);
+	out_be32(&prob->mfc_union_W.by32.mfc_size_tag32,
+				cmd->size << 16 | cmd->tag);
+	out_be32(&prob->mfc_union_W.by32.mfc_class_cmd32,
+				cmd->class << 16 | cmd->cmd);
+	status = in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32);
+	spin_unlock_irq(&ctx->spu->register_lock);
+
+	switch (status & 0xffff) {
+	case 0:
+		return 0;
+	case 2:
+		return -EAGAIN;
+	default:
+		return -EINVAL;
+	}
+}
+
 struct spu_context_ops spu_hw_ops = {
 	.mbox_read = spu_hw_mbox_read,
 	.mbox_stat_read = spu_hw_mbox_stat_read,
@@ -252,4 +305,8 @@
 	.get_ls = spu_hw_get_ls,
 	.runcntl_write = spu_hw_runcntl_write,
 	.runcntl_stop = spu_hw_runcntl_stop,
+	.set_mfc_query = spu_hw_set_mfc_query,
+	.read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,
+	.get_mfc_free_elements = spu_hw_get_mfc_free_elements,
+	.send_mfc_command = spu_hw_send_mfc_command,
 };
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index b3962c3..d955419 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -103,7 +103,7 @@
 
 static int
 spufs_new_file(struct super_block *sb, struct dentry *dentry,
-		struct file_operations *fops, int mode,
+		const struct file_operations *fops, int mode,
 		struct spu_context *ctx)
 {
 	static struct inode_operations spufs_file_iops = {
@@ -241,7 +241,7 @@
 		inode->i_gid = dir->i_gid;
 		inode->i_mode &= S_ISGID;
 	}
-	ctx = alloc_spu_context(inode->i_mapping);
+	ctx = alloc_spu_context();
 	SPUFS_I(inode)->i_ctx = ctx;
 	if (!ctx)
 		goto out_iput;
@@ -442,7 +442,7 @@
 	.kill_sb = kill_litter_super,
 };
 
-static int spufs_init(void)
+static int __init spufs_init(void)
 {
 	int ret;
 	ret = -ENOMEM;
@@ -472,7 +472,7 @@
 }
 module_init(spufs_init);
 
-static void spufs_exit(void)
+static void __exit spufs_exit(void)
 {
 	spu_sched_exit();
 	unregister_spu_syscalls(&spufs_calls);
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 18ea886..c04e078 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -76,6 +76,90 @@
 	return 0;
 }
 
+/*
+ * SPU syscall restarting is tricky because we violate the basic
+ * assumption that the signal handler is running on the interrupted
+ * thread. Here instead, the handler runs on PowerPC user space code,
+ * while the syscall was called from the SPU.
+ * This means we can only do a very rough approximation of POSIX
+ * signal semantics.
+ */
+int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret,
+			  unsigned int *npc)
+{
+	int ret;
+
+	switch (*spu_ret) {
+	case -ERESTARTSYS:
+	case -ERESTARTNOINTR:
+		/*
+		 * Enter the regular syscall restarting for
+		 * sys_spu_run, then restart the SPU syscall
+		 * callback.
+		 */
+		*npc -= 8;
+		ret = -ERESTARTSYS;
+		break;
+	case -ERESTARTNOHAND:
+	case -ERESTART_RESTARTBLOCK:
+		/*
+		 * Restart block is too hard for now, just return -EINTR
+		 * to the SPU.
+		 * ERESTARTNOHAND comes from sys_pause, we also return
+		 * -EINTR from there.
+		 * Assume that we need to be restarted ourselves though.
+		 */
+		*spu_ret = -EINTR;
+		ret = -ERESTARTSYS;
+		break;
+	default:
+		printk(KERN_WARNING "%s: unexpected return code %ld\n",
+			__FUNCTION__, *spu_ret);
+		ret = 0;
+	}
+	return ret;
+}
+
+int spu_process_callback(struct spu_context *ctx)
+{
+	struct spu_syscall_block s;
+	u32 ls_pointer, npc;
+	char *ls;
+	long spu_ret;
+	int ret;
+
+	/* get syscall block from local store */
+	npc = ctx->ops->npc_read(ctx);
+	ls = ctx->ops->get_ls(ctx);
+	ls_pointer = *(u32*)(ls + npc);
+	if (ls_pointer > (LS_SIZE - sizeof(s)))
+		return -EFAULT;
+	memcpy(&s, ls + ls_pointer, sizeof (s));
+
+	/* do actual syscall without pinning the spu */
+	ret = 0;
+	spu_ret = -ENOSYS;
+	npc += 4;
+
+	if (s.nr_ret < __NR_syscalls) {
+		spu_release(ctx);
+		/* do actual system call from here */
+		spu_ret = spu_sys_callback(&s);
+		if (spu_ret <= -ERESTARTSYS) {
+			ret = spu_handle_restartsys(ctx, &spu_ret, &npc);
+		}
+		spu_acquire(ctx);
+		if (ret == -ERESTARTSYS)
+			return ret;
+	}
+
+	/* write result, jump over indirect pointer */
+	memcpy(ls + ls_pointer, &spu_ret, sizeof (spu_ret));
+	ctx->ops->npc_write(ctx, npc);
+	ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
+	return ret;
+}
+
 static inline int spu_process_events(struct spu_context *ctx)
 {
 	struct spu *spu = ctx->spu;
@@ -107,6 +191,13 @@
 		ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
 		if (unlikely(ret))
 			break;
+		if ((*status & SPU_STATUS_STOPPED_BY_STOP) &&
+		    (*status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
+			ret = spu_process_callback(ctx);
+			if (ret)
+				break;
+			*status &= ~SPU_STATUS_STOPPED_BY_STOP;
+		}
 		if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
 			ret = spu_reacquire_runnable(ctx, npc, status);
 			if (ret)
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 963182f..bf652cd 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -180,6 +180,7 @@
 	spu->ibox_callback = spufs_ibox_callback;
 	spu->wbox_callback = spufs_wbox_callback;
 	spu->stop_callback = spufs_stop_callback;
+	spu->mfc_callback = spufs_mfc_callback;
 	mb();
 	spu_unmap_mappings(ctx);
 	spu_restore(&ctx->csa, spu);
@@ -197,6 +198,7 @@
 	spu->ibox_callback = NULL;
 	spu->wbox_callback = NULL;
 	spu->stop_callback = NULL;
+	spu->mfc_callback = NULL;
 	spu->mm = NULL;
 	spu->pid = 0;
 	spu->prio = MAX_PRIO;
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index db2601f..4485738 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -43,7 +43,11 @@
 	struct spu *spu;		  /* pointer to a physical SPU */
 	struct spu_state csa;		  /* SPU context save area. */
 	spinlock_t mmio_lock;		  /* protects mmio access */
-	struct address_space *local_store;/* local store backing store */
+	struct address_space *local_store; /* local store mapping.  */
+	struct address_space *mfc;	   /* 'mfc' area mappings. */
+	struct address_space *cntl; 	   /* 'control' area mappings. */
+	struct address_space *signal1; 	   /* 'signal1' area mappings. */
+	struct address_space *signal2; 	   /* 'signal2' area mappings. */
 
 	enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
 	struct rw_semaphore state_sema;
@@ -55,13 +59,27 @@
 	wait_queue_head_t ibox_wq;
 	wait_queue_head_t wbox_wq;
 	wait_queue_head_t stop_wq;
+	wait_queue_head_t mfc_wq;
 	struct fasync_struct *ibox_fasync;
 	struct fasync_struct *wbox_fasync;
+	struct fasync_struct *mfc_fasync;
+	u32 tagwait;
 	struct spu_context_ops *ops;
 	struct work_struct reap_work;
 	u64 flags;
 };
 
+struct mfc_dma_command {
+	int32_t pad;	/* reserved */
+	uint32_t lsa;	/* local storage address */
+	uint64_t ea;	/* effective address */
+	uint16_t size;	/* transfer size */
+	uint16_t tag;	/* command tag */
+	uint16_t class;	/* class ID */
+	uint16_t cmd;	/* command opcode */
+};
+
+
 /* SPU context query/set operations. */
 struct spu_context_ops {
 	int (*mbox_read) (struct spu_context * ctx, u32 * data);
@@ -84,6 +102,11 @@
 	char*(*get_ls) (struct spu_context * ctx);
 	void (*runcntl_write) (struct spu_context * ctx, u32 data);
 	void (*runcntl_stop) (struct spu_context * ctx);
+	int (*set_mfc_query)(struct spu_context * ctx, u32 mask, u32 mode);
+	u32 (*read_mfc_tagstatus)(struct spu_context * ctx);
+	u32 (*get_mfc_free_elements)(struct spu_context *ctx);
+	int (*send_mfc_command)(struct spu_context *ctx,
+					struct mfc_dma_command *cmd);
 };
 
 extern struct spu_context_ops spu_hw_ops;
@@ -106,7 +129,7 @@
 extern struct file_operations spufs_context_fops;
 
 /* context management */
-struct spu_context * alloc_spu_context(struct address_space *local_store);
+struct spu_context * alloc_spu_context(void);
 void destroy_spu_context(struct kref *kref);
 struct spu_context * get_spu_context(struct spu_context *ctx);
 int put_spu_context(struct spu_context *ctx);
@@ -159,5 +182,6 @@
 void spufs_ibox_callback(struct spu *spu);
 void spufs_wbox_callback(struct spu *spu);
 void spufs_stop_callback(struct spu *spu);
+void spufs_mfc_callback(struct spu *spu);
 
 #endif
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index 212db28..97898d5 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -2145,7 +2145,8 @@
 	csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR |
 	    CLASS1_ENABLE_STORAGE_FAULT_INTR;
 	csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_SPU_STOP_INTR |
-	    CLASS2_ENABLE_SPU_HALT_INTR;
+	    CLASS2_ENABLE_SPU_HALT_INTR |
+	    CLASS2_ENABLE_SPU_DMA_TAG_GROUP_COMPLETE_INTR;
 }
 
 static void init_priv2(struct spu_state *csa)
diff --git a/arch/powerpc/platforms/chrp/chrp.h b/arch/powerpc/platforms/chrp/chrp.h
index 814f547..63f0aee 100644
--- a/arch/powerpc/platforms/chrp/chrp.h
+++ b/arch/powerpc/platforms/chrp/chrp.h
@@ -8,4 +8,4 @@
 extern long chrp_time_init(void);
 
 extern void chrp_find_bridges(void);
-extern void chrp_event_scan(void);
+extern void chrp_event_scan(unsigned long);
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index 8bf4307..23a2017 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -35,6 +35,7 @@
 #include <linux/root_dev.h>
 #include <linux/initrd.h>
 #include <linux/module.h>
+#include <linux/timer.h>
 
 #include <asm/io.h>
 #include <asm/pgtable.h>
@@ -61,6 +62,10 @@
 
 struct mpic *chrp_mpic;
 
+/* Used for doing CHRP event-scans */
+DEFINE_PER_CPU(struct timer_list, heartbeat_timer);
+unsigned long event_scan_interval;
+
 /*
  * XXX this should be in xmon.h, but putting it there means xmon.h
  * has to include <linux/interrupt.h> (to get irqreturn_t), which
@@ -229,8 +234,6 @@
 {
 	struct device_node *root = find_path_device ("/");
 	char *machine = NULL;
-	struct device_node *device;
-	unsigned int *p = NULL;
 
 	/* init to some ~sane value until calibrate_delay() runs */
 	loops_per_jiffy = 50000000/HZ;
@@ -287,23 +290,12 @@
 	 */
 	sio_init();
 
-	/* Get the event scan rate for the rtas so we know how
-	 * often it expects a heartbeat. -- Cort
-	 */
-	device = find_devices("rtas");
-	if (device)
-		p = (unsigned int *) get_property
-			(device, "rtas-event-scan-rate", NULL);
-	if (p && *p) {
-		ppc_md.heartbeat = chrp_event_scan;
-		ppc_md.heartbeat_reset = HZ / (*p * 30) - 1;
-		ppc_md.heartbeat_count = 1;
-		printk("RTAS Event Scan Rate: %u (%lu jiffies)\n",
-		       *p, ppc_md.heartbeat_reset);
-	}
-
 	pci_create_OF_bus_map();
 
+#ifdef CONFIG_SMP
+	smp_ops = &chrp_smp_ops;
+#endif /* CONFIG_SMP */
+
 	/*
 	 * Print the banner, then scroll down so boot progress
 	 * can be printed.  -- Cort
@@ -312,7 +304,7 @@
 }
 
 void
-chrp_event_scan(void)
+chrp_event_scan(unsigned long unused)
 {
 	unsigned char log[1024];
 	int ret = 0;
@@ -320,7 +312,8 @@
 	/* XXX: we should loop until the hardware says no more error logs -- Cort */
 	rtas_call(rtas_token("event-scan"), 4, 1, &ret, 0xffffffff, 0,
 		  __pa(log), 1024);
-	ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
+	mod_timer(&__get_cpu_var(heartbeat_timer),
+		  jiffies + event_scan_interval);
 }
 
 /*
@@ -465,6 +458,9 @@
 void __init
 chrp_init2(void)
 {
+	struct device_node *device;
+	unsigned int *p = NULL;
+
 #ifdef CONFIG_NVRAM
 	chrp_nvram_init();
 #endif
@@ -476,12 +472,53 @@
 	request_region(0x80,0x10,"dma page reg");
 	request_region(0xc0,0x20,"dma2");
 
+	/* Get the event scan rate for the rtas so we know how
+	 * often it expects a heartbeat. -- Cort
+	 */
+	device = find_devices("rtas");
+	if (device)
+		p = (unsigned int *) get_property
+			(device, "rtas-event-scan-rate", NULL);
+	if (p && *p) {
+		/*
+		 * Arrange to call chrp_event_scan at least *p times
+		 * per minute.  We use 59 rather than 60 here so that
+		 * the rate will be slightly higher than the minimum.
+		 * This all assumes we don't do hotplug CPU on any
+		 * machine that needs the event scans done.
+		 */
+		unsigned long interval, offset;
+		int cpu, ncpus;
+		struct timer_list *timer;
+
+		interval = HZ * 59 / *p;
+		offset = HZ;
+		ncpus = num_online_cpus();
+		event_scan_interval = ncpus * interval;
+		for (cpu = 0; cpu < ncpus; ++cpu) {
+			timer = &per_cpu(heartbeat_timer, cpu);
+			setup_timer(timer, chrp_event_scan, 0);
+			timer->expires = jiffies + offset;
+			add_timer_on(timer, cpu);
+			offset += interval;
+		}
+		printk("RTAS Event Scan Rate: %u (%lu jiffies)\n",
+		       *p, interval);
+	}
+
 	if (ppc_md.progress)
 		ppc_md.progress("  Have fun!    ", 0x7777);
 }
 
-void __init chrp_init(void)
+static int __init chrp_probe(void)
 {
+ 	char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
+ 					  "device_type", NULL);
+ 	if (dtype == NULL)
+ 		return 0;
+ 	if (strcmp(dtype, "chrp"))
+		return 0;
+
 	ISA_DMA_THRESHOLD = ~0L;
 	DMA_MODE_READ = 0x44;
 	DMA_MODE_WRITE = 0x48;
diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c
index 12c6f68..7d78890 100644
--- a/arch/powerpc/platforms/chrp/time.c
+++ b/arch/powerpc/platforms/chrp/time.c
@@ -120,33 +120,15 @@
 void chrp_get_rtc_time(struct rtc_time *tm)
 {
 	unsigned int year, mon, day, hour, min, sec;
-	int uip, i;
 
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-
-	/* Since the UIP flag is set for about 2.2 ms and the clock
-	 * is typically written with a precision of 1 jiffy, trying
-	 * to obtain a precision better than a few milliseconds is
-	 * an illusion. Only consistency is interesting, this also
-	 * allows to use the routine for /dev/rtc without a potential
-	 * 1 second kernel busy loop triggered by any reader of /dev/rtc.
-	 */
-
-	for ( i = 0; i<1000000; i++) {
-		uip = chrp_cmos_clock_read(RTC_FREQ_SELECT);
+	do {
 		sec = chrp_cmos_clock_read(RTC_SECONDS);
 		min = chrp_cmos_clock_read(RTC_MINUTES);
 		hour = chrp_cmos_clock_read(RTC_HOURS);
 		day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH);
 		mon = chrp_cmos_clock_read(RTC_MONTH);
 		year = chrp_cmos_clock_read(RTC_YEAR);
-		uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT);
-		if ((uip & RTC_UIP)==0) break;
-	}
+	} while (sec != chrp_cmos_clock_read(RTC_SECONDS));
 
 	if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
 		BCD_TO_BIN(sec);
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index fa45506..6ce8a40 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -675,18 +675,20 @@
 void __init iSeries_init_IRQ(void) { }
 #endif
 
-static int __init iseries_probe(int platform)
+static int __init iseries_probe(void)
 {
-	if (PLATFORM_ISERIES_LPAR != platform)
+	unsigned long root = of_get_flat_dt_root();
+	if (!of_flat_dt_is_compatible(root, "IBM,iSeries"))
 		return 0;
 
-	ppc64_firmware_features |= FW_FEATURE_ISERIES;
-	ppc64_firmware_features |= FW_FEATURE_LPAR;
+	powerpc_firmware_features |= FW_FEATURE_ISERIES;
+	powerpc_firmware_features |= FW_FEATURE_LPAR;
 
 	return 1;
 }
 
-struct machdep_calls __initdata iseries_md = {
+define_machine(iseries) {
+	.name		= "iSeries",
 	.setup_arch	= iSeries_setup_arch,
 	.show_cpuinfo	= iSeries_show_cpuinfo,
 	.init_IRQ	= iSeries_init_IRQ,
@@ -930,7 +932,6 @@
 
 	/* /chosen */
 	dt_start_node(dt, "chosen");
-	dt_prop_u32(dt, "linux,platform", PLATFORM_ISERIES_LPAR);
 	dt_prop_str(dt, "bootargs", cmd_line);
 	if (cmd_mem_limit)
 		dt_prop_u64(dt, "linux,memory-limit", cmd_mem_limit);
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index ec5c1e1..24c0aef 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -259,9 +259,10 @@
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
  */
-static int __init maple_probe(int platform)
+static int __init maple_probe(void)
 {
-	if (platform != PLATFORM_MAPLE)
+	unsigned long root = of_get_flat_dt_root();
+	if (!of_flat_dt_is_compatible(root, "Momentum,Maple"))
 		return 0;
 	/*
 	 * On U3, the DART (iommu) must be allocated now since it
@@ -274,7 +275,8 @@
 	return 1;
 }
 
-struct machdep_calls __initdata maple_md = {
+define_machine(maple_md) {
+	.name			= "Maple",
 	.probe			= maple_probe,
 	.setup_arch		= maple_setup_arch,
 	.init_early		= maple_init_early,
@@ -290,7 +292,7 @@
        	.get_rtc_time		= maple_get_rtc_time,
       	.calibrate_decr		= generic_calibrate_decr,
 	.progress		= maple_progress,
-	.idle_loop		= native_idle,
+	.power_save		= power4_idle,
 #ifdef CONFIG_KEXEC
 	.machine_kexec		= default_machine_kexec,
 	.machine_kexec_prepare	= default_machine_kexec_prepare,
diff --git a/arch/powerpc/platforms/maple/time.c b/arch/powerpc/platforms/maple/time.c
index 5e6981d..b9a2b3d 100644
--- a/arch/powerpc/platforms/maple/time.c
+++ b/arch/powerpc/platforms/maple/time.c
@@ -60,34 +60,14 @@
 
 void maple_get_rtc_time(struct rtc_time *tm)
 {
-	int uip, i;
-
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-
-	/* Since the UIP flag is set for about 2.2 ms and the clock
-	 * is typically written with a precision of 1 jiffy, trying
-	 * to obtain a precision better than a few milliseconds is
-	 * an illusion. Only consistency is interesting, this also
-	 * allows to use the routine for /dev/rtc without a potential
-	 * 1 second kernel busy loop triggered by any reader of /dev/rtc.
-	 */
-
-	for (i = 0; i<1000000; i++) {
-		uip = maple_clock_read(RTC_FREQ_SELECT);
+	do {
 		tm->tm_sec = maple_clock_read(RTC_SECONDS);
 		tm->tm_min = maple_clock_read(RTC_MINUTES);
 		tm->tm_hour = maple_clock_read(RTC_HOURS);
 		tm->tm_mday = maple_clock_read(RTC_DAY_OF_MONTH);
 		tm->tm_mon = maple_clock_read(RTC_MONTH);
 		tm->tm_year = maple_clock_read(RTC_YEAR);
-		uip |= maple_clock_read(RTC_FREQ_SELECT);
-		if ((uip & RTC_UIP)==0)
-			break;
-	}
+	} while (tm->tm_sec != maple_clock_read(RTC_SECONDS));
 
 	if (!(maple_clock_read(RTC_CONTROL) & RTC_DM_BINARY)
 	    || RTC_ALWAYS_BCD) {
diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c
index fa8b4d7..eacbfd9 100644
--- a/arch/powerpc/platforms/powermac/bootx_init.c
+++ b/arch/powerpc/platforms/powermac/bootx_init.c
@@ -161,9 +161,7 @@
 static void __init bootx_add_chosen_props(unsigned long base,
 					  unsigned long *mem_end)
 {
-	u32 val = _MACH_Pmac;
-
-	bootx_dt_add_prop("linux,platform", &val, 4, mem_end);
+	u32 val;
 
 	if (bootx_info->kernelParamsOffset) {
 		char *args = (char *)((unsigned long)bootx_info) +
@@ -493,7 +491,7 @@
 		    && (strcmp(model, "iMac,1") == 0
 			|| strcmp(model, "PowerMac1,1") == 0)) {
 			bootx_printf("iMac,1 detected, shutting down USB \n");
-			out_le32((unsigned *)0x80880008, 1);	/* XXX */
+			out_le32((unsigned __iomem *)0x80880008, 1);	/* XXX */
 		}
 	}
 
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index a415e8d..b57e465 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -21,6 +21,7 @@
 #include <linux/cpufreq.h>
 #include <linux/init.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/irq.h>
@@ -90,7 +91,7 @@
 static int (*g5_switch_freq)(int speed_mode);
 static int (*g5_query_freq)(void);
 
-static DECLARE_MUTEX(g5_switch_mutex);
+static DEFINE_MUTEX(g5_switch_mutex);
 
 
 static struct smu_sdbp_fvt *g5_fvt_table;	/* table of op. points */
@@ -327,7 +328,7 @@
 	if (g5_pmode_cur == newstate)
 		return 0;
 
-	down(&g5_switch_mutex);
+	mutex_lock(&g5_switch_mutex);
 
 	freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
 	freqs.new = g5_cpu_freqs[newstate].frequency;
@@ -337,7 +338,7 @@
 	rc = g5_switch_freq(newstate);
 	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
-	up(&g5_switch_mutex);
+	mutex_unlock(&g5_switch_mutex);
 
 	return rc;
 }
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
index e49eddd..a5063cd 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -2951,7 +2951,7 @@
 
 void pmac_set_early_video_resume(void (*proc)(void *data), void *data)
 {
-	if (_machine != _MACH_Pmac)
+	if (!machine_is(powermac))
 		return;
 	preempt_disable();
 	pmac_early_vresume_proc = proc;
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index 87eb6bb..e14f9ac 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -1457,6 +1457,9 @@
 		return 0;
 	i2c_inited = 1;
 
+	if (!machine_is(powermac))
+		return 0;
+
 	/* Probe keywest-i2c busses */
 	kw_i2c_probe();
 
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
index 5fd2899..262f967 100644
--- a/arch/powerpc/platforms/powermac/nvram.c
+++ b/arch/powerpc/platforms/powermac/nvram.c
@@ -74,7 +74,7 @@
  * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
  */
 static int nvram_naddrs;
-static volatile unsigned char *nvram_data;
+static volatile unsigned char __iomem *nvram_data;
 static int is_core_99;
 static int core99_bank = 0;
 static int nvram_partitions[3];
@@ -148,7 +148,7 @@
 }
 
 #ifdef CONFIG_PPC32
-static volatile unsigned char *nvram_addr;
+static volatile unsigned char __iomem *nvram_addr;
 static int nvram_mult;
 
 static unsigned char direct_nvram_read_byte(int addr)
@@ -285,7 +285,7 @@
 	int stat, i;
 	unsigned long timeout;
 
-	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+	u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
 
        	DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank);
 
@@ -317,7 +317,7 @@
 	int i, stat = 0;
 	unsigned long timeout;
 
-	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+	u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
 
        	DBG("nvram: Sharp/Micron Writing bank %d...\n", bank);
 
@@ -352,7 +352,7 @@
 	int i, stat = 0;
 	unsigned long timeout;
 
-	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+	u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
 
        	DBG("nvram: AMD Erasing bank %d...\n", bank);
 
@@ -399,7 +399,7 @@
 	int i, stat = 0;
 	unsigned long timeout;
 
-	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+	u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
 
        	DBG("nvram: AMD Writing bank %d...\n", bank);
 
@@ -597,7 +597,7 @@
 	}
 
 #ifdef CONFIG_PPC32
-	if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+	if (machine_is(chrp) && nvram_naddrs == 1) {
 		nvram_data = ioremap(r1.start, s1);
 		nvram_mult = 1;
 		ppc_md.nvram_read_val	= direct_nvram_read_byte;
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index de3f30e..f5d8d15 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -1201,7 +1201,7 @@
 #ifdef CONFIG_PPC32
 void pmac_pci_fixup_cardbus(struct pci_dev* dev)
 {
-	if (_machine != _MACH_Pmac)
+	if (!machine_is(powermac))
 		return;
 	/*
 	 * Fix the interrupt routing on the various cardbus bridges
@@ -1244,8 +1244,9 @@
         * On PowerMacs, we try to switch any PCI ATA controller to
 	* fully native mode
         */
-	if (_machine != _MACH_Pmac)
+	if (!machine_is(powermac))
 		return;
+
 	/* Some controllers don't have the class IDE */
 	if (dev->vendor == PCI_VENDOR_ID_PROMISE)
 		switch(dev->device) {
diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c
index 9b7150f..a3bd3e7 100644
--- a/arch/powerpc/platforms/powermac/pfunc_base.c
+++ b/arch/powerpc/platforms/powermac/pfunc_base.c
@@ -336,6 +336,8 @@
 		return 0;
 	pfbase_inited = 1;
 
+	if (!machine_is(powermac))
+		return 0;
 
 	DBG("Installing base platform functions...\n");
 
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 385aab9..4d15e39 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -350,6 +350,13 @@
 		smp_ops = &psurge_smp_ops;
 #endif
 #endif /* CONFIG_SMP */
+
+#ifdef CONFIG_ADB
+	if (strstr(cmd_line, "adb_sync")) {
+		extern int __adb_probe_sync;
+		__adb_probe_sync = 1;
+	}
+#endif /* CONFIG_ADB */
 }
 
 char *bootpath;
@@ -576,30 +583,6 @@
 	pmac_power_off();
 }
 
-#ifdef CONFIG_PPC32
-void __init pmac_init(void)
-{
-	/* isa_io_base gets set in pmac_pci_init */
-	isa_mem_base = PMAC_ISA_MEM_BASE;
-	pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
-	ISA_DMA_THRESHOLD = ~0L;
-	DMA_MODE_READ = 1;
-	DMA_MODE_WRITE = 2;
-
-	ppc_md = pmac_md;
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-        ppc_ide_md.ide_init_hwif	= pmac_ide_init_hwif_ports;
-        ppc_ide_md.default_io_base	= pmac_ide_get_base;
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
-
-	if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
-
-}
-#endif
-
 /* 
  * Early initialization.
  */
@@ -646,6 +629,12 @@
 {
 	struct device_node *np;
 
+	if (machine_is(chrp))
+		return -1;
+
+	if (!machine_is(powermac))
+		return 0;
+
 	np = of_find_node_by_name(NULL, "valkyrie");
 	if (np)
 		of_platform_device_create(np, "valkyrie", NULL);
@@ -666,12 +655,15 @@
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
  */
-static int __init pmac_probe(int platform)
+static int __init pmac_probe(void)
 {
-#ifdef CONFIG_PPC64
-	if (platform != PLATFORM_POWERMAC)
+	unsigned long root = of_get_flat_dt_root();
+
+	if (!of_flat_dt_is_compatible(root, "Power Macintosh") &&
+	    !of_flat_dt_is_compatible(root, "MacRISC"))
 		return 0;
 
+#ifdef CONFIG_PPC64
 	/*
 	 * On U3, the DART (iommu) must be allocated now since it
 	 * has an impact on htab_initialize (due to the large page it
@@ -681,6 +673,23 @@
 	alloc_dart_table();
 #endif
 
+#ifdef CONFIG_PPC32
+	/* isa_io_base gets set in pmac_pci_init */
+	isa_mem_base = PMAC_ISA_MEM_BASE;
+	pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
+	ISA_DMA_THRESHOLD = ~0L;
+	DMA_MODE_READ = 1;
+	DMA_MODE_WRITE = 2;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+        ppc_ide_md.ide_init_hwif	= pmac_ide_init_hwif_ports;
+        ppc_ide_md.default_io_base	= pmac_ide_get_base;
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
+
+#endif /* CONFIG_PPC32 */
+
 #ifdef CONFIG_PMAC_SMU
 	/*
 	 * SMU based G5s need some memory below 2Gb, at least the current
@@ -709,10 +718,8 @@
 }
 #endif
 
-struct machdep_calls __initdata pmac_md = {
-#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64)
-	.cpu_die		= generic_mach_cpu_die,
-#endif
+define_machine(powermac) {
+	.name			= "PowerMac",
 	.probe			= pmac_probe,
 	.setup_arch		= pmac_setup_arch,
 	.init_early		= pmac_init_early,
@@ -733,7 +740,7 @@
 	.progress		= udbg_progress,
 #ifdef CONFIG_PPC64
 	.pci_probe_mode		= pmac_pci_probe_mode,
-	.idle_loop		= native_idle,
+	.power_save		= power4_idle,
 	.enable_pmcs		= power4_enable_pmcs,
 #ifdef CONFIG_KEXEC
 	.machine_kexec		= default_machine_kexec,
@@ -746,4 +753,7 @@
 	.pcibios_after_init	= pmac_pcibios_after_init,
 	.phys_mem_access_prot	= pci_phys_mem_access_prot,
 #endif
+#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64)
+	.cpu_die		= generic_mach_cpu_die,
+#endif
 };
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index 5d9afa1..890758a 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -336,10 +336,10 @@
  */
 void __init pmac_calibrate_decr(void)
 {
-#ifdef CONFIG_PM
+#if defined(CONFIG_PM) && defined(CONFIG_ADB_PMU)
 	/* XXX why here? */
 	pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif /* CONFIG_PM */
+#endif
 
 	generic_calibrate_decr();
 
diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
index c4352a8..b4fa9f0 100644
--- a/arch/powerpc/platforms/powermac/udbg_scc.c
+++ b/arch/powerpc/platforms/powermac/udbg_scc.c
@@ -116,7 +116,7 @@
 	/* Setup for 57600 8N1 */
 	if (ch == ch_a)
 		addr += 0x20;
-	sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
+	sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
 	sccc += addr & ~PAGE_MASK;
 	sccd = sccc + 0x10;
 
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 2ab9dcd..9b2b1cb 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -1018,7 +1018,7 @@
 {
 	struct proc_dir_entry *e;
 
-	if (platform_is_pseries()) {
+	if (machine_is(pseries)) {
 		e = create_proc_entry("ppc64/eeh", 0, NULL);
 		if (e)
 			e->proc_fops = &proc_eeh_operations;
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index b811d5f..cc2495a 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -257,6 +257,7 @@
 	struct pci_bus *frozen_bus;
 	int rc = 0;
 	enum pci_ers_result result = PCI_ERS_RESULT_NONE;
+	const char *pci_str, *drv_str;
 
 	frozen_dn = find_device_pe(event->dn);
 	frozen_bus = pcibios_find_pci_bus(frozen_dn);
@@ -291,6 +292,13 @@
 
 	frozen_pdn = PCI_DN(frozen_dn);
 	frozen_pdn->eeh_freeze_count++;
+
+	pci_str = pci_name (frozen_pdn->pcidev);
+	drv_str = pcid_name (frozen_pdn->pcidev);
+	if (!pci_str) {
+		pci_str = pci_name (event->dev);
+		drv_str = pcid_name (event->dev);
+	}
 	
 	if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
 		goto hard_fail;
@@ -306,9 +314,7 @@
 	eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */);
 	printk(KERN_WARNING
 	   "EEH: This PCI device has failed %d times since last reboot: %s - %s\n",
-		frozen_pdn->eeh_freeze_count,
-		pci_name (frozen_pdn->pcidev), 
-		pcid_name(frozen_pdn->pcidev));
+		frozen_pdn->eeh_freeze_count, drv_str, pci_str);
 
 	/* Walk the various device drivers attached to this slot through
 	 * a reset sequence, giving each an opportunity to do what it needs
@@ -360,9 +366,7 @@
 	   "EEH: PCI device %s - %s has failed %d times \n"
 	   "and has been permanently disabled.  Please try reseating\n"
 	   "this device or replacing it.\n",
-		pci_name (frozen_pdn->pcidev), 
-		pcid_name(frozen_pdn->pcidev), 
-		frozen_pdn->eeh_freeze_count);
+		drv_str, pci_str, frozen_pdn->eeh_freeze_count);
 
 	eeh_slot_error_detail(frozen_pdn, 2 /* Permanent Error */);
 
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 989f4bc..c01d8f0 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -91,7 +91,7 @@
 				continue;
 
 			/* we have a match */
-			ppc64_firmware_features |=
+			powerpc_firmware_features |=
 				firmware_features_table[i].val;
 			break;
 		}
diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c
index 138e128..ba6befd 100644
--- a/arch/powerpc/platforms/pseries/hvconsole.c
+++ b/arch/powerpc/platforms/pseries/hvconsole.c
@@ -62,6 +62,11 @@
 	unsigned long *lbuf = (unsigned long *) buf;
 	long ret;
 
+
+	/* hcall will ret H_PARAMETER if 'count' exceeds firmware max.*/
+	if (count > MAX_VIO_PUT_CHARS)
+		count = MAX_VIO_PUT_CHARS;
+
 	ret = plpar_hcall_norets(H_PUT_TERM_CHAR, vtermno, count, lbuf[0],
 				 lbuf[1]);
 	if (ret == H_Success)
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index 946ad59..e97e67f 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -120,7 +120,7 @@
 	int i;
 	unsigned int reg;
 
-	if (!platform_is_pseries())
+	if (!machine_is(pseries))
 		return;
 
 	printk("Using INTC for W82c105 IDE controller.\n");
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index 44abdeb..6bfacc2 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -28,6 +28,7 @@
 #include <linux/pci.h>
 #include <asm/pci-bridge.h>
 #include <asm/ppc-pci.h>
+#include <asm/firmware.h>
 
 static struct pci_bus *
 find_bus_among_children(struct pci_bus *bus,
@@ -152,20 +153,24 @@
 void
 pcibios_add_pci_devices(struct pci_bus * bus)
 {
-	int slotno, num;
+	int slotno, num, mode;
 	struct pci_dev *dev;
 	struct device_node *dn = pci_bus_to_OF_node(bus);
 
 	eeh_add_device_tree_early(dn);
 
-	if (_machine == PLATFORM_PSERIES_LPAR) {
+	mode = PCI_PROBE_NORMAL;
+	if (ppc_md.pci_probe_mode)
+		mode = ppc_md.pci_probe_mode(bus);
+
+	if (mode == PCI_PROBE_DEVTREE) {
 		/* use ofdt-based probe */
 		of_scan_bus(dn, bus);
 		if (!list_empty(&bus->devices)) {
 			pcibios_fixup_new_pci_devices(bus, 0);
 			pci_bus_add_devices(bus);
 		}
-	} else {
+	} else if (mode == PCI_PROBE_NORMAL) {
 		/* use legacy probe */
 		slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
 		num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index b046bcf..9639c66 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -132,7 +132,7 @@
 		of_node_put(np);
 	}
 
-	return 1;
+	return 0;
 }
 __initcall(init_ras_IRQ);
 
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index 86cfa6e..1773103 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -17,8 +17,9 @@
 #include <linux/proc_fs.h>
 
 #include <asm/prom.h>
-#include <asm/pSeries_reconfig.h>
+#include <asm/machdep.h>
 #include <asm/uaccess.h>
+#include <asm/pSeries_reconfig.h>
 
 
 
@@ -94,16 +95,16 @@
 	return parent;
 }
 
-static struct notifier_block *pSeries_reconfig_chain;
+static BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain);
 
 int pSeries_reconfig_notifier_register(struct notifier_block *nb)
 {
-	return notifier_chain_register(&pSeries_reconfig_chain, nb);
+	return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb);
 }
 
 void pSeries_reconfig_notifier_unregister(struct notifier_block *nb)
 {
-	notifier_chain_unregister(&pSeries_reconfig_chain, nb);
+	blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb);
 }
 
 static int pSeries_reconfig_add_node(const char *path, struct property *proplist)
@@ -131,7 +132,7 @@
 		goto out_err;
 	}
 
-	err = notifier_call_chain(&pSeries_reconfig_chain,
+	err = blocking_notifier_call_chain(&pSeries_reconfig_chain,
 				  PSERIES_RECONFIG_ADD, np);
 	if (err == NOTIFY_BAD) {
 		printk(KERN_ERR "Failed to add device node %s\n", path);
@@ -171,7 +172,7 @@
 
 	remove_node_proc_entries(np);
 
-	notifier_call_chain(&pSeries_reconfig_chain,
+	blocking_notifier_call_chain(&pSeries_reconfig_chain,
 			    PSERIES_RECONFIG_REMOVE, np);
 	of_detach_node(np);
 
@@ -508,7 +509,7 @@
 {
 	struct proc_dir_entry *ent;
 
-	if (!platform_is_pseries())
+	if (!machine_is(pseries))
 		return 0;
 
 	ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL);
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
index a6f628d..fcc4d56 100644
--- a/arch/powerpc/platforms/pseries/rtasd.c
+++ b/arch/powerpc/platforms/pseries/rtasd.c
@@ -27,6 +27,7 @@
 #include <asm/prom.h>
 #include <asm/nvram.h>
 #include <asm/atomic.h>
+#include <asm/machdep.h>
 
 #if 0
 #define DEBUG(A...)	printk(KERN_ERR A)
@@ -481,7 +482,7 @@
 {
 	struct proc_dir_entry *entry;
 
-	if (!platform_is_pseries())
+	if (!machine_is(pseries))
 		return 0;
 
 	/* No RTAS */
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 44d5c7f..b2fbf8b 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -81,8 +81,8 @@
 
 int fwnmi_active;  /* TRUE if an FWNMI handler is present */
 
-static void pseries_shared_idle(void);
-static void pseries_dedicated_idle(void);
+static void pseries_shared_idle_sleep(void);
+static void pseries_dedicated_idle_sleep(void);
 
 struct mpic *pSeries_mpic;
 
@@ -236,14 +236,13 @@
 		vpa_init(boot_cpuid);
 		if (get_lppaca()->shared_proc) {
 			printk(KERN_INFO "Using shared processor idle loop\n");
-			ppc_md.idle_loop = pseries_shared_idle;
+			ppc_md.power_save = pseries_shared_idle_sleep;
 		} else {
 			printk(KERN_INFO "Using dedicated idle loop\n");
-			ppc_md.idle_loop = pseries_dedicated_idle;
+			ppc_md.power_save = pseries_dedicated_idle_sleep;
 		}
 	} else {
 		printk(KERN_INFO "Using default idle loop\n");
-		ppc_md.idle_loop = default_idle;
 	}
 
 	if (firmware_has_feature(FW_FEATURE_LPAR))
@@ -373,156 +372,123 @@
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
  */
-extern struct machdep_calls pSeries_md;
 
-static int __init pSeries_probe(int platform)
+static int __init pSeries_probe_hypertas(unsigned long node,
+					 const char *uname, int depth,
+					 void *data)
 {
-	if (platform != PLATFORM_PSERIES &&
-	    platform != PLATFORM_PSERIES_LPAR)
+	if (depth != 1 ||
+	    (strcmp(uname, "rtas") != 0 && strcmp(uname, "rtas@0") != 0))
+ 		return 0;
+
+	if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL)
+ 		powerpc_firmware_features |= FW_FEATURE_LPAR;
+
+ 	return 1;
+}
+
+static int __init pSeries_probe(void)
+{
+ 	char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
+ 					  "device_type", NULL);
+ 	if (dtype == NULL)
+ 		return 0;
+ 	if (strcmp(dtype, "chrp"))
 		return 0;
 
-	/* if we have some ppc_md fixups for LPAR to do, do
-	 * it here ...
-	 */
+	DBG("pSeries detected, looking for LPAR capability...\n");
 
-	if (platform == PLATFORM_PSERIES_LPAR)
-		ppc64_firmware_features |= FW_FEATURE_LPAR;
+	/* Now try to figure out if we are running on LPAR */
+	of_scan_flat_dt(pSeries_probe_hypertas, NULL);
+
+	DBG("Machine is%s LPAR !\n",
+	    (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not");
 
 	return 1;
 }
 
+
 DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
 
-static inline void dedicated_idle_sleep(unsigned int cpu)
-{
-	struct lppaca *plppaca = &lppaca[cpu ^ 1];
-
-	/* Only sleep if the other thread is not idle */
-	if (!(plppaca->idle)) {
-		local_irq_disable();
-
-		/*
-		 * We are about to sleep the thread and so wont be polling any
-		 * more.
-		 */
-		clear_thread_flag(TIF_POLLING_NRFLAG);
-		smp_mb__after_clear_bit();
-
-		/*
-		 * SMT dynamic mode. Cede will result in this thread going
-		 * dormant, if the partner thread is still doing work.  Thread
-		 * wakes up if partner goes idle, an interrupt is presented, or
-		 * a prod occurs.  Returning from the cede enables external
-		 * interrupts.
-		 */
-		if (!need_resched())
-			cede_processor();
-		else
-			local_irq_enable();
-		set_thread_flag(TIF_POLLING_NRFLAG);
-	} else {
-		/*
-		 * Give the HV an opportunity at the processor, since we are
-		 * not doing any work.
-		 */
-		poll_pending();
-	}
-}
-
-static void pseries_dedicated_idle(void)
+static void pseries_dedicated_idle_sleep(void)
 { 
 	unsigned int cpu = smp_processor_id();
 	unsigned long start_snooze;
 	unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
-	set_thread_flag(TIF_POLLING_NRFLAG);
 
-	while (1) {
-		/*
-		 * Indicate to the HV that we are idle. Now would be
-		 * a good time to find other work to dispatch.
-		 */
-		get_lppaca()->idle = 1;
+	/*
+	 * Indicate to the HV that we are idle. Now would be
+	 * a good time to find other work to dispatch.
+	 */
+	get_lppaca()->idle = 1;
 
-		if (!need_resched()) {
-			start_snooze = get_tb() +
-				*smt_snooze_delay * tb_ticks_per_usec;
+	/*
+	 * We come in with interrupts disabled, and need_resched()
+	 * has been checked recently.  If we should poll for a little
+	 * while, do so.
+	 */
+	if (*smt_snooze_delay) {
+		start_snooze = get_tb() +
+			*smt_snooze_delay * tb_ticks_per_usec;
+		local_irq_enable();
+		set_thread_flag(TIF_POLLING_NRFLAG);
 
-			while (!need_resched() && !cpu_is_offline(cpu)) {
-				ppc64_runlatch_off();
-
-				/*
-				 * Go into low thread priority and possibly
-				 * low power mode.
-				 */
-				HMT_low();
-				HMT_very_low();
-
-				if (*smt_snooze_delay != 0 &&
-				    get_tb() > start_snooze) {
-					HMT_medium();
-					dedicated_idle_sleep(cpu);
-				}
-
-			}
-
-			HMT_medium();
+		while (get_tb() < start_snooze) {
+			if (need_resched() || cpu_is_offline(cpu))
+				goto out;
+			ppc64_runlatch_off();
+			HMT_low();
+			HMT_very_low();
 		}
 
-		get_lppaca()->idle = 0;
-		ppc64_runlatch_on();
-
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
-
-		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
-			cpu_die();
+		HMT_medium();
+		clear_thread_flag(TIF_POLLING_NRFLAG);
+		smp_mb();
+		local_irq_disable();
+		if (need_resched() || cpu_is_offline(cpu))
+			goto out;
 	}
+
+	/*
+	 * Cede if the other thread is not idle, so that it can
+	 * go single-threaded.  If the other thread is idle,
+	 * we ask the hypervisor if it has pending work it
+	 * wants to do and cede if it does.  Otherwise we keep
+	 * polling in order to reduce interrupt latency.
+	 *
+	 * Doing the cede when the other thread is active will
+	 * result in this thread going dormant, meaning the other
+	 * thread gets to run in single-threaded (ST) mode, which
+	 * is slightly faster than SMT mode with this thread at
+	 * very low priority.  The cede enables interrupts, which
+	 * doesn't matter here.
+	 */
+	if (!lppaca[cpu ^ 1].idle || poll_pending() == H_Pending)
+		cede_processor();
+
+out:
+	HMT_medium();
+	get_lppaca()->idle = 0;
 }
 
-static void pseries_shared_idle(void)
+static void pseries_shared_idle_sleep(void)
 {
-	unsigned int cpu = smp_processor_id();
+	/*
+	 * Indicate to the HV that we are idle. Now would be
+	 * a good time to find other work to dispatch.
+	 */
+	get_lppaca()->idle = 1;
 
-	while (1) {
-		/*
-		 * Indicate to the HV that we are idle. Now would be
-		 * a good time to find other work to dispatch.
-		 */
-		get_lppaca()->idle = 1;
+	/*
+	 * Yield the processor to the hypervisor.  We return if
+	 * an external interrupt occurs (which are driven prior
+	 * to returning here) or if a prod occurs from another
+	 * processor. When returning here, external interrupts
+	 * are enabled.
+	 */
+	cede_processor();
 
-		while (!need_resched() && !cpu_is_offline(cpu)) {
-			local_irq_disable();
-			ppc64_runlatch_off();
-
-			/*
-			 * Yield the processor to the hypervisor.  We return if
-			 * an external interrupt occurs (which are driven prior
-			 * to returning here) or if a prod occurs from another
-			 * processor. When returning here, external interrupts
-			 * are enabled.
-			 *
-			 * Check need_resched() again with interrupts disabled
-			 * to avoid a race.
-			 */
-			if (!need_resched())
-				cede_processor();
-			else
-				local_irq_enable();
-
-			HMT_medium();
-		}
-
-		get_lppaca()->idle = 0;
-		ppc64_runlatch_on();
-
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
-
-		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
-			cpu_die();
-	}
+	get_lppaca()->idle = 0;
 }
 
 static int pSeries_pci_probe_mode(struct pci_bus *bus)
@@ -553,7 +519,8 @@
 }
 #endif
 
-struct machdep_calls __initdata pSeries_md = {
+define_machine(pseries) {
+	.name			= "pSeries",
 	.probe			= pSeries_probe,
 	.setup_arch		= pSeries_setup_arch,
 	.init_early		= pSeries_init_early,
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index eb86cdb..4864cb3 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -500,7 +500,7 @@
 	     np;
 	     np = of_find_node_by_type(np, "cpu")) {
 		ireg = (uint *)get_property(np, "reg", &ilen);
-		if (ireg && ireg[0] == boot_cpuid_phys) {
+		if (ireg && ireg[0] == get_hard_smp_processor_id(boot_cpuid)) {
 			ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s",
 						    &ilen);
 			i = ilen / sizeof(int);
@@ -541,7 +541,7 @@
 		ops = &pSeriesLP_ops;
 	else {
 #ifdef CONFIG_SMP
-		for_each_cpu(i) {
+		for_each_possible_cpu(i) {
 			int hard_id;
 
 			/* FIXME: Do this dynamically! --RR */
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index 54a0a9b..e9a8f5d 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -19,6 +19,10 @@
 	bool
 	default y
 
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
@@ -57,15 +61,15 @@
 	select PPC_FPU
 	help
 	  There are four types of PowerPC chips supported.  The more common
-	  types (601, 603, 604, 740, 750, 7400), the Motorola embedded
-	  versions (821, 823, 850, 855, 860, 52xx, 82xx, 83xx), the IBM
-	  embedded versions (403 and 405) and the POWER3 processor.
-	  (For support for more recent 64-bit processors, set ARCH=powerpc.)
+	  types (601, 603, 604, 740, 750, 7400), the older Freescale
+	  (formerly Motorola) embedded versions (821, 823, 850, 855, 860,
+	  52xx, 82xx, 83xx), the IBM embedded versions (403 and 405) and
+	  the Book E embedded processors from IBM (44x) and Freescale (85xx).
+	  For support for 64-bit processors, set ARCH=powerpc.
 	  Unless you are building a kernel for one of the embedded processor
-	  systems or a POWER3-based IBM RS/6000, choose 6xx.
-	  Note that the kernel runs in 32-bit mode even on 64-bit chips.
-	  Also note that because the 52xx, 82xx, & 83xx family has a 603e core,
-	  specific support for that chipset is asked later on.
+	  systems, choose 6xx.
+	  Also note that because the 52xx, 82xx, & 83xx family have a 603e
+	  core, specific support for that chipset is asked later on.
 
 config 40x
 	bool "40x"
@@ -73,10 +77,6 @@
 config 44x
 	bool "44x"
 
-config POWER3
-	select PPC_FPU
-	bool "POWER3"
-
 config 8xx
 	bool "8xx"
 
@@ -248,14 +248,9 @@
 source arch/ppc/platforms/4xx/Kconfig
 source arch/ppc/platforms/85xx/Kconfig
 
-config PPC64BRIDGE
-	bool
-	depends on POWER3
-	default y
-
 config PPC_STD_MMU
 	bool
-	depends on 6xx || POWER3
+	depends on 6xx
 	default y
 
 config NOT_COHERENT_CACHE
@@ -530,8 +525,8 @@
 
 choice
 	prompt "Machine Type"
-	depends on 6xx || POWER3
-	default PPC_MULTIPLATFORM
+	depends on 6xx
+	default PPC_PREP
 	---help---
 	  Linux currently supports several different kinds of PowerPC-based
 	  machines: Apple Power Macintoshes and clones (such as the Motorola
@@ -541,15 +536,14 @@
 	  Platform) machines (including all of the recent IBM RS/6000 and
 	  pSeries machines), and several embedded PowerPC systems containing
 	  4xx, 6xx, 7xx, 8xx, 74xx, and 82xx processors.  Currently, the
-	  default option is to build a kernel which works on PReP and CHRP.
+	  default option is to build a kernel which works on PReP.
 
-	  Note that support for Apple machines is now only available with
-	  ARCH=powerpc, and has been removed from this menu.  If you wish
-	  to build a kernel for an Apple machine, exit this configuration
-	  process and re-run it with ARCH=powerpc.
+	  Note that support for Apple and CHRP machines is now only available
+	  with ARCH=powerpc, and has been removed from this menu.  If you
+	  wish to build a kernel for an Apple or CHRP machine, exit this
+	  configuration process and re-run it with ARCH=powerpc.
 
-	  Select CHRP/PReP if configuring for an IBM RS/6000 or
-	  pSeries machine, or a PReP machine.
+	  Select PReP if configuring for a PReP machine.
 
 	  Select Gemini if configuring for a Synergy Microsystems' Gemini
 	  series Single Board Computer.  More information is available at:
@@ -558,8 +552,8 @@
 	  Select APUS if configuring for a PowerUP Amiga.  More information is
 	  available at: <http://linux-apus.sourceforge.net/>.
 
-config PPC_MULTIPLATFORM
-	bool "CHRP/PReP"
+config PPC_PREP
+	bool "PReP"
 
 config APUS
 	bool "Amiga-APUS"
@@ -711,6 +705,13 @@
 	  much but it's only been tested on this board version. I think this
 	  board is also known as IceCube.
 
+config LITE5200B
+	bool "Freescale LITE5200B"
+	depends LITE5200
+	help
+	  Support for the LITE5200B dev board for the MPC5200 from Freescale.
+	  This is the new board with 2 PCI slots.
+
 config MPC834x_SYS
 	bool "Freescale MPC834x SYS"
 	help
@@ -796,25 +797,6 @@
 	  you wish to build a kernel for a machine with a CPM2 coprocessor
 	  on it (826x, 827x, 8560).
 
-config PPC_CHRP
-	bool "Support for CHRP (Common Hardware Reference Platform) machines"
-	depends on PPC_MULTIPLATFORM
-	select PPC_I8259
-	select PPC_INDIRECT_PCI
-	default y
-
-config PPC_PREP
-	bool "Support for PReP (PowerPC Reference Platform) machines"
-	depends on PPC_MULTIPLATFORM
-	select PPC_I8259
-	select PPC_INDIRECT_PCI
-	default y
-
-config PPC_OF
-	bool
-	depends on PPC_CHRP
-	default y
-
 config PPC_GEN550
 	bool
 	depends on SANDPOINT || SPRUCE || PPLUS || \
@@ -973,14 +955,6 @@
 
 source "fs/Kconfig.binfmt"
 
-config PROC_DEVICETREE
-	bool "Support for Open Firmware device tree in /proc"
-	depends on PPC_OF && PROC_FS
-	help
-	  This option adds a device-tree directory under /proc which contains
-	  an image of the device tree that the kernel copies from Open
-	  Firmware. If unsure, say Y here.
-
 config PREP_RESIDUAL
 	bool "Support for PReP Residual Data"
 	depends on PPC_PREP
@@ -1173,8 +1147,7 @@
 
 config ISA
 	bool "Support for ISA-bus hardware"
-	depends on PPC_PREP || PPC_CHRP
-	select PPC_I8259
+	depends on PPC_PREP
 	help
 	  Find out whether you have ISA slots on your motherboard.  ISA is the
 	  name of a bus system, i.e. the way the CPU talks to the other stuff
@@ -1184,18 +1157,18 @@
 
 config GENERIC_ISA_DMA
 	bool
-	depends on POWER3 || 6xx && !CPM2
+	depends on 6xx && !CPM2
 	default y
 
 config PPC_I8259
 	bool
-	default y if 85xx
+	default y if 85xx || PPC_PREP
 	default n
 
 config PPC_INDIRECT_PCI
 	bool
 	depends on PCI
-	default y if 40x || 44x || 85xx || 83xx
+	default y if 40x || 44x || 85xx || 83xx || PPC_PREP
 	default n
 
 config EISA
@@ -1386,7 +1359,7 @@
 
 config BOOT_LOAD_BOOL
 	bool "Set the boot link/load address"
-	depends on ADVANCED_OPTIONS && !PPC_MULTIPLATFORM
+	depends on ADVANCED_OPTIONS && !PPC_PREP
 	help
 	  This option allows you to set the initial load address of the zImage
 	  or zImage.initrd file.  This can be useful if you are on a board
diff --git a/arch/ppc/Kconfig.debug b/arch/ppc/Kconfig.debug
index 8cc75ab..f94b877 100644
--- a/arch/ppc/Kconfig.debug
+++ b/arch/ppc/Kconfig.debug
@@ -53,13 +53,6 @@
 	  Unless you are intending to debug the kernel with one of these
 	  machines, say N here.
 
-config BOOTX_TEXT
-	bool "Support for early boot text console (BootX or OpenFirmware only)"
-	depends PPC_OF
-	help
-	  Say Y here to see progress messages from the boot firmware in text
-	  mode. Requires either BootX or Open Firmware.
-
 config SERIAL_TEXT_DEBUG
 	bool "Support for early boot texts over serial port"
 	depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
index 9fbdf54..0db66dc 100644
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -40,10 +40,8 @@
 CFLAGS		+= -mstring
 endif
 
-cpu-as-$(CONFIG_PPC64BRIDGE)	+= -Wa,-mppc64bridge
 cpu-as-$(CONFIG_4xx)		+= -Wa,-m405
 cpu-as-$(CONFIG_6xx)		+= -Wa,-maltivec
-cpu-as-$(CONFIG_POWER4)		+= -Wa,-maltivec
 cpu-as-$(CONFIG_E500)		+= -Wa,-me500
 cpu-as-$(CONFIG_E200)		+= -Wa,-me200
 
@@ -59,8 +57,6 @@
 head-$(CONFIG_44x)		:= arch/ppc/kernel/head_44x.o
 head-$(CONFIG_FSL_BOOKE)	:= arch/ppc/kernel/head_fsl_booke.o
 
-head-$(CONFIG_6xx)		+= arch/ppc/kernel/idle_6xx.o
-head-$(CONFIG_POWER4)		+= arch/ppc/kernel/idle_power4.o
 head-$(CONFIG_PPC_FPU)		+= arch/powerpc/kernel/fpu.o
 
 core-y				+= arch/ppc/kernel/ arch/powerpc/kernel/ \
@@ -71,7 +67,7 @@
 core-$(CONFIG_4xx)		+= arch/ppc/platforms/4xx/
 core-$(CONFIG_83xx)		+= arch/ppc/platforms/83xx/
 core-$(CONFIG_85xx)		+= arch/ppc/platforms/85xx/
-core-$(CONFIG_MATH_EMULATION)	+= arch/ppc/math-emu/
+core-$(CONFIG_MATH_EMULATION)	+= arch/powerpc/math-emu/
 core-$(CONFIG_XMON)		+= arch/ppc/xmon/
 core-$(CONFIG_APUS)		+= arch/ppc/amiga/
 drivers-$(CONFIG_8xx)		+= arch/ppc/8xx_io/
diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
index 84eec0b..b739e25 100644
--- a/arch/ppc/boot/Makefile
+++ b/arch/ppc/boot/Makefile
@@ -19,14 +19,13 @@
 BOOT_TARGETS	= zImage zImage.initrd znetboot znetboot.initrd
 
 bootdir-y			:= simple
-bootdir-$(CONFIG_PPC_OF)	+= openfirmware
 subdir-y			:= lib common images
-subdir-$(CONFIG_PPC_MULTIPLATFORM)	+= of1275
+subdir-$(CONFIG_PPC_PREP)	+= of1275
 
 # for cleaning
-subdir-				+= simple openfirmware
+subdir-				+= simple
 
-hostprogs-y := $(addprefix utils/, addnote mknote hack-coff mkprep mkbugboot mktree)
+hostprogs-y := $(addprefix utils/, mkprep mkbugboot mktree)
 
 PHONY += $(BOOT_TARGETS) $(bootdir-y)
 
diff --git a/arch/ppc/boot/openfirmware/Makefile b/arch/ppc/boot/openfirmware/Makefile
deleted file mode 100644
index 66b7397..0000000
--- a/arch/ppc/boot/openfirmware/Makefile
+++ /dev/null
@@ -1,109 +0,0 @@
-# Makefile for making bootable images on various OpenFirmware machines.
-#
-# This file is included by the global makefile so that you can add your own
-# architecture-specific flags and dependencies.
-#
-# Paul Mackerras	January 1997
-#	XCOFF bootable images for PowerMacs
-# Geert Uytterhoeven	September 1997
-#	ELF bootable iamges for CHRP machines.
-# Tom Rini		January 2001
-# 	Cleaned up, moved into arch/ppc/boot/pmac
-# Tom Rini		July/August 2002
-#	Merged 'chrp' and 'pmac' into 'openfirmware', and cleaned up the
-#	rules.
-
-zImage.initrd znetboot.initrd: del-ramdisk-sec	:= -R .ramdisk
-zImage.initrd znetboot.initrd: initrd		:= .initrd
-
-
-boot	:= arch/ppc/boot
-common	:= $(boot)/common
-utils	:= $(boot)/utils
-bootlib	:= $(boot)/lib
-of1275	:= $(boot)/of1275
-images	:= $(boot)/images
-
-CHRP_LD_ARGS	:= -T $(srctree)/$(boot)/ld.script -e _start -Ttext 0x00800000
-
-COMMONOBJS	:= start.o misc.o common.o
-CHRPOBJS	:= crt0.o     $(COMMONOBJS) chrpmain.o
-
-targets 	:= $(CHRPOBJS) dummy.o
-CHRPOBJS	:= $(addprefix $(obj)/, $(CHRPOBJS))
-
-LIBS		:= lib/lib.a $(bootlib)/lib.a $(of1275)/lib.a $(common)/lib.a
-
-ifdef CONFIG_SMP
-END := .smp
-endif
-ifdef CONFIG_PPC64BRIDGE
-END += .64
-endif
-
-
-$(images)/ramdisk.image.gz:
-	@echo '  MISSING $@'
-	@echo '          RAM disk image must be provided separately'
-	@/bin/false
-
-quiet_cmd_genimage = GEN     $@
-      cmd_genimage = $(OBJCOPY) -R .comment       \
-	--add-section=.image=$(images)/vmlinux.gz \
-	--set-section-flags=.image=contents,alloc,load,readonly,data $< $@
-
-targets += image.o
-$(obj)/image.o: $(obj)/dummy.o $(images)/vmlinux.gz FORCE
-	$(call if_changed,genimage)
-
-# Place the ramdisk in the initrd image.
-quiet_cmd_genimage-initrd = GEN     $@
-      cmd_genimage-initrd = $(OBJCOPY) $< $@ \
-	--add-section=.ramdisk=$(images)/ramdisk.image.gz \
-	--set-section-flags=.ramdisk=contents,alloc,load,readonly,data
-targets += image.initrd.o
-$(obj)/image.initrd.o: $(obj)/image.o $(images)/ramdisk.image.gz FORCE
-	$(call if_changed,genimage-initrd)
-
-
-targets += crt0.o
-$(obj)/crt0.o: $(common)/crt0.S FORCE
-	$(call if_changed_dep,as_o_S)
-
-quiet_cmd_gen-chrp = CHRP    $@
-      cmd_gen-chrp = $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) $< $(LIBS) && \
-			$(OBJCOPY) $@ $@ -R .comment $(del-ramdisk-sec)
-
-$(images)/zImage.chrp: $(obj)/image.o $(CHRPOBJS) $(LIBS) \
-				   $(srctree)/$(boot)/ld.script
-	$(call cmd,gen-chrp)
-$(images)/zImage.initrd.chrp: $(obj)/image.initrd.o $(CHRPOBJS) $(LIBS) \
-				   $(srctree)/$(boot)/ld.script
-	$(call cmd,gen-chrp)
-
-quiet_cmd_addnote = ADDNOTE $@
-      cmd_addnote = cat $< > $@ && $(utils)/addnote $@
-$(images)/zImage.chrp-rs6k $(images)/zImage.initrd.chrp-rs6k: \
-	%-rs6k: %
-	$(call cmd,addnote)
-
-# The targets used on the make command-line
-
-PHONY += zImage zImage.initrd
-zImage:		 $(images)/zImage.chrp		\
-		 $(images)/zImage.chrp-rs6k
-	@echo '  kernel: $@ is ready ($<)'
-zImage.initrd:	 $(images)/zImage.initrd.chrp		\
-		 $(images)/zImage.initrd.chrp-rs6k
-	@echo '  kernel: $@ is ready ($<)'
-
-TFTPIMAGE	:= /tftpboot/zImage
-
-PHONY += znetboot znetboot.initrd
-znetboot:	$(images)/zImage.chrp
-	cp $(images)/zImage.chrp      $(TFTPIMAGE).chrp$(END)
-	@echo '  kernel: $@ is ready ($<)'
-znetboot.initrd:$(images)/zImage.initrd.chrp
-	cp $(images)/zImage.initrd.chrp      $(TFTPIMAGE).chrp$(END)
-	@echo '  kernel: $@ is ready ($<)'
-
diff --git a/arch/ppc/boot/openfirmware/chrpmain.c b/arch/ppc/boot/openfirmware/chrpmain.c
deleted file mode 100644
index 245dbd9..0000000
--- a/arch/ppc/boot/openfirmware/chrpmain.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) Paul Mackerras 1997.
- *
- * 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/string.h>
-#include "nonstdio.h"
-#include "of1275.h"
-#include <asm/processor.h>
-#include <asm/page.h>
-
-/* Passed from the linker */
-extern char __image_begin, __image_end;
-extern char __ramdisk_begin, __ramdisk_end;
-extern char _start, _end;
-
-extern unsigned int heap_max;
-extern void flush_cache(void *, unsigned long);
-extern void gunzip(void *, int, unsigned char *, int *);
-extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach,
-		unsigned int progend);
-
-char *avail_ram;
-char *begin_avail, *end_avail;
-char *avail_high;
-
-#define RAM_START	0x00000000
-#define RAM_END		(64<<20)
-
-#define BOOT_START	((unsigned long)_start)
-#define BOOT_END	((unsigned long)(_end + 0xFFF) & ~0xFFF)
-
-#define RAM_FREE	((unsigned long)(_end+0x1000)&~0xFFF)
-#define PROG_START	0x00010000
-#define PROG_SIZE	0x007f0000 /* 8MB */
-
-#define SCRATCH_SIZE	(128 << 10)
-
-static char scratch[SCRATCH_SIZE];	/* 128k of scratch space for gunzip */
-
-typedef void (*kernel_start_t)(int, int, void *, unsigned int, unsigned int);
-
-void
-boot(int a1, int a2, void *prom)
-{
-    unsigned sa, len;
-    void *dst;
-    unsigned char *im;
-    unsigned int initrd_size, initrd_start;
-
-    printf("chrpboot starting: loaded at 0x%p\n\r", &_start);
-
-    initrd_size = &__ramdisk_end - &__ramdisk_begin;
-    if (initrd_size) {
-	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
-	a1 = initrd_start;
-	a2 = initrd_size;
-	claim(initrd_start, RAM_END - initrd_start, 0);
-	printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r",
-	       initrd_start, &__ramdisk_begin, initrd_size);
-	memcpy((char *)initrd_start, &__ramdisk_begin, initrd_size);
-    } else {
-	initrd_start = 0;
-	initrd_size = 0;
-	a2 = 0xdeadbeef;
-    }
-
-    im = &__image_begin;
-    len = &__image_end - &__image_begin;
-    /* claim 4MB starting at PROG_START */
-    claim(PROG_START, PROG_SIZE - PROG_START, 0);
-    dst = (void *) PROG_START;
-    if (im[0] == 0x1f && im[1] == 0x8b) {
-	avail_ram = scratch;
-	begin_avail = avail_high = avail_ram;
-	end_avail = scratch + sizeof(scratch);
-	printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len);
-	gunzip(dst, PROG_SIZE - PROG_START, im, &len);
-	printf("done %u bytes\n\r", len);
-	printf("%u bytes of heap consumed, max in use %u\n\r",
-	       avail_high - begin_avail, heap_max);
-    } else {
-	memmove(dst, im, len);
-    }
-
-    flush_cache(dst, len);
-    make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_chrp,
-		    (PROG_START + PROG_SIZE));
-
-    sa = PROG_START;
-    printf("start address = 0x%x\n\r", sa);
-
-    (*(kernel_start_t)sa)(a1, a2, prom, initrd_start, initrd_size);
-
-    printf("returned?\n\r");
-
-    pause();
-}
diff --git a/arch/ppc/boot/openfirmware/common.c b/arch/ppc/boot/openfirmware/common.c
deleted file mode 100644
index 0f46756..0000000
--- a/arch/ppc/boot/openfirmware/common.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) Paul Mackerras 1997.
- *
- * 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 "nonstdio.h"
-#include "of1275.h"
-#include <linux/string.h>
-#include <linux/zlib.h>
-#include <asm/bootinfo.h>
-#include <asm/page.h>
-
-/* Information from the linker */
-
-extern int strcmp(const char *s1, const char *s2);
-extern char *avail_ram, *avail_high;
-extern char *end_avail;
-
-unsigned int heap_use, heap_max;
-
-struct memchunk {
-    unsigned int size;
-    struct memchunk *next;
-};
-
-static struct memchunk *freechunks;
-
-static void *zalloc(unsigned size)
-{
-    void *p;
-    struct memchunk **mpp, *mp;
-
-    size = (size + 7) & -8;
-    heap_use += size;
-    if (heap_use > heap_max)
-	heap_max = heap_use;
-    for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) {
-	if (mp->size == size) {
-	    *mpp = mp->next;
-	    return mp;
-	}
-    }
-    p = avail_ram;
-    avail_ram += size;
-    if (avail_ram > avail_high)
-	avail_high = avail_ram;
-    if (avail_ram > end_avail) {
-	printf("oops... out of memory\n\r");
-	pause();
-    }
-    return p;
-}
-
-#define HEAD_CRC	2
-#define EXTRA_FIELD	4
-#define ORIG_NAME	8
-#define COMMENT		0x10
-#define RESERVED	0xe0
-
-void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
-{
-	z_stream s;
-	int r, i, flags;
-
-	/* skip header */
-	i = 10;
-	flags = src[3];
-	if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
-		printf("bad gzipped data\n\r");
-		exit();
-	}
-	if ((flags & EXTRA_FIELD) != 0)
-		i = 12 + src[10] + (src[11] << 8);
-	if ((flags & ORIG_NAME) != 0)
-		while (src[i++] != 0)
-			;
-	if ((flags & COMMENT) != 0)
-		while (src[i++] != 0)
-			;
-	if ((flags & HEAD_CRC) != 0)
-		i += 2;
-	if (i >= *lenp) {
-		printf("gunzip: ran out of data in header\n\r");
-		exit();
-	}
-
-	/* Initialize ourself. */
-	s.workspace = zalloc(zlib_inflate_workspacesize());
-	r = zlib_inflateInit2(&s, -MAX_WBITS);
-	if (r != Z_OK) {
-		printf("zlib_inflateInit2 returned %d\n\r", r);
-		exit();
-	}
-	s.next_in = src + i;
-	s.avail_in = *lenp - i;
-	s.next_out = dst;
-	s.avail_out = dstlen;
-	r = zlib_inflate(&s, Z_FINISH);
-	if (r != Z_OK && r != Z_STREAM_END) {
-		printf("inflate returned %d msg: %s\n\r", r, s.msg);
-		exit();
-	}
-	*lenp = s.next_out - (unsigned char *) dst;
-	zlib_inflateEnd(&s);
-}
-
-/* Make a bi_rec in OF.  We need to be passed a name for BI_BOOTLOADER_ID,
- * a machine type for BI_MACHTYPE, and the location where the end of the
- * bootloader is (PROG_START + PROG_SIZE)
- */
-void make_bi_recs(unsigned long addr, char *name, unsigned int mach,
-		unsigned long progend)
-{
-	struct bi_record *rec;
-
-
-	/* leave a 1MB gap then align to the next 1MB boundary */
-	addr = _ALIGN(addr+ (1<<20) - 1, (1<<20));
-	/* oldworld machine seem very unhappy about this. -- Tom */
-	if (addr >= progend)
-		claim(addr, 0x1000, 0);
-
-	rec = (struct bi_record *)addr;
-	rec->tag = BI_FIRST;
-	rec->size = sizeof(struct bi_record);
-	rec = (struct bi_record *)((unsigned long)rec + rec->size);
-
-	rec->tag = BI_BOOTLOADER_ID;
-	sprintf( (char *)rec->data, name);
-	rec->size = sizeof(struct bi_record) + strlen(name) + 1;
-	rec = (struct bi_record *)((unsigned long)rec + rec->size);
-
-	rec->tag = BI_MACHTYPE;
-	rec->data[0] = mach;
-	rec->data[1] = 1;
-	rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long);
-	rec = (struct bi_record *)((unsigned long)rec + rec->size);
-
-	rec->tag = BI_LAST;
-	rec->size = sizeof(struct bi_record);
-	rec = (struct bi_record *)((unsigned long)rec + rec->size);
-}
diff --git a/arch/ppc/boot/openfirmware/dummy.c b/arch/ppc/boot/openfirmware/dummy.c
deleted file mode 100644
index 31dbf45..0000000
--- a/arch/ppc/boot/openfirmware/dummy.c
+++ /dev/null
@@ -1,4 +0,0 @@
-int main(void)
-{
-	return 0;
-}
diff --git a/arch/ppc/boot/openfirmware/misc.S b/arch/ppc/boot/openfirmware/misc.S
deleted file mode 100644
index ab9e897..0000000
--- a/arch/ppc/boot/openfirmware/misc.S
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) Paul Mackerras 1997.
- *
- * 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.
- */
-	.text
-
-/*
- * Use the BAT2 & 3 registers to map the 1st 16MB of RAM to
- * the address given as the 1st argument.
- */
-	.globl	setup_bats
-setup_bats:
-	mfpvr	5
-	rlwinm	5,5,16,16,31		/* r3 = 1 for 601, 4 for 604 */
-	cmpwi	0,5,1
-	li	0,0
-	bne	4f
-	mtibatl	3,0			/* invalidate BAT first */
-	ori	3,3,4			/* set up BAT registers for 601 */
-	li	4,0x7f
-	mtibatu	2,3
-	mtibatl	2,4
-	oris	3,3,0x80
-	oris	4,4,0x80
-	mtibatu	3,3
-	mtibatl	3,4
-	b	5f
-4:	mtdbatu	3,0			/* invalidate BATs first */
-	mtibatu	3,0
-	ori	3,3,0xff		/* set up BAT registers for 604 */
-	li	4,2
-	mtdbatl	2,4
-	mtdbatu	2,3
-	mtibatl	2,4
-	mtibatu	2,3
-	oris	3,3,0x80
-	oris	4,4,0x80
-	mtdbatl	3,4
-	mtdbatu	3,3
-	mtibatl	3,4
-	mtibatu	3,3
-5:	sync
-	isync
-	blr
-
-/*
- * Flush the dcache and invalidate the icache for a range of addresses.
- *
- * flush_cache(addr, len)
- */
-	.global	flush_cache
-flush_cache:
-	addi	4,4,0x1f	/* len = (len + 0x1f) / 0x20 */
-	rlwinm.	4,4,27,5,31
-	mtctr	4
-	beqlr
-1:	dcbf	0,3
-	icbi	0,3
-	addi	3,3,0x20
-	bdnz	1b
-	sync
-	isync
-	blr
diff --git a/arch/ppc/boot/openfirmware/start.c b/arch/ppc/boot/openfirmware/start.c
deleted file mode 100644
index 1617a26..0000000
--- a/arch/ppc/boot/openfirmware/start.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) Paul Mackerras 1997.
- *
- * 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 <stdarg.h>
-#include "of1275.h"
-
-extern int strlen(const char *s);
-extern void boot(int a1, int a2, void *prom);
-
-phandle stdin;
-phandle stdout;
-phandle stderr;
-
-void printk(char *fmt, ...);
-
-void
-start(int a1, int a2, void *promptr)
-{
-    ofinit(promptr);
-    if (ofstdio(&stdin, &stdout, &stderr))
-	exit();
-
-    boot(a1, a2, promptr);
-    for (;;)
-	exit();
-}
-
-int writestring(void *f, char *ptr, int nb)
-{
-	int w = 0, i;
-	char *ret = "\r";
-
-	for (i = 0; i < nb; ++i) {
-		if (ptr[i] == '\n') {
-			if (i > w) {
-				write(f, ptr + w, i - w);
-				w = i;
-			}
-			write(f, ret, 1);
-		}
-	}
-	if (w < nb)
-		write(f, ptr + w, nb - w);
-	return nb;
-}
-
-int
-putc(int c, void *f)
-{
-    char ch = c;
-
-    return writestring(f, &ch, 1) == 1? c: -1;
-}
-
-int
-putchar(int c)
-{
-    return putc(c, stdout);
-}
-
-int
-fputs(char *str, void *f)
-{
-    int n = strlen(str);
-
-    return writestring(f, str, n) == n? 0: -1;
-}
-
-int
-readchar(void)
-{
-    char ch;
-
-    for (;;) {
-	switch (read(stdin, &ch, 1)) {
-	case 1:
-	    return ch;
-	case -1:
-	    printk("read(stdin) returned -1\n");
-	    return -1;
-	}
-    }
-}
-
-static char line[256];
-static char *lineptr;
-static int lineleft;
-
-int
-getchar(void)
-{
-    int c;
-
-    if (lineleft == 0) {
-	lineptr = line;
-	for (;;) {
-	    c = readchar();
-	    if (c == -1 || c == 4)
-		break;
-	    if (c == '\r' || c == '\n') {
-		*lineptr++ = '\n';
-		putchar('\n');
-		break;
-	    }
-	    switch (c) {
-	    case 0177:
-	    case '\b':
-		if (lineptr > line) {
-		    putchar('\b');
-		    putchar(' ');
-		    putchar('\b');
-		    --lineptr;
-		}
-		break;
-	    case 'U' & 0x1F:
-		while (lineptr > line) {
-		    putchar('\b');
-		    putchar(' ');
-		    putchar('\b');
-		    --lineptr;
-		}
-		break;
-	    default:
-		if (lineptr >= &line[sizeof(line) - 1])
-		    putchar('\a');
-		else {
-		    putchar(c);
-		    *lineptr++ = c;
-		}
-	    }
-	}
-	lineleft = lineptr - line;
-	lineptr = line;
-    }
-    if (lineleft == 0)
-	return -1;
-    --lineleft;
-    return *lineptr++;
-}
-
-extern int vsprintf(char *buf, const char *fmt, va_list args);
-static char sprint_buf[1024];
-
-void
-printk(char *fmt, ...)
-{
-	va_list args;
-	int n;
-
-	va_start(args, fmt);
-	n = vsprintf(sprint_buf, fmt, args);
-	va_end(args);
-	writestring(stdout, sprint_buf, n);
-}
-
-int
-printf(char *fmt, ...)
-{
-	va_list args;
-	int n;
-
-	va_start(args, fmt);
-	n = vsprintf(sprint_buf, fmt, args);
-	va_end(args);
-	writestring(stdout, sprint_buf, n);
-	return n;
-}
diff --git a/arch/ppc/boot/simple/mpc10x_memory.c b/arch/ppc/boot/simple/mpc10x_memory.c
index c242908..8da8f57 100644
--- a/arch/ppc/boot/simple/mpc10x_memory.c
+++ b/arch/ppc/boot/simple/mpc10x_memory.c
@@ -50,10 +50,10 @@
  * the system.  This assumes that the firmware has correctly set up the memory
  * controller registers.  On CONFIG_PPC_PREP, we know we are being called
  * under a PReP memory map. On all other machines, we assume we are under
- * a CHRP memory map.  Further, on CONFIG_PPC_MULTIPLATFORM we must rename
+ * a CHRP memory map.  Further, on CONFIG_PPC_PREP we must rename
  * this function.
  */
-#ifdef CONFIG_PPC_MULTIPLATFORM
+#ifdef CONFIG_PPC_PREP
 #define get_mem_size mpc10x_get_mem_size
 #endif
 unsigned long
diff --git a/arch/ppc/boot/simple/relocate.S b/arch/ppc/boot/simple/relocate.S
index 7efddc5..2533113 100644
--- a/arch/ppc/boot/simple/relocate.S
+++ b/arch/ppc/boot/simple/relocate.S
@@ -194,7 +194,7 @@
 	/*
 	 * Start at the begining.
 	 */
-#ifdef CONFIG_PPC_MULTIPLATFORM
+#ifdef CONFIG_PPC_PREP
 	li	r9,0xc
 	mtlr	r9
 	/* tell kernel we're prep, by putting 0xdeadc0de at KERNELLOAD,
diff --git a/arch/ppc/boot/utils/addnote.c b/arch/ppc/boot/utils/addnote.c
deleted file mode 100644
index 6c52b18..0000000
--- a/arch/ppc/boot/utils/addnote.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Program to hack in a PT_NOTE program header entry in an ELF file.
- * This is needed for OF on RS/6000s to load an image correctly.
- * Note that OF needs a program header entry for the note, not an
- * ELF section.
- *
- * Copyright 2000 Paul Mackerras.
- *
- * 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.
- *
- * Usage: addnote zImage
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-
-char arch[] = "PowerPC";
-
-#define N_DESCR	6
-unsigned int descr[N_DESCR] = {
-#if 1
-	/* values for IBM RS/6000 machines */
-	0xffffffff,		/* real-mode = true */
-	0x00c00000,		/* real-base, i.e. where we expect OF to be */
-	0xffffffff,		/* real-size */
-	0xffffffff,		/* virt-base */
-	0xffffffff,		/* virt-size */
-	0x4000,			/* load-base */
-#else
-	/* values for longtrail CHRP */
-	0,			/* real-mode = false */
-	0xffffffff,		/* real-base */
-	0xffffffff,		/* real-size */
-	0xffffffff,		/* virt-base */
-	0xffffffff,		/* virt-size */
-	0x00600000,		/* load-base */
-#endif
-};
-
-unsigned char buf[512];
-
-#define GET_16BE(off)	((buf[off] << 8) + (buf[(off)+1]))
-#define GET_32BE(off)	((GET_16BE(off) << 16) + GET_16BE((off)+2))
-
-#define PUT_16BE(off, v)	(buf[off] = ((v) >> 8) & 0xff, \
-				 buf[(off) + 1] = (v) & 0xff)
-#define PUT_32BE(off, v)	(PUT_16BE((off), (v) >> 16), \
-				 PUT_16BE((off) + 2, (v)))
-
-/* Structure of an ELF file */
-#define E_IDENT		0	/* ELF header */
-#define	E_PHOFF		28
-#define E_PHENTSIZE	42
-#define E_PHNUM		44
-#define E_HSIZE		52	/* size of ELF header */
-
-#define EI_MAGIC	0	/* offsets in E_IDENT area */
-#define EI_CLASS	4
-#define EI_DATA		5
-
-#define PH_TYPE		0	/* ELF program header */
-#define PH_OFFSET	4
-#define PH_FILESZ	16
-#define PH_HSIZE	32	/* size of program header */
-
-#define PT_NOTE		4	/* Program header type = note */
-
-#define ELFCLASS32	1
-#define ELFDATA2MSB	2
-
-unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' };
-
-int main(int ac, char **av)
-{
-	int fd, n, i;
-	int ph, ps, np;
-	int nnote, ns;
-
-	if (ac != 2) {
-		fprintf(stderr, "Usage: %s elf-file\n", av[0]);
-		exit(1);
-	}
-	fd = open(av[1], O_RDWR);
-	if (fd < 0) {
-		perror(av[1]);
-		exit(1);
-	}
-
-	nnote = strlen(arch) + 1 + (N_DESCR + 3) * 4;
-
-	n = read(fd, buf, sizeof(buf));
-	if (n < 0) {
-		perror("read");
-		exit(1);
-	}
-
-	if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0)
-		goto notelf;
-
-	if (buf[E_IDENT+EI_CLASS] != ELFCLASS32
-	    || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) {
-		fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n",
-			av[1]);
-		exit(1);
-	}
-
-	ph = GET_32BE(E_PHOFF);
-	ps = GET_16BE(E_PHENTSIZE);
-	np = GET_16BE(E_PHNUM);
-	if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
-		goto notelf;
-	if (ph + (np + 1) * ps + nnote > n)
-		goto nospace;
-
-	for (i = 0; i < np; ++i) {
-		if (GET_32BE(ph + PH_TYPE) == PT_NOTE) {
-			fprintf(stderr, "%s already has a note entry\n",
-				av[1]);
-			exit(0);
-		}
-		ph += ps;
-	}
-
-	/* XXX check that the area we want to use is all zeroes */
-	for (i = 0; i < ps + nnote; ++i)
-		if (buf[ph + i] != 0)
-			goto nospace;
-
-	/* fill in the program header entry */
-	ns = ph + ps;
-	PUT_32BE(ph + PH_TYPE, PT_NOTE);
-	PUT_32BE(ph + PH_OFFSET, ns);
-	PUT_32BE(ph + PH_FILESZ, nnote);
-
-	/* fill in the note area we point to */
-	/* XXX we should probably make this a proper section */
-	PUT_32BE(ns, strlen(arch) + 1);
-	PUT_32BE(ns + 4, N_DESCR * 4);
-	PUT_32BE(ns + 8, 0x1275);
-	strcpy(&buf[ns + 12], arch);
-	ns += 12 + strlen(arch) + 1;
-	for (i = 0; i < N_DESCR; ++i)
-		PUT_32BE(ns + i * 4, descr[i]);
-
-	/* Update the number of program headers */
-	PUT_16BE(E_PHNUM, np + 1);
-
-	/* write back */
-	lseek(fd, (long) 0, SEEK_SET);
-	i = write(fd, buf, n);
-	if (i < 0) {
-		perror("write");
-		exit(1);
-	}
-	if (i < n) {
-		fprintf(stderr, "%s: write truncated\n", av[1]);
-		exit(1);
-	}
-
-	exit(0);
-
- notelf:
-	fprintf(stderr, "%s does not appear to be an ELF file\n", av[0]);
-	exit(1);
-
- nospace:
-	fprintf(stderr, "sorry, I can't find space in %s to put the note\n",
-		av[0]);
-	exit(1);
-}
diff --git a/arch/ppc/boot/utils/hack-coff.c b/arch/ppc/boot/utils/hack-coff.c
deleted file mode 100644
index 5e5a657..0000000
--- a/arch/ppc/boot/utils/hack-coff.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * hack-coff.c - hack the header of an xcoff file to fill in
- * a few fields needed by the Open Firmware xcoff loader on
- * Power Macs but not initialized by objcopy.
- *
- * Copyright (C) Paul Mackerras 1997.
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include "rs6000.h"
-
-#define AOUT_MAGIC	0x010b
-
-#define get_16be(x)	((((unsigned char *)(x))[0] << 8) \
-			 + ((unsigned char *)(x))[1])
-#define put_16be(x, v)	(((unsigned char *)(x))[0] = (v) >> 8, \
-			 ((unsigned char *)(x))[1] = (v) & 0xff)
-#define get_32be(x)	((((unsigned char *)(x))[0] << 24) \
-			 + (((unsigned char *)(x))[1] << 16) \
-			 + (((unsigned char *)(x))[2] << 8) \
-			 + ((unsigned char *)(x))[3])
-
-int
-main(int ac, char **av)
-{
-    int fd;
-    int i, nsect;
-    int aoutsz;
-    struct external_filehdr fhdr;
-    AOUTHDR aout;
-    struct external_scnhdr shdr;
-
-    if (ac != 2) {
-	fprintf(stderr, "Usage: hack-coff coff-file\n");
-	exit(1);
-    }
-    if ((fd = open(av[1], 2)) == -1) {
-	perror(av[2]);
-	exit(1);
-    }
-    if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr))
-	goto readerr;
-    i = get_16be(fhdr.f_magic);
-    if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) {
-	fprintf(stderr, "%s: not an xcoff file\n", av[1]);
-	exit(1);
-    }
-    aoutsz = get_16be(fhdr.f_opthdr);
-    if (read(fd, &aout, aoutsz) != aoutsz)
-	goto readerr;
-    nsect = get_16be(fhdr.f_nscns);
-    for (i = 0; i < nsect; ++i) {
-	if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
-	    goto readerr;
-	if (strcmp(shdr.s_name, ".text") == 0) {
-	    put_16be(aout.o_snentry, i+1);
-	    put_16be(aout.o_sntext, i+1);
-	} else if (strcmp(shdr.s_name, ".data") == 0) {
-	    put_16be(aout.o_sndata, i+1);
-	} else if (strcmp(shdr.s_name, ".bss") == 0) {
-	    put_16be(aout.o_snbss, i+1);
-	}
-    }
-    put_16be(aout.magic, AOUT_MAGIC);
-    if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1
-	|| write(fd, &aout, aoutsz) != aoutsz) {
-	fprintf(stderr, "%s: write error\n", av[1]);
-	exit(1);
-    }
-    close(fd);
-    exit(0);
-
-readerr:
-    fprintf(stderr, "%s: read error or file too short\n", av[1]);
-    exit(1);
-}
diff --git a/arch/ppc/boot/utils/mknote.c b/arch/ppc/boot/utils/mknote.c
deleted file mode 100644
index b9fbb2c..0000000
--- a/arch/ppc/boot/utils/mknote.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) Cort Dougan 1999.
- *
- * 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.
- *
- * Generate a note section as per the CHRP specification.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff );
-
-int main(void)
-{
-/* header */
-	/* namesz */
-	PL(strlen("PowerPC")+1);
-	/* descrsz */
-	PL(6*4);
-	/* type */
-	PL(0x1275);
-	/* name */
-	printf("PowerPC"); printf("%c", 0);
-	
-/* descriptor */
-	/* real-mode */
-	PL(0xffffffff);
-	/* real-base */
-	PL(0x00c00000);
-	/* real-size */
-	PL(0xffffffff);
-	/* virt-base */
-	PL(0xffffffff);
-	/* virt-size */
-	PL(0xffffffff);
-	/* load-base */
-	PL(0x4000);
-	return 0;
-}
diff --git a/arch/ppc/configs/ibmchrp_defconfig b/arch/ppc/configs/ibmchrp_defconfig
deleted file mode 100644
index 27f3e69..0000000
--- a/arch/ppc/configs/ibmchrp_defconfig
+++ /dev/null
@@ -1,875 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_GENERIC_NVRAM=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-# CONFIG_STANDALONE is not set
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-# CONFIG_EMBEDDED is not set
-CONFIG_KALLSYMS=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Processor
-#
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-# CONFIG_ALTIVEC is not set
-# CONFIG_TAU is not set
-# CONFIG_CPU_FREQ is not set
-# CONFIG_PPC601_SYNC_FIX is not set
-CONFIG_PPC_STD_MMU=y
-
-#
-# Platform options
-#
-CONFIG_PPC_MULTIPLATFORM=y
-# CONFIG_APUS is not set
-# CONFIG_WILLOW is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-# CONFIG_GEMINI is not set
-# CONFIG_EST8260 is not set
-# CONFIG_SBS8260 is not set
-# CONFIG_RPX6 is not set
-# CONFIG_TQM8260 is not set
-CONFIG_PPC_CHRP=y
-CONFIG_PPC_PMAC=y
-CONFIG_PPC_PREP=y
-CONFIG_PPC_OF=y
-CONFIG_PPCBUG_NVRAM=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-CONFIG_HIGHMEM=y
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=y
-CONFIG_PROC_DEVICETREE=y
-CONFIG_PPC_RTAS=y
-# CONFIG_PREP_RESIDUAL is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Bus options
-#
-CONFIG_ISA=y
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00800000
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-CONFIG_BLK_DEV_FD=y
-# CONFIG_BLK_DEV_XD 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
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_LBD=y
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_REPORT_LUNS is not set
-CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-CONFIG_SCSI_SPI_ATTRS=y
-# CONFIG_SCSI_FC_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_MESH is not set
-# CONFIG_SCSI_MAC53C94 is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Macintosh device drivers
-#
-# CONFIG_ADB is not set
-# CONFIG_ADB_CUDA is not set
-# CONFIG_ADB_PMU is not set
-# CONFIG_MAC_FLOPPY is not set
-# CONFIG_MAC_SERIAL is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-CONFIG_IP_NF_TFTP=m
-CONFIG_IP_NF_AMANDA=m
-# CONFIG_IP_NF_QUEUE is not set
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-# CONFIG_IP_NF_MATCH_PKTTYPE is not set
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_RECENT=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_SAME=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_NAT_TFTP=m
-CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_MANGLE is not set
-# CONFIG_IP_NF_TARGET_LOG is not set
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-CONFIG_IP_NF_TARGET_NOTRACK=m
-CONFIG_IP_NF_RAW=m
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_MACE is not set
-# CONFIG_BMAC is not set
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_AT1700 is not set
-# CONFIG_DEPCA is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
-# CONFIG_B44 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_CS89x0 is not set
-# CONFIG_DGRS is not set
-# CONFIG_EEPRO100 is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_INPORT is not set
-# CONFIG_MOUSE_LOGIBM is not set
-# CONFIG_MOUSE_PC110PAD is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=y
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-# CONFIG_SERIAL_8250_CONSOLE is not set
-CONFIG_SERIAL_8250_NR_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-# CONFIG_SERIAL_PMACZILOG is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-CONFIG_NVRAM=y
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-CONFIG_FB=y
-# CONFIG_FB_PM2 is not set
-# CONFIG_FB_CYBER2000 is not set
-CONFIG_FB_OF=y
-# CONFIG_FB_CONTROL is not set
-# CONFIG_FB_PLATINUM is not set
-# CONFIG_FB_VALKYRIE is not set
-# CONFIG_FB_CT65550 is not set
-# CONFIG_FB_IMSTT is not set
-# CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_VGA16 is not set
-# CONFIG_FB_RIVA is not set
-CONFIG_FB_MATROX=y
-CONFIG_FB_MATROX_MILLENIUM=y
-CONFIG_FB_MATROX_MYSTIQUE=y
-# CONFIG_FB_MATROX_G450 is not set
-CONFIG_FB_MATROX_G100A=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_MULTIHEAD is not set
-# CONFIG_FB_RADEON_OLD is not set
-# CONFIG_FB_RADEON is not set
-# CONFIG_FB_ATY128 is not set
-# CONFIG_FB_ATY is not set
-# CONFIG_FB_SIS is not set
-# CONFIG_FB_NEOMAGIC is not set
-# CONFIG_FB_KYRO is not set
-CONFIG_FB_3DFX=y
-# CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-CONFIG_VGA_CONSOLE=y
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-
-#
-# Logo configuration
-#
-CONFIG_LOGO=y
-CONFIG_LOGO_LINUX_MONO=y
-CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_SYSFS=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-# CONFIG_NFS_FS is not set
-# CONFIG_NFSD is not set
-# CONFIG_EXPORTFS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-CONFIG_MAC_PARTITION=y
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1250 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-CONFIG_NLS_ISO8859_1=m
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_BOOTX_TEXT is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/pmac_defconfig b/arch/ppc/configs/pmac_defconfig
deleted file mode 100644
index a2db8b5..0000000
--- a/arch/ppc/configs/pmac_defconfig
+++ /dev/null
@@ -1,1591 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.13-rc3
-# Wed Jul 13 14:13:13 2005
-#
-CONFIG_MMU=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_GENERIC_NVRAM=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-# CONFIG_EMBEDDED is not set
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_ALL is not set
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_KMOD=y
-
-#
-# Processor
-#
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-# CONFIG_E200 is not set
-# CONFIG_E500 is not set
-CONFIG_PPC_FPU=y
-CONFIG_ALTIVEC=y
-CONFIG_TAU=y
-# CONFIG_TAU_INT is not set
-# CONFIG_TAU_AVERAGE is not set
-# CONFIG_KEXEC is not set
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_TABLE=y
-# CONFIG_CPU_FREQ_DEBUG is not set
-CONFIG_CPU_FREQ_STAT=m
-CONFIG_CPU_FREQ_STAT_DETAILS=y
-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=m
-CONFIG_CPU_FREQ_GOV_USERSPACE=m
-CONFIG_CPU_FREQ_GOV_ONDEMAND=m
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
-CONFIG_CPU_FREQ_PMAC=y
-CONFIG_PPC601_SYNC_FIX=y
-CONFIG_PM=y
-CONFIG_PPC_STD_MMU=y
-
-#
-# Platform options
-#
-CONFIG_PPC_MULTIPLATFORM=y
-# CONFIG_APUS is not set
-# CONFIG_KATANA is not set
-# CONFIG_WILLOW is not set
-# CONFIG_CPCI690 is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_CHESTNUT is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_HDPU is not set
-# CONFIG_EV64260 is not set
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_RADSTONE_PPC7D is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-# CONFIG_GEMINI is not set
-# CONFIG_EST8260 is not set
-# CONFIG_SBC82xx is not set
-# CONFIG_SBS8260 is not set
-# CONFIG_RPX8260 is not set
-# CONFIG_TQM8260 is not set
-# CONFIG_ADS8272 is not set
-# CONFIG_PQ2FADS is not set
-# CONFIG_LITE5200 is not set
-# CONFIG_MPC834x_SYS is not set
-CONFIG_PPC_CHRP=y
-CONFIG_PPC_PMAC=y
-CONFIG_PPC_PREP=y
-CONFIG_PPC_OF=y
-CONFIG_PPCBUG_NVRAM=y
-# CONFIG_SMP is not set
-# CONFIG_HIGHMEM is not set
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT is not set
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=m
-CONFIG_PROC_DEVICETREE=y
-# CONFIG_PREP_RESIDUAL is not set
-# CONFIG_CMDLINE_BOOL is not set
-# CONFIG_PM_DEBUG is not set
-CONFIG_SOFTWARE_SUSPEND=y
-CONFIG_PM_STD_PARTITION=""
-# CONFIG_SECCOMP is not set
-CONFIG_ISA_DMA_API=y
-
-#
-# Bus options
-#
-# CONFIG_ISA is not set
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
-# CONFIG_PCI_DEBUG is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-CONFIG_PCCARD=m
-# CONFIG_PCMCIA_DEBUG is not set
-CONFIG_PCMCIA=m
-# CONFIG_PCMCIA_LOAD_CIS is not set
-# CONFIG_PCMCIA_IOCTL is not set
-CONFIG_CARDBUS=y
-
-#
-# PC-card bridges
-#
-CONFIG_YENTA=m
-# CONFIG_PD6729 is not set
-# CONFIG_I82092 is not set
-# CONFIG_TCIC is not set
-CONFIG_PCCARD_NONSTATIC=m
-
-#
-# Advanced setup
-#
-CONFIG_ADVANCED_OPTIONS=y
-CONFIG_HIGHMEM_START=0xfe000000
-# CONFIG_LOWMEM_SIZE_BOOL is not set
-CONFIG_LOWMEM_SIZE=0x30000000
-# CONFIG_KERNEL_START_BOOL is not set
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE_BOOL=y
-CONFIG_TASK_SIZE=0xc0000000
-CONFIG_BOOT_LOAD=0x00800000
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_CT_ACCT=y
-CONFIG_IP_NF_CONNTRACK_MARK=y
-CONFIG_IP_NF_CT_PROTO_SCTP=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-CONFIG_IP_NF_TFTP=m
-CONFIG_IP_NF_AMANDA=m
-CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_RECENT=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_REALM=m
-CONFIG_IP_NF_MATCH_SCTP=m
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
-CONFIG_IP_NF_MATCH_HASHLIMIT=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_SAME=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_NAT_TFTP=m
-CONFIG_IP_NF_NAT_AMANDA=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_TOS=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
-CONFIG_IP_NF_TARGET_CONNMARK=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_SCHED is not set
-CONFIG_NET_CLS_ROUTE=y
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
-# CONFIG_NETPOLL_TRAP is not set
-CONFIG_NET_POLL_CONTROLLER=y
-# CONFIG_HAMRADIO is not set
-CONFIG_IRDA=m
-
-#
-# IrDA protocols
-#
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
-# CONFIG_IRDA_ULTRA is not set
-
-#
-# IrDA options
-#
-CONFIG_IRDA_CACHE_LAST_LSAP=y
-CONFIG_IRDA_FAST_RR=y
-# CONFIG_IRDA_DEBUG is not set
-
-#
-# Infrared-port device drivers
-#
-
-#
-# SIR device drivers
-#
-CONFIG_IRTTY_SIR=m
-
-#
-# Dongle support
-#
-# CONFIG_DONGLE is not set
-
-#
-# Old SIR device drivers
-#
-# CONFIG_IRPORT_SIR is not set
-
-#
-# Old Serial dongle support
-#
-
-#
-# FIR device drivers
-#
-# CONFIG_USB_IRDA is not set
-# CONFIG_SIGMATEL_FIR is not set
-# CONFIG_NSC_FIR is not set
-# CONFIG_WINBOND_FIR is not set
-# CONFIG_TOSHIBA_FIR is not set
-# CONFIG_SMC_IRCC_FIR is not set
-# CONFIG_ALI_FIR is not set
-# CONFIG_VLSI_FIR is not set
-# CONFIG_VIA_FIR is not set
-# CONFIG_BT is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-# CONFIG_STANDALONE is not set
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=m
-# CONFIG_DEBUG_DRIVER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-CONFIG_MAC_FLOPPY=m
-# 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
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_UB is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_LBD=y
-CONFIG_CDROM_PKTCDVD=m
-CONFIG_CDROM_PKTCDVD_BUFFERS=8
-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECS is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=y
-CONFIG_BLK_DEV_IDESCSI=y
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_IDE_GENERIC is not set
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_IDEPCI_SHARE_IRQ=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-CONFIG_BLK_DEV_GENERIC=y
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_SL82C105 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
-# CONFIG_BLK_DEV_AMD74XX is not set
-CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_BLK_DEV_IT821X is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-CONFIG_BLK_DEV_PDC202XX_NEW=y
-# CONFIG_PDC202XX_FORCE is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-CONFIG_BLK_DEV_IDE_PMAC=y
-CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y
-CONFIG_BLK_DEV_IDEDMA_PMAC=y
-CONFIG_BLK_DEV_IDE_PMAC_BLINK=y
-# 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
-
-#
-# SCSI device support
-#
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
-# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-CONFIG_SCSI_SPI_ATTRS=y
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-CONFIG_SCSI_AIC7XXX=m
-CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
-CONFIG_AIC7XXX_RESET_DELAY_MS=15000
-CONFIG_AIC7XXX_DEBUG_ENABLE=y
-CONFIG_AIC7XXX_DEBUG_MASK=0
-CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
-CONFIG_SCSI_AIC7XXX_OLD=m
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_LPFC is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-CONFIG_SCSI_MESH=y
-CONFIG_SCSI_MESH_SYNC_RATE=5
-CONFIG_SCSI_MESH_RESET_DELAY_MS=1000
-CONFIG_SCSI_MAC53C94=y
-
-#
-# PCMCIA SCSI adapter support
-#
-# CONFIG_PCMCIA_AHA152X is not set
-# CONFIG_PCMCIA_FDOMAIN is not set
-# CONFIG_PCMCIA_NINJA_SCSI is not set
-# CONFIG_PCMCIA_QLOGIC is not set
-# CONFIG_PCMCIA_SYM53C500 is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-# CONFIG_FUSION_SPI is not set
-# CONFIG_FUSION_FC is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-CONFIG_IEEE1394=m
-
-#
-# Subsystem Options
-#
-# CONFIG_IEEE1394_VERBOSEDEBUG is not set
-# CONFIG_IEEE1394_OUI_DB is not set
-CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
-CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
-# CONFIG_IEEE1394_EXPORT_FULL_API is not set
-
-#
-# Device Drivers
-#
-# CONFIG_IEEE1394_PCILYNX is not set
-CONFIG_IEEE1394_OHCI1394=m
-
-#
-# Protocol Drivers
-#
-CONFIG_IEEE1394_VIDEO1394=m
-CONFIG_IEEE1394_SBP2=m
-# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
-CONFIG_IEEE1394_ETH1394=m
-CONFIG_IEEE1394_DV1394=m
-CONFIG_IEEE1394_RAWIO=m
-CONFIG_IEEE1394_CMP=m
-CONFIG_IEEE1394_AMDTP=m
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Macintosh device drivers
-#
-CONFIG_ADB=y
-CONFIG_ADB_CUDA=y
-CONFIG_ADB_PMU=y
-CONFIG_PMAC_APM_EMU=y
-CONFIG_PMAC_MEDIABAY=y
-CONFIG_PMAC_BACKLIGHT=y
-CONFIG_ADB_MACIO=y
-CONFIG_INPUT_ADBHID=y
-CONFIG_MAC_EMUMOUSEBTN=y
-CONFIG_THERM_WINDTUNNEL=m
-CONFIG_THERM_ADT746X=m
-# CONFIG_ANSLCD is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-CONFIG_TUN=m
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-CONFIG_MACE=y
-# CONFIG_MACE_AAUI_PORT is not set
-CONFIG_BMAC=y
-# CONFIG_HAPPYMEAL is not set
-CONFIG_SUNGEM=y
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
-# CONFIG_EEPRO100 is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SKGE is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_VIA_VELOCITY is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_BNX2 is not set
-# CONFIG_MV643XX_ETH is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-# CONFIG_STRIP is not set
-# CONFIG_PCMCIA_WAVELAN is not set
-# CONFIG_PCMCIA_NETWAVE is not set
-
-#
-# Wireless 802.11 Frequency Hopping cards support
-#
-# CONFIG_PCMCIA_RAYCS is not set
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-CONFIG_HERMES=m
-CONFIG_APPLE_AIRPORT=m
-# CONFIG_PLX_HERMES is not set
-# CONFIG_TMD_HERMES is not set
-# CONFIG_PCI_HERMES is not set
-# CONFIG_ATMEL is not set
-
-#
-# Wireless 802.11b Pcmcia/Cardbus cards support
-#
-CONFIG_PCMCIA_HERMES=m
-# CONFIG_AIRO_CS is not set
-# CONFIG_PCMCIA_WL3501 is not set
-
-#
-# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
-#
-# CONFIG_PRISM54 is not set
-CONFIG_NET_WIRELESS=y
-
-#
-# PCMCIA network device support
-#
-# CONFIG_NET_PCMCIA is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-CONFIG_PPP=y
-CONFIG_PPP_MULTILINK=y
-# CONFIG_PPP_FILTER is not set
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPPOE=m
-# CONFIG_SLIP is not set
-# CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
-CONFIG_NETCONSOLE=m
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-# CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-# CONFIG_MOUSE_PS2 is not set
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=m
-CONFIG_SERIAL_8250_CS=m
-CONFIG_SERIAL_8250_NR_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_PMACZILOG=y
-CONFIG_SERIAL_PMACZILOG_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
-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_NVRAM=y
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-CONFIG_AGP=m
-CONFIG_AGP_UNINORTH=m
-CONFIG_DRM=m
-# CONFIG_DRM_TDFX is not set
-CONFIG_DRM_R128=m
-CONFIG_DRM_RADEON=m
-# CONFIG_DRM_MGA is not set
-# CONFIG_DRM_SIS is not set
-# CONFIG_DRM_VIA is not set
-
-#
-# PCMCIA character devices
-#
-# CONFIG_SYNCLINK_CS is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=m
-
-#
-# I2C Algorithms
-#
-CONFIG_I2C_ALGOBIT=y
-# 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_HYDRA is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_I810 is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_ISA is not set
-CONFIG_I2C_KEYWEST=m
-# CONFIG_I2C_MPC is not set
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PROSAVAGE is not set
-# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB 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_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-# CONFIG_I2C_VOODOO3 is not set
-# CONFIG_I2C_PCA_ISA is not set
-# CONFIG_I2C_SENSOR 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_RTC8564 is not set
-# CONFIG_SENSORS_M41T00 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
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
-# CONFIG_HWMON is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-CONFIG_FB=y
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_FB_CFB_COPYAREA=y
-CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_SOFT_CURSOR=y
-CONFIG_FB_MACMODES=y
-CONFIG_FB_MODE_HELPERS=y
-CONFIG_FB_TILEBLITTING=y
-# CONFIG_FB_CIRRUS is not set
-# CONFIG_FB_PM2 is not set
-# CONFIG_FB_CYBER2000 is not set
-CONFIG_FB_OF=y
-CONFIG_FB_CONTROL=y
-CONFIG_FB_PLATINUM=y
-CONFIG_FB_VALKYRIE=y
-CONFIG_FB_CT65550=y
-# CONFIG_FB_ASILIANT is not set
-CONFIG_FB_IMSTT=y
-# CONFIG_FB_VGA16 is not set
-# CONFIG_FB_NVIDIA is not set
-# CONFIG_FB_RIVA is not set
-CONFIG_FB_MATROX=y
-CONFIG_FB_MATROX_MILLENIUM=y
-CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G=y
-# CONFIG_FB_MATROX_I2C is not set
-# CONFIG_FB_MATROX_MULTIHEAD is not set
-# CONFIG_FB_RADEON_OLD is not set
-CONFIG_FB_RADEON=y
-CONFIG_FB_RADEON_I2C=y
-# CONFIG_FB_RADEON_DEBUG is not set
-CONFIG_FB_ATY128=y
-CONFIG_FB_ATY=y
-CONFIG_FB_ATY_CT=y
-CONFIG_FB_ATY_GENERIC_LCD=y
-# CONFIG_FB_ATY_XL_INIT is not set
-CONFIG_FB_ATY_GX=y
-# CONFIG_FB_SAVAGE is not set
-# CONFIG_FB_SIS is not set
-# CONFIG_FB_NEOMAGIC is not set
-# CONFIG_FB_KYRO is not set
-CONFIG_FB_3DFX=y
-CONFIG_FB_3DFX_ACCEL=y
-# CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_S1D13XXX is not set
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-
-#
-# Logo configuration
-#
-CONFIG_LOGO=y
-CONFIG_LOGO_LINUX_MONO=y
-CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_DEVICE=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_LCD_DEVICE=y
-
-#
-# Sound
-#
-CONFIG_SOUND=m
-CONFIG_DMASOUND_PMAC=m
-CONFIG_DMASOUND=m
-
-#
-# Advanced Linux Sound Architecture
-#
-CONFIG_SND=m
-CONFIG_SND_TIMER=m
-CONFIG_SND_PCM=m
-CONFIG_SND_HWDEP=m
-CONFIG_SND_RAWMIDI=m
-CONFIG_SND_SEQUENCER=m
-CONFIG_SND_SEQ_DUMMY=m
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-CONFIG_SND_SEQUENCER_OSS=y
-# CONFIG_SND_VERBOSE_PRINTK is not set
-# CONFIG_SND_DEBUG is not set
-
-#
-# Generic devices
-#
-CONFIG_SND_DUMMY=m
-# CONFIG_SND_VIRMIDI is not set
-# CONFIG_SND_MTPAV is not set
-# CONFIG_SND_SERIAL_U16550 is not set
-# CONFIG_SND_MPU401 is not set
-
-#
-# PCI devices
-#
-# CONFIG_SND_ALI5451 is not set
-# CONFIG_SND_ATIIXP is not set
-# CONFIG_SND_ATIIXP_MODEM is not set
-# CONFIG_SND_AU8810 is not set
-# CONFIG_SND_AU8820 is not set
-# CONFIG_SND_AU8830 is not set
-# CONFIG_SND_AZT3328 is not set
-# CONFIG_SND_BT87X is not set
-# CONFIG_SND_CS46XX is not set
-# CONFIG_SND_CS4281 is not set
-# CONFIG_SND_EMU10K1 is not set
-# CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_YMFPCI is not set
-# CONFIG_SND_ALS4000 is not set
-# CONFIG_SND_CMIPCI is not set
-# CONFIG_SND_ENS1370 is not set
-# CONFIG_SND_ENS1371 is not set
-# CONFIG_SND_ES1938 is not set
-# CONFIG_SND_ES1968 is not set
-# CONFIG_SND_MAESTRO3 is not set
-# CONFIG_SND_FM801 is not set
-# CONFIG_SND_ICE1712 is not set
-# CONFIG_SND_ICE1724 is not set
-# CONFIG_SND_INTEL8X0 is not set
-# CONFIG_SND_INTEL8X0M is not set
-# CONFIG_SND_SONICVIBES is not set
-# CONFIG_SND_VIA82XX is not set
-# CONFIG_SND_VIA82XX_MODEM is not set
-# CONFIG_SND_VX222 is not set
-# CONFIG_SND_HDA_INTEL is not set
-
-#
-# ALSA PowerMac devices
-#
-CONFIG_SND_POWERMAC=m
-
-#
-# USB devices
-#
-CONFIG_SND_USB_AUDIO=m
-CONFIG_SND_USB_USX2Y=m
-
-#
-# PCMCIA devices
-#
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
-CONFIG_USB_DYNAMIC_MINORS=y
-CONFIG_USB_SUSPEND=y
-# CONFIG_USB_OTG is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_EHCI_HCD is not set
-# CONFIG_USB_ISP116X_HCD is not set
-CONFIG_USB_OHCI_HCD=y
-# CONFIG_USB_OHCI_BIG_ENDIAN is not set
-CONFIG_USB_OHCI_LITTLE_ENDIAN=y
-# CONFIG_USB_UHCI_HCD is not set
-# CONFIG_USB_SL811_HCD is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH_TTY is not set
-# CONFIG_USB_MIDI is not set
-CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-# CONFIG_USB_STORAGE is not set
-
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=y
-CONFIG_USB_HIDINPUT=y
-# CONFIG_HID_FF is not set
-CONFIG_USB_HIDDEV=y
-# 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_MTOUCH is not set
-# CONFIG_USB_ITMTOUCH is not set
-# CONFIG_USB_EGALAX is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_MICROTEK is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-CONFIG_USB_PEGASUS=m
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET is not set
-# CONFIG_USB_ZD1201 is not set
-# CONFIG_USB_MON is not set
-
-#
-# USB port drivers
-#
-
-#
-# USB Serial Converter support
-#
-CONFIG_USB_SERIAL=m
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_AIRPRIME is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_CP2101 is not set
-# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-CONFIG_USB_SERIAL_VISOR=m
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
-# CONFIG_USB_SERIAL_GARMIN is not set
-# CONFIG_USB_SERIAL_IPW is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-CONFIG_USB_SERIAL_KEYSPAN=m
-CONFIG_USB_SERIAL_KEYSPAN_MPR=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19=y
-CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_KOBIL_SCT is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_HP4X is not set
-# CONFIG_USB_SERIAL_SAFE is not set
-# CONFIG_USB_SERIAL_TI is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OPTION is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-CONFIG_USB_EZUSB=y
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_EMI62 is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_AUERSWALD is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LEGOTOWER is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_LED is not set
-# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
-# CONFIG_USB_IDMOUSE is not set
-# CONFIG_USB_LD is not set
-# CONFIG_USB_TEST is not set
-
-#
-# USB DSL modem support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# InfiniBand support
-#
-# CONFIG_INFINIBAND is not set
-
-#
-# SN Devices
-#
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-# CONFIG_EXT2_FS_POSIX_ACL is not set
-# CONFIG_EXT2_FS_SECURITY is not set
-# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-CONFIG_FS_POSIX_ACL=y
-
-#
-# XFS support
-#
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_INOTIFY=y
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=m
-CONFIG_UDF_NLS=y
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_SYSFS=y
-CONFIG_DEVPTS_FS_XATTR=y
-CONFIG_DEVPTS_FS_SECURITY=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_XATTR=y
-CONFIG_TMPFS_SECURITY=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=m
-CONFIG_HFSPLUS_FS=m
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-CONFIG_CRAMFS=m
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V2_ACL=y
-CONFIG_NFSD_V3=y
-CONFIG_NFSD_V3_ACL=y
-# CONFIG_NFSD_V4 is not set
-CONFIG_NFSD_TCP=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=y
-CONFIG_NFS_ACL_SUPPORT=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-CONFIG_SMB_FS=m
-# CONFIG_SMB_NLS_DEFAULT is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-CONFIG_MAC_PARTITION=y
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-CONFIG_NLS_CODEPAGE_1250=m
-CONFIG_NLS_CODEPAGE_1251=m
-CONFIG_NLS_ASCII=m
-CONFIG_NLS_ISO8859_1=m
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-CONFIG_NLS_ISO8859_15=m
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-CONFIG_NLS_UTF8=m
-
-#
-# Library routines
-#
-CONFIG_CRC_CCITT=y
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_LOG_BUF_SHIFT=16
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_XMON is not set
-# CONFIG_BDI_SWITCH is not set
-CONFIG_BOOTX_TEXT=y
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
diff --git a/arch/ppc/configs/power3_defconfig b/arch/ppc/configs/power3_defconfig
deleted file mode 100644
index a1ef929..0000000
--- a/arch/ppc/configs/power3_defconfig
+++ /dev/null
@@ -1,1035 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_GENERIC_NVRAM=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-# CONFIG_STANDALONE is not set
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=15
-# CONFIG_HOTPLUG is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-# CONFIG_EMBEDDED is not set
-CONFIG_KALLSYMS=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-CONFIG_STOP_MACHINE=y
-
-#
-# Processor
-#
-# CONFIG_6xx is not set
-# CONFIG_40x is not set
-# CONFIG_44x is not set
-CONFIG_POWER3=y
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_PPC64BRIDGE=y
-CONFIG_PPC_STD_MMU=y
-
-#
-# Platform options
-#
-CONFIG_PPC_MULTIPLATFORM=y
-# CONFIG_APUS is not set
-# CONFIG_WILLOW is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-# CONFIG_GEMINI is not set
-# CONFIG_EST8260 is not set
-# CONFIG_SBS8260 is not set
-# CONFIG_RPX6 is not set
-# CONFIG_TQM8260 is not set
-CONFIG_PPC_CHRP=y
-CONFIG_PPC_PMAC=y
-CONFIG_PPC_PREP=y
-CONFIG_PPC_OF=y
-CONFIG_PPCBUG_NVRAM=y
-CONFIG_SMP=y
-# CONFIG_IRQ_ALL_CPUS is not set
-CONFIG_NR_CPUS=32
-# CONFIG_PREEMPT is not set
-CONFIG_HIGHMEM=y
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=y
-CONFIG_PROC_DEVICETREE=y
-CONFIG_PPC_RTAS=y
-# CONFIG_PREP_RESIDUAL is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Bus options
-#
-CONFIG_ISA=y
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
-
-#
-# Advanced setup
-#
-CONFIG_ADVANCED_OPTIONS=y
-# CONFIG_HIGHMEM_START_BOOL is not set
-CONFIG_HIGHMEM_START=0xfe000000
-# CONFIG_LOWMEM_SIZE_BOOL is not set
-CONFIG_LOWMEM_SIZE=0x30000000
-# CONFIG_KERNEL_START_BOOL is not set
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE_BOOL=y
-CONFIG_TASK_SIZE=0xc0000000
-CONFIG_BOOT_LOAD=0x00800000
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-CONFIG_PARPORT=m
-CONFIG_PARPORT_PC=m
-CONFIG_PARPORT_PC_CML1=m
-# CONFIG_PARPORT_SERIAL is not set
-CONFIG_PARPORT_PC_FIFO=y
-# CONFIG_PARPORT_PC_SUPERIO is not set
-# CONFIG_PARPORT_OTHER is not set
-# CONFIG_PARPORT_1284 is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-CONFIG_BLK_DEV_FD=y
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE 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
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_LBD=y
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_REPORT_LUNS is not set
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-
-#
-# SCSI Transport Attributes
-#
-CONFIG_SCSI_SPI_ATTRS=y
-# CONFIG_SCSI_FC_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_PPA is not set
-# CONFIG_SCSI_IMM is not set
-# CONFIG_SCSI_NCR53C406A is not set
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_MESH is not set
-# CONFIG_SCSI_MAC53C94 is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=y
-CONFIG_MD_RAID0=y
-CONFIG_MD_RAID1=y
-CONFIG_MD_RAID5=y
-CONFIG_MD_RAID6=y
-# CONFIG_MD_MULTIPATH is not set
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=y
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Macintosh device drivers
-#
-# CONFIG_ADB is not set
-# CONFIG_ADB_CUDA is not set
-# CONFIG_ADB_PMU is not set
-# CONFIG_MAC_FLOPPY is not set
-# CONFIG_MAC_SERIAL is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_MACE is not set
-# CONFIG_BMAC is not set
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_AT1700 is not set
-# CONFIG_DEPCA is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
-# CONFIG_B44 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_CS89x0 is not set
-# CONFIG_DGRS is not set
-# CONFIG_EEPRO100 is not set
-CONFIG_E100=y
-# CONFIG_E100_NAPI is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-CONFIG_E1000=y
-# CONFIG_E1000_NAPI is not set
-# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
-CONFIG_GAMEPORT=m
-CONFIG_SOUND_GAMEPORT=m
-# CONFIG_GAMEPORT_NS558 is not set
-# CONFIG_GAMEPORT_L4 is not set
-# CONFIG_GAMEPORT_EMU10K1 is not set
-# CONFIG_GAMEPORT_VORTEX is not set
-# CONFIG_GAMEPORT_FM801 is not set
-# CONFIG_GAMEPORT_CS461x is not set
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-# CONFIG_SERIO_PCIPS2 is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_INPORT is not set
-# CONFIG_MOUSE_LOGIBM is not set
-# CONFIG_MOUSE_PC110PAD is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=y
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_PMACZILOG is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-CONFIG_PRINTER=m
-# CONFIG_LP_CONSOLE is not set
-# CONFIG_PPDEV is not set
-# CONFIG_TIPAR is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-CONFIG_NVRAM=y
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-
-#
-# I2C Algorithms
-#
-CONFIG_I2C_ALGOBIT=y
-CONFIG_I2C_ALGOPCF=y
-
-#
-# 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_HYDRA is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_I810 is not set
-# CONFIG_I2C_ISA is not set
-# CONFIG_I2C_KEYWEST is not set
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_PARPORT is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_PROSAVAGE is not set
-# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-# CONFIG_I2C_VOODOO3 is not set
-
-#
-# Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 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_LM90 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-
-#
-# Other I2C Chip support
-#
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCF8591 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
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-CONFIG_FB=y
-# CONFIG_FB_PM2 is not set
-# CONFIG_FB_CYBER2000 is not set
-CONFIG_FB_OF=y
-# CONFIG_FB_CONTROL is not set
-# CONFIG_FB_PLATINUM is not set
-# CONFIG_FB_VALKYRIE is not set
-# CONFIG_FB_CT65550 is not set
-# CONFIG_FB_IMSTT is not set
-# CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_VGA16 is not set
-# CONFIG_FB_RIVA is not set
-CONFIG_FB_MATROX=y
-CONFIG_FB_MATROX_MILLENIUM=y
-CONFIG_FB_MATROX_MYSTIQUE=y
-# CONFIG_FB_MATROX_G450 is not set
-CONFIG_FB_MATROX_G100A=y
-CONFIG_FB_MATROX_G100=y
-CONFIG_FB_MATROX_I2C=y
-# CONFIG_FB_MATROX_MAVEN is not set
-CONFIG_FB_MATROX_MULTIHEAD=y
-# CONFIG_FB_RADEON_OLD is not set
-# CONFIG_FB_RADEON is not set
-# CONFIG_FB_ATY128 is not set
-# CONFIG_FB_ATY is not set
-# CONFIG_FB_SIS is not set
-# CONFIG_FB_NEOMAGIC is not set
-# CONFIG_FB_KYRO is not set
-# CONFIG_FB_3DFX is not set
-# CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-
-#
-# Logo configuration
-#
-CONFIG_LOGO=y
-CONFIG_LOGO_LINUX_MONO=y
-CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-# CONFIG_DMASOUND_PMAC is not set
-
-#
-# Advanced Linux Sound Architecture
-#
-CONFIG_SND=m
-CONFIG_SND_TIMER=m
-CONFIG_SND_PCM=m
-CONFIG_SND_HWDEP=m
-CONFIG_SND_RAWMIDI=m
-CONFIG_SND_SEQUENCER=m
-CONFIG_SND_SEQ_DUMMY=m
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-CONFIG_SND_SEQUENCER_OSS=y
-# CONFIG_SND_VERBOSE_PRINTK is not set
-# CONFIG_SND_DEBUG is not set
-
-#
-# Generic devices
-#
-CONFIG_SND_MPU401_UART=m
-CONFIG_SND_OPL3_LIB=m
-CONFIG_SND_DUMMY=m
-# CONFIG_SND_VIRMIDI is not set
-# CONFIG_SND_MTPAV is not set
-# CONFIG_SND_SERIAL_U16550 is not set
-# CONFIG_SND_MPU401 is not set
-
-#
-# ISA devices
-#
-# CONFIG_SND_AD1848 is not set
-# CONFIG_SND_CS4231 is not set
-CONFIG_SND_CS4232=m
-# CONFIG_SND_CS4236 is not set
-# CONFIG_SND_ES1688 is not set
-# CONFIG_SND_ES18XX is not set
-# CONFIG_SND_GUSCLASSIC is not set
-# CONFIG_SND_GUSEXTREME is not set
-# CONFIG_SND_GUSMAX is not set
-# CONFIG_SND_INTERWAVE is not set
-# CONFIG_SND_INTERWAVE_STB is not set
-# CONFIG_SND_OPTI92X_AD1848 is not set
-# CONFIG_SND_OPTI92X_CS4231 is not set
-# CONFIG_SND_OPTI93X is not set
-# CONFIG_SND_SB8 is not set
-# CONFIG_SND_SB16 is not set
-# CONFIG_SND_SBAWE is not set
-# CONFIG_SND_WAVEFRONT is not set
-# CONFIG_SND_CMI8330 is not set
-# CONFIG_SND_OPL3SA2 is not set
-# CONFIG_SND_SGALAXY is not set
-# CONFIG_SND_SSCAPE is not set
-
-#
-# PCI devices
-#
-CONFIG_SND_AC97_CODEC=m
-# CONFIG_SND_ALI5451 is not set
-# CONFIG_SND_ATIIXP is not set
-# CONFIG_SND_AU8810 is not set
-# CONFIG_SND_AU8820 is not set
-# CONFIG_SND_AU8830 is not set
-# CONFIG_SND_AZT3328 is not set
-# CONFIG_SND_BT87X is not set
-CONFIG_SND_CS46XX=m
-# CONFIG_SND_CS46XX_NEW_DSP is not set
-CONFIG_SND_CS4281=m
-# CONFIG_SND_EMU10K1 is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_YMFPCI is not set
-# CONFIG_SND_ALS4000 is not set
-# CONFIG_SND_CMIPCI is not set
-# CONFIG_SND_ENS1370 is not set
-# CONFIG_SND_ENS1371 is not set
-# CONFIG_SND_ES1938 is not set
-# CONFIG_SND_ES1968 is not set
-# CONFIG_SND_MAESTRO3 is not set
-# CONFIG_SND_FM801 is not set
-# CONFIG_SND_ICE1712 is not set
-# CONFIG_SND_ICE1724 is not set
-# CONFIG_SND_INTEL8X0 is not set
-# CONFIG_SND_INTEL8X0M is not set
-# CONFIG_SND_SONICVIBES is not set
-# CONFIG_SND_VIA82XX is not set
-# CONFIG_SND_VX222 is not set
-
-#
-# ALSA PowerMac devices
-#
-# CONFIG_SND_POWERMAC is not set
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=y
-# CONFIG_NFSD_V3 is not set
-# CONFIG_NFSD_TCP is not set
-CONFIG_LOCKD=y
-CONFIG_EXPORTFS=y
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=y
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1250 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-CONFIG_NLS_ISO8859_1=y
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=m
-CONFIG_ZLIB_DEFLATE=m
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_BOOTX_TEXT=y
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_NULL=y
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=m
-CONFIG_CRYPTO_SHA1=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_DES=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_TWOFISH=m
-# CONFIG_CRYPTO_SERPENT is not set
-CONFIG_CRYPTO_AES=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_DEFLATE=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_TEST is not set
diff --git a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/prep_defconfig
similarity index 100%
rename from arch/ppc/configs/common_defconfig
rename to arch/ppc/configs/prep_defconfig
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index e399bbb..466437f 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -1,48 +1,24 @@
 #
 # Makefile for the linux kernel.
 #
-ifneq ($(CONFIG_PPC_MERGE),y)
-
 extra-$(CONFIG_PPC_STD_MMU)	:= head.o
 extra-$(CONFIG_40x)		:= head_4xx.o
 extra-$(CONFIG_44x)		:= head_44x.o
 extra-$(CONFIG_FSL_BOOKE)	:= head_fsl_booke.o
 extra-$(CONFIG_8xx)		:= head_8xx.o
-extra-$(CONFIG_6xx)		+= idle_6xx.o
 extra-y				+= vmlinux.lds
 
-obj-y				:= entry.o traps.o idle.o time.o misc.o \
+obj-y				:= entry.o traps.o time.o misc.o \
 					setup.o \
 					ppc_htab.o
-obj-$(CONFIG_6xx)		+= l2cr.o cpu_setup_6xx.o
-obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o
-obj-$(CONFIG_MODULES)		+= module.o ppc_ksyms.o
+obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)	+= dma-mapping.o
 obj-$(CONFIG_PCI)		+= pci.o
 obj-$(CONFIG_RAPIDIO)		+= rio.o
 obj-$(CONFIG_KGDB)		+= ppc-stub.o
 obj-$(CONFIG_SMP)		+= smp.o smp-tbsync.o
-obj-$(CONFIG_TAU)		+= temp.o
-ifndef CONFIG_E200
-obj-$(CONFIG_FSL_BOOKE)		+= perfmon_fsl_booke.o
-endif
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
 
 ifndef CONFIG_MATH_EMULATION
 obj-$(CONFIG_8xx)		+= softemu8xx.o
 endif
-
-# These are here while we do the architecture merge
-
-else
-obj-y				:= idle.o
-obj-$(CONFIG_6xx)		+= l2cr.o cpu_setup_6xx.o
-obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o
-obj-$(CONFIG_MODULES)		+= module.o
-obj-$(CONFIG_NOT_COHERENT_CACHE)	+= dma-mapping.o
-obj-$(CONFIG_KGDB)		+= ppc-stub.o
-obj-$(CONFIG_TAU)		+= temp.o
-ifndef CONFIG_E200
-obj-$(CONFIG_FSL_BOOKE)		+= perfmon_fsl_booke.o
-endif
-endif
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index 3a28159..5891ecb 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -135,10 +135,10 @@
 	mfspr	r11,SPRN_HID0
 	mtcr	r11
 BEGIN_FTR_SECTION
-	bt-	8,power_save_6xx_restore	/* Check DOZE */
+	bt-	8,4f			/* Check DOZE */
 END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
 BEGIN_FTR_SECTION
-	bt-	9,power_save_6xx_restore	/* Check NAP */
+	bt-	9,4f			/* Check NAP */
 END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
 #endif /* CONFIG_6xx */
 	.globl transfer_to_handler_cont
@@ -157,6 +157,10 @@
 	SYNC
 	RFI				/* jump to handler, enable MMU */
 
+#ifdef CONFIG_6xx
+4:	b	power_save_6xx_restore
+#endif
+
 /*
  * On kernel stack overflow, load up an initial stack pointer
  * and call StackOverflow(regs), which should not return.
@@ -926,55 +930,3 @@
 	b	4b
 
 	.comm	ee_restarts,4
-
-/*
- * PROM code for specific machines follows.  Put it
- * here so it's easy to add arch-specific sections later.
- * -- Cort
- */
-#ifdef CONFIG_PPC_OF
-/*
- * On CHRP, the Run-Time Abstraction Services (RTAS) have to be
- * called with the MMU off.
- */
-_GLOBAL(enter_rtas)
-	stwu	r1,-INT_FRAME_SIZE(r1)
-	mflr	r0
-	stw	r0,INT_FRAME_SIZE+4(r1)
-	lis	r4,rtas_data@ha
-	lwz	r4,rtas_data@l(r4)
-	lis	r6,1f@ha	/* physical return address for rtas */
-	addi	r6,r6,1f@l
-	tophys(r6,r6)
-	tophys(r7,r1)
-	lis	r8,rtas_entry@ha
-	lwz	r8,rtas_entry@l(r8)
-	mfmsr	r9
-	stw	r9,8(r1)
-	LOAD_MSR_KERNEL(r0,MSR_KERNEL)
-	SYNC			/* disable interrupts so SRR0/1 */
-	MTMSRD(r0)		/* don't get trashed */
-	li	r9,MSR_KERNEL & ~(MSR_IR|MSR_DR)
-	mtlr	r6
-	CLR_TOP32(r7)
-	mtspr	SPRN_SPRG2,r7
-	mtspr	SPRN_SRR0,r8
-	mtspr	SPRN_SRR1,r9
-	RFI
-1:	tophys(r9,r1)
-	lwz	r8,INT_FRAME_SIZE+4(r9)	/* get return address */
-	lwz	r9,8(r9)	/* original msr value */
-	FIX_SRR1(r9,r0)
-	addi	r1,r1,INT_FRAME_SIZE
-	li	r0,0
-	mtspr	SPRN_SPRG2,r0
-	mtspr	SPRN_SRR0,r8
-	mtspr	SPRN_SRR1,r9
-	RFI			/* return to caller */
-
-	.globl	machine_check_in_rtas
-machine_check_in_rtas:
-	twi	31,0,0
-	/* XXX load up BATs and panic */
-
-#endif /* CONFIG_PPC_OF */
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 53ea845..01303ef 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -37,19 +37,6 @@
 #include <asm/amigappc.h>
 #endif
 
-#ifdef CONFIG_PPC64BRIDGE
-#define LOAD_BAT(n, reg, RA, RB)	\
-	ld	RA,(n*32)+0(reg);	\
-	ld	RB,(n*32)+8(reg);	\
-	mtspr	SPRN_IBAT##n##U,RA;	\
-	mtspr	SPRN_IBAT##n##L,RB;	\
-	ld	RA,(n*32)+16(reg);	\
-	ld	RB,(n*32)+24(reg);	\
-	mtspr	SPRN_DBAT##n##U,RA;	\
-	mtspr	SPRN_DBAT##n##L,RB;	\
-
-#else /* CONFIG_PPC64BRIDGE */
-
 /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */
 #define LOAD_BAT(n, reg, RA, RB)	\
 	/* see the comment for clear_bats() -- Cort */ \
@@ -66,7 +53,6 @@
 	mtspr	SPRN_DBAT##n##U,RA;	\
 	mtspr	SPRN_DBAT##n##L,RB;	\
 1:
-#endif /* CONFIG_PPC64BRIDGE */
 
 	.text
 	.stabs	"arch/ppc/kernel/",N_SO,0,0,0f
@@ -129,11 +115,6 @@
 
 	.globl	__start
 __start:
-/*
- * We have to do any OF calls before we map ourselves to KERNELBASE,
- * because OF may have I/O devices mapped into that area
- * (particularly on CHRP).
- */
 	mr	r31,r3			/* save parameters */
 	mr	r30,r4
 	mr	r29,r5
@@ -148,14 +129,6 @@
  */
 	bl	early_init
 
-/*
- * On POWER4, we first need to tweak some CPU configuration registers
- * like real mode cache inhibit or exception base
- */
-#ifdef CONFIG_POWER4
-	bl	__970_cpu_preinit
-#endif /* CONFIG_POWER4 */
-
 #ifdef CONFIG_APUS
 /* On APUS the __va/__pa constants need to be set to the correct
  * values before continuing.
@@ -169,7 +142,6 @@
  */
  	bl	mmu_off
 __after_mmu_off:
-#ifndef CONFIG_POWER4
 	bl	clear_bats
 	bl	flush_tlbs
 
@@ -177,10 +149,6 @@
 #if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
 	bl	setup_disp_bat
 #endif
-#else /* CONFIG_POWER4 */
-	bl	reloc_offset
-	bl	initial_mm_power4
-#endif /* CONFIG_POWER4 */
 
 /*
  * Call setup_cpu for CPU 0 and initialize 6xx Idle
@@ -192,18 +160,11 @@
 	bl	reloc_offset
 	bl	init_idle_6xx
 #endif /* CONFIG_6xx */
-#ifdef CONFIG_POWER4
-	bl	reloc_offset
-	bl	init_idle_power4
-#endif /* CONFIG_POWER4 */
 
 
 #ifndef CONFIG_APUS
 /*
  * We need to run with _start at physical address 0.
- * On CHRP, we are loaded at 0x10000 since OF on CHRP uses
- * the exception vectors at 0 (and therefore this copy
- * overwrites OF's exception vectors with our own).
  * If the MMU is already turned on, we copy stuff to KERNELBASE,
  * otherwise we copy it to 0.
  */
@@ -358,51 +319,19 @@
 #endif
 
 /* Machine check */
-/*
- * On CHRP, this is complicated by the fact that we could get a
- * machine check inside RTAS, and we have no guarantee that certain
- * critical registers will have the values we expect.  The set of
- * registers that might have bad values includes all the GPRs
- * and all the BATs.  We indicate that we are in RTAS by putting
- * a non-zero value, the address of the exception frame to use,
- * in SPRG2.  The machine check handler checks SPRG2 and uses its
- * value if it is non-zero.  If we ever needed to free up SPRG2,
- * we could use a field in the thread_info or thread_struct instead.
- * (Other exception handlers assume that r1 is a valid kernel stack
- * pointer when we take an exception from supervisor mode.)
- *	-- paulus.
- */
 	. = 0x200
 	mtspr	SPRN_SPRG0,r10
 	mtspr	SPRN_SPRG1,r11
 	mfcr	r10
-#ifdef CONFIG_PPC_CHRP
-	mfspr	r11,SPRN_SPRG2
-	cmpwi	0,r11,0
-	bne	7f
-#endif /* CONFIG_PPC_CHRP */
 	EXCEPTION_PROLOG_1
 7:	EXCEPTION_PROLOG_2
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-#ifdef CONFIG_PPC_CHRP
-	mfspr	r4,SPRN_SPRG2
-	cmpwi	cr1,r4,0
-	bne	cr1,1f
-#endif
 	EXC_XFER_STD(0x200, machine_check_exception)
-#ifdef CONFIG_PPC_CHRP
-1:	b	machine_check_in_rtas
-#endif
 
 /* Data access exception. */
 	. = 0x300
-#ifdef CONFIG_PPC64BRIDGE
-	b	DataAccess
-DataAccessCont:
-#else
 DataAccess:
 	EXCEPTION_PROLOG
-#endif /* CONFIG_PPC64BRIDGE */
 	mfspr	r10,SPRN_DSISR
 	andis.	r0,r10,0xa470		/* weird error? */
 	bne	1f			/* if not, try to put a PTE */
@@ -414,21 +343,10 @@
 	mfspr	r4,SPRN_DAR
 	EXC_XFER_EE_LITE(0x300, handle_page_fault)
 
-#ifdef CONFIG_PPC64BRIDGE
-/* SLB fault on data access. */
-	. = 0x380
-	b	DataSegment
-#endif /* CONFIG_PPC64BRIDGE */
-
 /* Instruction access exception. */
 	. = 0x400
-#ifdef CONFIG_PPC64BRIDGE
-	b	InstructionAccess
-InstructionAccessCont:
-#else
 InstructionAccess:
 	EXCEPTION_PROLOG
-#endif /* CONFIG_PPC64BRIDGE */
 	andis.	r0,r9,0x4000		/* no pte found? */
 	beq	1f			/* if so, try to put a PTE */
 	li	r3,0			/* into the hash table */
@@ -438,12 +356,6 @@
 	mr	r5,r9
 	EXC_XFER_EE_LITE(0x400, handle_page_fault)
 
-#ifdef CONFIG_PPC64BRIDGE
-/* SLB fault on instruction access. */
-	. = 0x480
-	b	InstructionSegment
-#endif /* CONFIG_PPC64BRIDGE */
-
 /* External interrupt */
 	EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
 
@@ -708,15 +620,9 @@
 	EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception, EXC_XFER_EE)
 	EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_EE)
 	EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE)
-#ifdef CONFIG_POWER4
-	EXCEPTION(0x1600, Trap_16, unknown_exception, EXC_XFER_EE)
-	EXCEPTION(0x1700, Trap_17, altivec_assist_exception, EXC_XFER_EE)
-	EXCEPTION(0x1800, Trap_18, TAUException, EXC_XFER_STD)
-#else /* !CONFIG_POWER4 */
 	EXCEPTION(0x1600, Trap_16, altivec_assist_exception, EXC_XFER_EE)
 	EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD)
 	EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE)
-#endif /* CONFIG_POWER4 */
 	EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE)
 	EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_EE)
 	EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_EE)
@@ -754,28 +660,6 @@
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception)
 
-#ifdef CONFIG_PPC64BRIDGE
-DataAccess:
-	EXCEPTION_PROLOG
-	b	DataAccessCont
-
-InstructionAccess:
-	EXCEPTION_PROLOG
-	b	InstructionAccessCont
-
-DataSegment:
-	EXCEPTION_PROLOG
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	mfspr	r4,SPRN_DAR
-	stw	r4,_DAR(r11)
-	EXC_XFER_STD(0x380, unknown_exception)
-
-InstructionSegment:
-	EXCEPTION_PROLOG
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	EXC_XFER_STD(0x480, unknown_exception)
-#endif /* CONFIG_PPC64BRIDGE */
-
 #ifdef CONFIG_ALTIVEC
 /* Note that the AltiVec support is closely modeled after the FP
  * support.  Changes to one are likely to be applicable to the
@@ -1048,13 +932,6 @@
 
 	.globl	__secondary_start
 __secondary_start:
-#ifdef CONFIG_PPC64BRIDGE
-	mfmsr	r0
-	clrldi	r0,r0,1			/* make sure it's in 32-bit mode */
-	SYNC
-	MTMSRD(r0)
-	isync
-#endif
 	/* Copy some CPU settings from CPU 0 */
 	bl	__restore_cpu_setup
 
@@ -1065,10 +942,6 @@
 	lis	r3,-KERNELBASE@h
 	bl	init_idle_6xx
 #endif /* CONFIG_6xx */
-#ifdef CONFIG_POWER4
-	lis	r3,-KERNELBASE@h
-	bl	init_idle_power4
-#endif /* CONFIG_POWER4 */
 
 	/* get current_thread_info and current */
 	lis	r1,secondary_ti@ha
@@ -1109,12 +982,12 @@
  * Those generic dummy functions are kept for CPUs not
  * included in CONFIG_6xx
  */
-#if !defined(CONFIG_6xx) && !defined(CONFIG_POWER4)
+#if !defined(CONFIG_6xx)
 _GLOBAL(__save_cpu_setup)
 	blr
 _GLOBAL(__restore_cpu_setup)
 	blr
-#endif /* !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) */
+#endif /* !defined(CONFIG_6xx) */
 
 
 /*
@@ -1132,11 +1005,6 @@
 	tophys(r6,r6)
 	lwz	r6,_SDR1@l(r6)
 	mtspr	SPRN_SDR1,r6
-#ifdef CONFIG_PPC64BRIDGE
-	/* clear the ASR so we only use the pseudo-segment registers. */
-	li	r6,0
-	mtasr	r6
-#endif /* CONFIG_PPC64BRIDGE */
 	li	r0,16		/* load up segment register values */
 	mtctr	r0		/* for context 0 */
 	lis	r3,0x2000	/* Ku = 1, VSID = 0 */
@@ -1145,7 +1013,7 @@
 	addi	r3,r3,0x111	/* increment VSID */
 	addis	r4,r4,0x1000	/* address of next segment */
 	bdnz	3b
-#ifndef CONFIG_POWER4
+
 /* Load the BAT registers with the values set up by MMU_init.
    MMU_init takes care of whether we're on a 601 or not. */
 	mfpvr	r3
@@ -1158,7 +1026,7 @@
 	LOAD_BAT(1,r3,r4,r5)
 	LOAD_BAT(2,r3,r4,r5)
 	LOAD_BAT(3,r3,r4,r5)
-#endif /* CONFIG_POWER4 */
+
 	blr
 
 /*
@@ -1269,9 +1137,6 @@
 	li	r4,0
 	isync
 3:
-#ifdef CONFIG_PPC64BRIDGE
-	slbie	r4
-#endif /* CONFIG_PPC64BRIDGE */
 	mtsrin	r3,r4
 	addi	r3,r3,0x111	/* next VSID */
 	rlwinm	r3,r3,0,8,3	/* clear out any overflow from VSID field */
@@ -1358,7 +1223,6 @@
 	sync
 	RFI
 
-#ifndef CONFIG_POWER4
 /*
  * Use the first pair of BAT registers to map the 1st 16MB
  * of RAM to KERNELBASE.  From this point on we can't safely
@@ -1366,7 +1230,6 @@
  */
 initial_bats:
 	lis	r11,KERNELBASE@h
-#ifndef CONFIG_PPC64BRIDGE
 	mfspr	r9,SPRN_PVR
 	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
 	cmpwi	0,r9,1
@@ -1381,7 +1244,6 @@
 	mtspr	SPRN_IBAT1L,r10
 	isync
 	blr
-#endif /* CONFIG_PPC64BRIDGE */
 
 4:	tophys(r8,r11)
 #ifdef CONFIG_SMP
@@ -1395,11 +1257,6 @@
 	ori	r11,r11,BL_256M<<2|0x2	/* set up BAT registers for 604 */
 #endif /* CONFIG_APUS */
 
-#ifdef CONFIG_PPC64BRIDGE
-	/* clear out the high 32 bits in the BAT */
-	clrldi	r11,r11,32
-	clrldi	r8,r8,32
-#endif /* CONFIG_PPC64BRIDGE */
 	mtspr	SPRN_DBAT0L,r8		/* N.B. 6xx (not 601) have valid */
 	mtspr	SPRN_DBAT0U,r11		/* bit in upper BAT register */
 	mtspr	SPRN_IBAT0L,r8
@@ -1432,38 +1289,6 @@
 
 #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
 
-#else /* CONFIG_POWER4 */
-/*
- * Load up the SDR1 and segment register values now
- * since we don't have the BATs.
- * Also make sure we are running in 32-bit mode.
- */
-
-initial_mm_power4:
-	addis	r14,r3,_SDR1@ha		/* get the value from _SDR1 */
-	lwz	r14,_SDR1@l(r14)	/* assume hash table below 4GB */
-	mtspr	SPRN_SDR1,r14
-	slbia
-	lis	r4,0x2000		/* set pseudo-segment reg 12 */
-	ori	r5,r4,0x0ccc
-	mtsr	12,r5
-#if 0
-	ori	r5,r4,0x0888		/* set pseudo-segment reg 8 */
-	mtsr	8,r5			/* (for access to serial port) */
-#endif
-#ifdef CONFIG_BOOTX_TEXT
-	ori	r5,r4,0x0999		/* set pseudo-segment reg 9 */
-	mtsr	9,r5			/* (for access to screen) */
-#endif
-	mfmsr	r0
-	clrldi	r0,r0,1
-	sync
-	mtmsr	r0
-	isync
-	blr
-
-#endif /* CONFIG_POWER4 */
-
 #ifdef CONFIG_8260
 /* Jump into the system reset for the rom.
  * We first disable the MMU, and then jump to the ROM reset address.
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
deleted file mode 100644
index 1be3ca5..0000000
--- a/arch/ppc/kernel/idle.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Idle daemon for PowerPC.  Idle daemon will handle any action
- * that needs to be taken when the system becomes idle.
- *
- * Written by Cort Dougan (cort@cs.nmt.edu).  Subsequently hacked
- * on by Tom Rini, Armin Kuster, Paul Mackerras and others.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/sysctl.h>
-#include <linux/cpu.h>
-
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/mmu.h>
-#include <asm/cache.h>
-#include <asm/cputable.h>
-#include <asm/machdep.h>
-#include <asm/smp.h>
-
-void default_idle(void)
-{
-	void (*powersave)(void);
-
-	powersave = ppc_md.power_save;
-
-	if (!need_resched()) {
-		if (powersave != NULL)
-			powersave();
-#ifdef CONFIG_SMP
-		else {
-			set_thread_flag(TIF_POLLING_NRFLAG);
-			while (!need_resched() &&
-					!cpu_is_offline(smp_processor_id()))
-				barrier();
-			clear_thread_flag(TIF_POLLING_NRFLAG);
-		}
-#endif
-	}
-}
-
-/*
- * The body of the idle task.
- */
-void cpu_idle(void)
-{
-	int cpu = smp_processor_id();
-
-	for (;;) {
-		while (!need_resched()) {
-			if (ppc_md.idle != NULL)
-				ppc_md.idle();
-			else
-				default_idle();
-		}
-
-		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
-			cpu_die();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
-	}
-}
-
-#if defined(CONFIG_SYSCTL) && defined(CONFIG_6xx)
-/*
- * Register the sysctl to set/clear powersave_nap.
- */
-extern int powersave_nap;
-
-static ctl_table powersave_nap_ctl_table[]={
-	{
-		.ctl_name	= KERN_PPC_POWERSAVE_NAP,
-		.procname	= "powersave-nap",
-		.data		= &powersave_nap,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-	{ 0, },
-};
-static ctl_table powersave_nap_sysctl_root[] = {
-	{ 1, "kernel", NULL, 0, 0755, powersave_nap_ctl_table, },
- 	{ 0,},
-};
-
-static int __init
-register_powersave_nap_sysctl(void)
-{
-	register_sysctl_table(powersave_nap_sysctl_root, 0);
-
-	return 0;
-}
-
-__initcall(register_powersave_nap_sysctl);
-#endif
diff --git a/arch/ppc/kernel/idle_6xx.S b/arch/ppc/kernel/idle_6xx.S
deleted file mode 100644
index 1a2194c..0000000
--- a/arch/ppc/kernel/idle_6xx.S
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- *  This file contains the power_save function for 6xx & 7xxx CPUs
- *  rewritten in assembler
- *
- *  Warning ! This code assumes that if your machine has a 750fx
- *  it will have PLL 1 set to low speed mode (used during NAP/DOZE).
- *  if this is not the case some additional changes will have to
- *  be done to check a runtime var (a bit like powersave-nap)
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- */
-
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/cputable.h>
-#include <asm/thread_info.h>
-#include <asm/ppc_asm.h>
-#include <asm/asm-offsets.h>
-
-#undef DEBUG
-
-	.text
-
-/*
- * Init idle, called at early CPU setup time from head.S for each CPU
- * Make sure no rest of NAP mode remains in HID0, save default
- * values for some CPU specific registers. Called with r24
- * containing CPU number and r3 reloc offset
- */
-_GLOBAL(init_idle_6xx)
-BEGIN_FTR_SECTION
-	mfspr	r4,SPRN_HID0
-	rlwinm	r4,r4,0,10,8	/* Clear NAP */
-	mtspr	SPRN_HID0, r4
-	b	1f
-END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
-	blr
-1:
-	slwi	r5,r24,2
-	add	r5,r5,r3
-BEGIN_FTR_SECTION
-	mfspr	r4,SPRN_MSSCR0
-	addis	r6,r5, nap_save_msscr0@ha
-	stw	r4,nap_save_msscr0@l(r6)
-END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR)
-BEGIN_FTR_SECTION
-	mfspr	r4,SPRN_HID1
-	addis	r6,r5,nap_save_hid1@ha
-	stw	r4,nap_save_hid1@l(r6)
-END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX)
-	blr
-
-/*
- * Here is the power_save_6xx function. This could eventually be
- * split into several functions & changing the function pointer
- * depending on the various features.
- */
-_GLOBAL(ppc6xx_idle)
-	/* Check if we can nap or doze, put HID0 mask in r3
-	 */
-	lis	r3, 0
-BEGIN_FTR_SECTION
-	lis	r3,HID0_DOZE@h
-END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
-BEGIN_FTR_SECTION
-	/* We must dynamically check for the NAP feature as it
-	 * can be cleared by CPU init after the fixups are done
-	 */
-	lis	r4,cur_cpu_spec@ha
-	lwz	r4,cur_cpu_spec@l(r4)
-	lwz	r4,CPU_SPEC_FEATURES(r4)
-	andi.	r0,r4,CPU_FTR_CAN_NAP
-	beq	1f
-	/* Now check if user or arch enabled NAP mode */
-	lis	r4,powersave_nap@ha
-	lwz	r4,powersave_nap@l(r4)
-	cmpwi	0,r4,0
-	beq	1f
-	lis	r3,HID0_NAP@h
-1:	
-END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
-	cmpwi	0,r3,0
-	beqlr
-
-	/* Clear MSR:EE */
-	mfmsr	r7
-	rlwinm	r0,r7,0,17,15
-	mtmsr	r0
-
-	/* Check current_thread_info()->flags */
-	rlwinm	r4,r1,0,0,18
-	lwz	r4,TI_FLAGS(r4)
-	andi.	r0,r4,_TIF_NEED_RESCHED
-	beq	1f
-	mtmsr	r7	/* out of line this ? */
-	blr
-1:	
-	/* Some pre-nap cleanups needed on some CPUs */
-	andis.	r0,r3,HID0_NAP@h
-	beq	2f
-BEGIN_FTR_SECTION
-	/* Disable L2 prefetch on some 745x and try to ensure
-	 * L2 prefetch engines are idle. As explained by errata
-	 * text, we can't be sure they are, we just hope very hard
-	 * that well be enough (sic !). At least I noticed Apple
-	 * doesn't even bother doing the dcbf's here...
-	 */
-	mfspr	r4,SPRN_MSSCR0
-	rlwinm	r4,r4,0,0,29
-	sync
-	mtspr	SPRN_MSSCR0,r4
-	sync
-	isync
-	lis	r4,KERNELBASE@h
-	dcbf	0,r4
-	dcbf	0,r4
-	dcbf	0,r4
-	dcbf	0,r4
-END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR)
-#ifdef DEBUG
-	lis	r6,nap_enter_count@ha
-	lwz	r4,nap_enter_count@l(r6)
-	addi	r4,r4,1
-	stw	r4,nap_enter_count@l(r6)
-#endif	
-2:
-BEGIN_FTR_SECTION
-	/* Go to low speed mode on some 750FX */
-	lis	r4,powersave_lowspeed@ha
-	lwz	r4,powersave_lowspeed@l(r4)
-	cmpwi	0,r4,0
-	beq	1f
-	mfspr	r4,SPRN_HID1
-	oris	r4,r4,0x0001
-	mtspr	SPRN_HID1,r4
-1:	
-END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX)
-
-	/* Go to NAP or DOZE now */	
-	mfspr	r4,SPRN_HID0
-	lis	r5,(HID0_NAP|HID0_SLEEP)@h
-BEGIN_FTR_SECTION
-	oris	r5,r5,HID0_DOZE@h
-END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
-	andc	r4,r4,r5
-	or	r4,r4,r3
-BEGIN_FTR_SECTION
-	oris	r4,r4,HID0_DPM@h	/* that should be done once for all  */
-END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
-	mtspr	SPRN_HID0,r4
-BEGIN_FTR_SECTION
-	DSSALL
-	sync
-END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-	ori	r7,r7,MSR_EE /* Could be ommited (already set) */
-	oris	r7,r7,MSR_POW@h
-	sync
-	isync
-	mtmsr	r7
-	isync
-	sync
-	blr
-	
-/*
- * Return from NAP/DOZE mode, restore some CPU specific registers,
- * we are called with DR/IR still off and r2 containing physical
- * address of current.
- */
-_GLOBAL(power_save_6xx_restore)
-	mfspr	r11,SPRN_HID0
-	rlwinm.	r11,r11,0,10,8	/* Clear NAP & copy NAP bit !state to cr1 EQ */
-	cror	4*cr1+eq,4*cr0+eq,4*cr0+eq
-BEGIN_FTR_SECTION
-	rlwinm	r11,r11,0,9,7	/* Clear DOZE */
-END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
-	mtspr	SPRN_HID0, r11
-
-#ifdef DEBUG
-	beq	cr1,1f
-	lis	r11,(nap_return_count-KERNELBASE)@ha
-	lwz	r9,nap_return_count@l(r11)
-	addi	r9,r9,1
-	stw	r9,nap_return_count@l(r11)
-1:
-#endif
-	
-	rlwinm	r9,r1,0,0,18
-	tophys(r9,r9)
-	lwz	r11,TI_CPU(r9)
-	slwi	r11,r11,2
-	/* Todo make sure all these are in the same page
-	 * and load r22 (@ha part + CPU offset) only once
-	 */
-BEGIN_FTR_SECTION
-	beq	cr1,1f
-	addis	r9,r11,(nap_save_msscr0-KERNELBASE)@ha
-	lwz	r9,nap_save_msscr0@l(r9)
-	mtspr	SPRN_MSSCR0, r9
-	sync
-	isync
-1:
-END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR)
-BEGIN_FTR_SECTION
-	addis	r9,r11,(nap_save_hid1-KERNELBASE)@ha
-	lwz	r9,nap_save_hid1@l(r9)
-	mtspr	SPRN_HID1, r9
-END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX)
-	b	transfer_to_handler_cont
-
-	.data
-
-_GLOBAL(nap_save_msscr0)
-	.space	4*NR_CPUS
-
-_GLOBAL(nap_save_hid1)
-	.space	4*NR_CPUS
-
-_GLOBAL(powersave_nap)
-	.long	0
-_GLOBAL(powersave_lowspeed)
-	.long	0
-
-#ifdef DEBUG
-_GLOBAL(nap_enter_count)
-	.space	4
-_GLOBAL(nap_return_count)
-	.space	4
-#endif
diff --git a/arch/ppc/kernel/idle_power4.S b/arch/ppc/kernel/idle_power4.S
deleted file mode 100644
index cc0d535..0000000
--- a/arch/ppc/kernel/idle_power4.S
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- *  This file contains the power_save function for 6xx & 7xxx CPUs
- *  rewritten in assembler
- *
- *  Warning ! This code assumes that if your machine has a 750fx
- *  it will have PLL 1 set to low speed mode (used during NAP/DOZE).
- *  if this is not the case some additional changes will have to
- *  be done to check a runtime var (a bit like powersave-nap)
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- */
-
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/cputable.h>
-#include <asm/thread_info.h>
-#include <asm/ppc_asm.h>
-#include <asm/asm-offsets.h>
-
-#undef DEBUG
-
-	.text
-
-/*
- * Init idle, called at early CPU setup time from head.S for each CPU
- * So nothing for now. Called with r24 containing CPU number and r3
- * reloc offset
- */
- 	.globl	init_idle_power4
-init_idle_power4:
-	blr
-
-/*
- * Here is the power_save_6xx function. This could eventually be
- * split into several functions & changing the function pointer
- * depending on the various features.
- */
-	.globl	power4_idle
-power4_idle:
-BEGIN_FTR_SECTION
-	blr
-END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
-	/* We must dynamically check for the NAP feature as it
-	 * can be cleared by CPU init after the fixups are done
-	 */
-	lis	r4,cur_cpu_spec@ha
-	lwz	r4,cur_cpu_spec@l(r4)
-	lwz	r4,CPU_SPEC_FEATURES(r4)
-	andi.	r0,r4,CPU_FTR_CAN_NAP
-	beqlr
-	/* Now check if user or arch enabled NAP mode */
-	lis	r4,powersave_nap@ha
-	lwz	r4,powersave_nap@l(r4)
-	cmpwi	0,r4,0
-	beqlr
-
-	/* Clear MSR:EE */
-	mfmsr	r7
-	rlwinm	r0,r7,0,17,15
-	mtmsr	r0
-
-	/* Check current_thread_info()->flags */
-	rlwinm	r4,r1,0,0,18
-	lwz	r4,TI_FLAGS(r4)
-	andi.	r0,r4,_TIF_NEED_RESCHED
-	beq	1f
-	mtmsr	r7	/* out of line this ? */
-	blr
-1:	
-	/* Go to NAP now */	
-BEGIN_FTR_SECTION
-	DSSALL
-	sync
-END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-	ori	r7,r7,MSR_EE /* Could be ommited (already set) */
-	oris	r7,r7,MSR_POW@h
-	sync
-	isync
-	mtmsr	r7
-	isync
-	sync
-	blr
-	
-	.globl powersave_nap
-powersave_nap:
-	.long	0
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 04d04c5..809673a 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -46,9 +46,6 @@
 static void fixup_broken_pcnet32(struct pci_dev* dev);
 static int reparent_resources(struct resource *parent, struct resource *res);
 static void fixup_cpc710_pci64(struct pci_dev* dev);
-#ifdef CONFIG_PPC_OF
-static u8* pci_to_OF_bus_map;
-#endif
 
 /* By default, we don't re-assign bus numbers.
  */
@@ -625,406 +622,13 @@
 	return hose;
 }
 
-#ifdef CONFIG_PPC_OF
-/*
- * Functions below are used on OpenFirmware machines.
- */
-static void
-make_one_node_map(struct device_node* node, u8 pci_bus)
-{
-	int *bus_range;
-	int len;
-
-	if (pci_bus >= pci_bus_count)
-		return;
-	bus_range = (int *) get_property(node, "bus-range", &len);
-	if (bus_range == NULL || len < 2 * sizeof(int)) {
-		printk(KERN_WARNING "Can't get bus-range for %s, "
-		       "assuming it starts at 0\n", node->full_name);
-		pci_to_OF_bus_map[pci_bus] = 0;
-	} else
-		pci_to_OF_bus_map[pci_bus] = bus_range[0];
-
-	for (node=node->child; node != 0;node = node->sibling) {
-		struct pci_dev* dev;
-		unsigned int *class_code, *reg;
-	
-		class_code = (unsigned int *) get_property(node, "class-code", NULL);
-		if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
-			(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
-			continue;
-		reg = (unsigned int *)get_property(node, "reg", NULL);
-		if (!reg)
-			continue;
-		dev = pci_find_slot(pci_bus, ((reg[0] >> 8) & 0xff));
-		if (!dev || !dev->subordinate)
-			continue;
-		make_one_node_map(node, dev->subordinate->number);
-	}
-}
-	
-void
-pcibios_make_OF_bus_map(void)
-{
-	int i;
-	struct pci_controller* hose;
-	u8* of_prop_map;
-
-	pci_to_OF_bus_map = (u8*)kmalloc(pci_bus_count, GFP_KERNEL);
-	if (!pci_to_OF_bus_map) {
-		printk(KERN_ERR "Can't allocate OF bus map !\n");
-		return;
-	}
-
-	/* We fill the bus map with invalid values, that helps
-	 * debugging.
-	 */
-	for (i=0; i<pci_bus_count; i++)
-		pci_to_OF_bus_map[i] = 0xff;
-
-	/* For each hose, we begin searching bridges */
-	for(hose=hose_head; hose; hose=hose->next) {
-		struct device_node* node;	
-		node = (struct device_node *)hose->arch_data;
-		if (!node)
-			continue;
-		make_one_node_map(node, hose->first_busno);
-	}
-	of_prop_map = get_property(find_path_device("/"), "pci-OF-bus-map", NULL);
-	if (of_prop_map)
-		memcpy(of_prop_map, pci_to_OF_bus_map, pci_bus_count);
-#ifdef DEBUG
-	printk("PCI->OF bus map:\n");
-	for (i=0; i<pci_bus_count; i++) {
-		if (pci_to_OF_bus_map[i] == 0xff)
-			continue;
-		printk("%d -> %d\n", i, pci_to_OF_bus_map[i]);
-	}
-#endif
-}
-
-typedef int (*pci_OF_scan_iterator)(struct device_node* node, void* data);
-
-static struct device_node*
-scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* data)
-{
-	struct device_node* sub_node;
-
-	for (; node != 0;node = node->sibling) {
-		unsigned int *class_code;
-	
-		if (filter(node, data))
-			return node;
-
-		/* For PCI<->PCI bridges or CardBus bridges, we go down
-		 * Note: some OFs create a parent node "multifunc-device" as
-		 * a fake root for all functions of a multi-function device,
-		 * we go down them as well.
-		 */
-		class_code = (unsigned int *) get_property(node, "class-code", NULL);
-		if ((!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
-			(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) &&
-			strcmp(node->name, "multifunc-device"))
-			continue;
-		sub_node = scan_OF_pci_childs(node->child, filter, data);
-		if (sub_node)
-			return sub_node;
-	}
-	return NULL;
-}
-
-static int
-scan_OF_pci_childs_iterator(struct device_node* node, void* data)
-{
-	unsigned int *reg;
-	u8* fdata = (u8*)data;
-	
-	reg = (unsigned int *) get_property(node, "reg", NULL);
-	if (reg && ((reg[0] >> 8) & 0xff) == fdata[1]
-		&& ((reg[0] >> 16) & 0xff) == fdata[0])
-		return 1;
-	return 0;
-}
-
-static struct device_node*
-scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn)
-{
-	u8 filter_data[2] = {bus, dev_fn};
-
-	return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data);
-}
-
-/*
- * Scans the OF tree for a device node matching a PCI device
- */
-struct device_node *
-pci_busdev_to_OF_node(struct pci_bus *bus, int devfn)
-{
-	struct pci_controller *hose;
-	struct device_node *node;
-	int busnr;
-
-	if (!have_of)
-		return NULL;
-	
-	/* Lookup the hose */
-	busnr = bus->number;
-	hose = pci_bus_to_hose(busnr);
-	if (!hose)
-		return NULL;
-
-	/* Check it has an OF node associated */
-	node = (struct device_node *) hose->arch_data;
-	if (!node)
-		return NULL;
-
-	/* Fixup bus number according to what OF think it is. */
-	if (pci_to_OF_bus_map)
-		busnr = pci_to_OF_bus_map[busnr];
-	if (busnr == 0xff)
-		return NULL;
-	
-	/* Now, lookup childs of the hose */
-	return scan_OF_childs_for_device(node->child, busnr, devfn);
-}
-EXPORT_SYMBOL(pci_busdev_to_OF_node);
-
-struct device_node*
-pci_device_to_OF_node(struct pci_dev *dev)
-{
-	return pci_busdev_to_OF_node(dev->bus, dev->devfn);
-}
-EXPORT_SYMBOL(pci_device_to_OF_node);
-
-/* This routine is meant to be used early during boot, when the
- * PCI bus numbers have not yet been assigned, and you need to
- * issue PCI config cycles to an OF device.
- * It could also be used to "fix" RTAS config cycles if you want
- * to set pci_assign_all_buses to 1 and still use RTAS for PCI
- * config cycles.
- */
-struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
-{
-	if (!have_of)
-		return NULL;
-	while(node) {
-		struct pci_controller* hose;
-		for (hose=hose_head;hose;hose=hose->next)
-			if (hose->arch_data == node)
-				return hose;
-		node=node->parent;
-	}
-	return NULL;
-}
-
-static int
-find_OF_pci_device_filter(struct device_node* node, void* data)
-{
-	return ((void *)node == data);
-}
-
-/*
- * Returns the PCI device matching a given OF node
- */
-int
-pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
-{
-	unsigned int *reg;
-	struct pci_controller* hose;
-	struct pci_dev* dev = NULL;
-	
-	if (!have_of)
-		return -ENODEV;
-	/* Make sure it's really a PCI device */
-	hose = pci_find_hose_for_OF_device(node);
-	if (!hose || !hose->arch_data)
-		return -ENODEV;
-	if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child,
-			find_OF_pci_device_filter, (void *)node))
-		return -ENODEV;
-	reg = (unsigned int *) get_property(node, "reg", NULL);
-	if (!reg)
-		return -ENODEV;
-	*bus = (reg[0] >> 16) & 0xff;
-	*devfn = ((reg[0] >> 8) & 0xff);
-
-	/* Ok, here we need some tweak. If we have already renumbered
-	 * all busses, we can't rely on the OF bus number any more.
-	 * the pci_to_OF_bus_map is not enough as several PCI busses
-	 * may match the same OF bus number.
-	 */
-	if (!pci_to_OF_bus_map)
-		return 0;
-
-	for_each_pci_dev(dev)
-		if (pci_to_OF_bus_map[dev->bus->number] == *bus &&
-				dev->devfn == *devfn) {
-			*bus = dev->bus->number;
-			pci_dev_put(dev);
-			return 0;
-		}
-
-	return -ENODEV;
-}
-EXPORT_SYMBOL(pci_device_from_OF_node);
-
-void __init
-pci_process_bridge_OF_ranges(struct pci_controller *hose,
-			   struct device_node *dev, int primary)
-{
-	static unsigned int static_lc_ranges[256] __initdata;
-	unsigned int *dt_ranges, *lc_ranges, *ranges, *prev;
-	unsigned int size;
-	int rlen = 0, orig_rlen;
-	int memno = 0;
-	struct resource *res;
-	int np, na = prom_n_addr_cells(dev);
-	np = na + 5;
-
-	/* First we try to merge ranges to fix a problem with some pmacs
-	 * that can have more than 3 ranges, fortunately using contiguous
-	 * addresses -- BenH
-	 */
-	dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
-	if (!dt_ranges)
-		return;
-	/* Sanity check, though hopefully that never happens */
-	if (rlen > sizeof(static_lc_ranges)) {
-		printk(KERN_WARNING "OF ranges property too large !\n");
-		rlen = sizeof(static_lc_ranges);
-	}
-	lc_ranges = static_lc_ranges;
-	memcpy(lc_ranges, dt_ranges, rlen);
-	orig_rlen = rlen;
-
-	/* Let's work on a copy of the "ranges" property instead of damaging
-	 * the device-tree image in memory
-	 */
-	ranges = lc_ranges;
-	prev = NULL;
-	while ((rlen -= np * sizeof(unsigned int)) >= 0) {
-		if (prev) {
-			if (prev[0] == ranges[0] && prev[1] == ranges[1] &&
-				(prev[2] + prev[na+4]) == ranges[2] &&
-				(prev[na+2] + prev[na+4]) == ranges[na+2]) {
-				prev[na+4] += ranges[na+4];
-				ranges[0] = 0;
-				ranges += np;
-				continue;
-			}
-		}
-		prev = ranges;
-		ranges += np;
-	}
-
-	/*
-	 * The ranges property is laid out as an array of elements,
-	 * each of which comprises:
-	 *   cells 0 - 2:	a PCI address
-	 *   cells 3 or 3+4:	a CPU physical address
-	 *			(size depending on dev->n_addr_cells)
-	 *   cells 4+5 or 5+6:	the size of the range
-	 */
-	ranges = lc_ranges;
-	rlen = orig_rlen;
-	while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {
-		res = NULL;
-		size = ranges[na+4];
-		switch ((ranges[0] >> 24) & 0x3) {
-		case 1:		/* I/O space */
-			if (ranges[2] != 0)
-				break;
-			hose->io_base_phys = ranges[na+2];
-			/* limit I/O space to 16MB */
-			if (size > 0x01000000)
-				size = 0x01000000;
-			hose->io_base_virt = ioremap(ranges[na+2], size);
-			if (primary)
-				isa_io_base = (unsigned long) hose->io_base_virt;
-			res = &hose->io_resource;
-			res->flags = IORESOURCE_IO;
-			res->start = ranges[2];
-			DBG("PCI: IO 0x%lx -> 0x%lx\n",
-				    res->start, res->start + size - 1);
-			break;
-		case 2:		/* memory space */
-			memno = 0;
-			if (ranges[1] == 0 && ranges[2] == 0
-			    && ranges[na+4] <= (16 << 20)) {
-				/* 1st 16MB, i.e. ISA memory area */
-				if (primary)
-					isa_mem_base = ranges[na+2];
-				memno = 1;
-			}
-			while (memno < 3 && hose->mem_resources[memno].flags)
-				++memno;
-			if (memno == 0)
-				hose->pci_mem_offset = ranges[na+2] - ranges[2];
-			if (memno < 3) {
-				res = &hose->mem_resources[memno];
-				res->flags = IORESOURCE_MEM;
-				if(ranges[0] & 0x40000000)
-					res->flags |= IORESOURCE_PREFETCH;
-				res->start = ranges[na+2];
-				DBG("PCI: MEM[%d] 0x%lx -> 0x%lx\n", memno,
-					    res->start, res->start + size - 1);
-			}
-			break;
-		}
-		if (res != NULL) {
-			res->name = dev->full_name;
-			res->end = res->start + size - 1;
-			res->parent = NULL;
-			res->sibling = NULL;
-			res->child = NULL;
-		}
-		ranges += np;
-	}
-}
-
-/* We create the "pci-OF-bus-map" property now so it appears in the
- * /proc device tree
- */
-void __init
-pci_create_OF_bus_map(void)
-{
-	struct property* of_prop;
-	
-	of_prop = (struct property*) alloc_bootmem(sizeof(struct property) + 256);
-	if (of_prop && find_path_device("/")) {
-		memset(of_prop, -1, sizeof(struct property) + 256);
-		of_prop->name = "pci-OF-bus-map";
-		of_prop->length = 256;
-		of_prop->value = (unsigned char *)&of_prop[1];
-		prom_add_property(find_path_device("/"), of_prop);
-	}
-}
-
-static ssize_t pci_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct pci_dev *pdev;
-	struct device_node *np;
-
-	pdev = to_pci_dev (dev);
-	np = pci_device_to_OF_node(pdev);
-	if (np == NULL || np->full_name == NULL)
-		return 0;
-	return sprintf(buf, "%s", np->full_name);
-}
-static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
-
-#else /* CONFIG_PPC_OF */
 void pcibios_make_OF_bus_map(void)
 {
 }
-#endif /* CONFIG_PPC_OF */
 
 /* Add sysfs properties */
 void pcibios_add_platform_entries(struct pci_dev *pdev)
 {
-#ifdef CONFIG_PPC_OF
-	device_create_file(&pdev->dev, &dev_attr_devspec);
-#endif /* CONFIG_PPC_OF */
 }
 
 
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
index 2f5c765..75c6450 100644
--- a/arch/ppc/kernel/ppc_htab.c
+++ b/arch/ppc/kernel/ppc_htab.c
@@ -52,7 +52,7 @@
 	return single_open(file, ppc_htab_show, NULL);
 }
 
-struct file_operations ppc_htab_operations = {
+const struct file_operations ppc_htab_operations = {
 	.open		= ppc_htab_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
@@ -104,7 +104,7 @@
 static int ppc_htab_show(struct seq_file *m, void *v)
 {
 	unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0;
-#if defined(CONFIG_PPC_STD_MMU) && !defined(CONFIG_PPC64BRIDGE)
+#if defined(CONFIG_PPC_STD_MMU)
 	unsigned int kptes = 0, uptes = 0;
 	PTE *ptr;
 #endif /* CONFIG_PPC_STD_MMU */
@@ -133,7 +133,6 @@
 		return 0;
 	}
 
-#ifndef CONFIG_PPC64BRIDGE
 	for (ptr = Hash; ptr < Hash_end; ptr++) {
 		unsigned int mctx, vsid;
 
@@ -147,7 +146,6 @@
 		else
 			uptes++;
 	}
-#endif
 
 	seq_printf(m,
 		      "PTE Hash Table Information\n"
@@ -155,20 +153,16 @@
 		      "Buckets\t\t: %lu\n"
  		      "Address\t\t: %08lx\n"
 		      "Entries\t\t: %lu\n"
-#ifndef CONFIG_PPC64BRIDGE
 		      "User ptes\t: %u\n"
 		      "Kernel ptes\t: %u\n"
 		      "Percent full\t: %lu%%\n"
-#endif
                       , (unsigned long)(Hash_size>>10),
 		      (Hash_size/(sizeof(PTE)*8)),
 		      (unsigned long)Hash,
 		      Hash_size/sizeof(PTE)
-#ifndef CONFIG_PPC64BRIDGE
                       , uptes,
 		      kptes,
 		      ((kptes+uptes)*100) / (Hash_size/sizeof(PTE))
-#endif
 		);
 
 	seq_printf(m,
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 82adb46..865ba74 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -18,7 +18,6 @@
 #include <linux/bitops.h>
 
 #include <asm/page.h>
-#include <asm/semaphore.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -30,7 +29,6 @@
 #include <linux/adb.h>
 #include <linux/cuda.h>
 #include <linux/pmu.h>
-#include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/pci-bridge.h>
 #include <asm/irq.h>
@@ -208,27 +206,6 @@
 EXPORT_SYMBOL(cuda_request);
 EXPORT_SYMBOL(cuda_poll);
 #endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_PPC_OF
-EXPORT_SYMBOL(find_devices);
-EXPORT_SYMBOL(find_type_devices);
-EXPORT_SYMBOL(find_compatible_devices);
-EXPORT_SYMBOL(find_path_device);
-EXPORT_SYMBOL(device_is_compatible);
-EXPORT_SYMBOL(machine_is_compatible);
-EXPORT_SYMBOL(find_all_nodes);
-EXPORT_SYMBOL(get_property);
-EXPORT_SYMBOL(request_OF_resource);
-EXPORT_SYMBOL(release_OF_resource);
-EXPORT_SYMBOL(of_find_node_by_name);
-EXPORT_SYMBOL(of_find_node_by_type);
-EXPORT_SYMBOL(of_find_compatible_node);
-EXPORT_SYMBOL(of_find_node_by_path);
-EXPORT_SYMBOL(of_find_all_nodes);
-EXPORT_SYMBOL(of_get_parent);
-EXPORT_SYMBOL(of_get_next_child);
-EXPORT_SYMBOL(of_node_get);
-EXPORT_SYMBOL(of_node_put);
-#endif /* CONFIG_PPC_OF */
 #if defined(CONFIG_BOOTX_TEXT)
 EXPORT_SYMBOL(btext_update_display);
 #endif
@@ -262,9 +239,6 @@
 EXPORT_SYMBOL(xmon);
 EXPORT_SYMBOL(xmon_printf);
 #endif
-EXPORT_SYMBOL(__up);
-EXPORT_SYMBOL(__down);
-EXPORT_SYMBOL(__down_interruptible);
 
 #if defined(CONFIG_KGDB) || defined(CONFIG_XMON)
 extern void (*debugger)(struct pt_regs *regs);
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 53e9dea..1f79e84 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -1,5 +1,5 @@
 /*
- * Common prep/chrp boot and setup code.
+ * Common prep boot and setup code.
  */
 
 #include <linux/config.h>
@@ -72,17 +72,12 @@
 unsigned int DMA_MODE_READ;
 unsigned int DMA_MODE_WRITE;
 
-#ifdef CONFIG_PPC_MULTIPLATFORM
-int _machine = 0;
-EXPORT_SYMBOL(_machine);
-
+#ifdef CONFIG_PPC_PREP
 extern void prep_init(unsigned long r3, unsigned long r4,
 		unsigned long r5, unsigned long r6, unsigned long r7);
-extern void chrp_init(unsigned long r3, unsigned long r4,
-		unsigned long r5, unsigned long r6, unsigned long r7);
 
 dev_t boot_dev;
-#endif /* CONFIG_PPC_MULTIPLATFORM */
+#endif /* CONFIG_PPC_PREP */
 
 int have_of;
 EXPORT_SYMBOL(have_of);
@@ -319,72 +314,12 @@
 	identify_cpu(offset, 0);
 	do_cpu_ftr_fixups(offset);
 
-#if defined(CONFIG_PPC_OF)
-	reloc_got2(offset);
-
-	/*
-	 * don't do anything on prep
-	 * for now, don't use bootinfo because it breaks yaboot 0.5
-	 * and assume that if we didn't find a magic number, we have OF
-	 */
-	if (*(unsigned long *)(0) != 0xdeadc0de)
-		phys = prom_init(r3, r4, (prom_entry)r5);
-
-	reloc_got2(-offset);
-#endif
-
 	return phys;
 }
 
-#ifdef CONFIG_PPC_OF
+#ifdef CONFIG_PPC_PREP
 /*
- * Assume here that all clock rates are the same in a
- * smp system.  -- Cort
- */
-int
-of_show_percpuinfo(struct seq_file *m, int i)
-{
-	struct device_node *cpu_node;
-	u32 *fp;
-	int s;
-	
-	cpu_node = find_type_devices("cpu");
-	if (!cpu_node)
-		return 0;
-	for (s = 0; s < i && cpu_node->next; s++)
-		cpu_node = cpu_node->next;
-	fp = (u32 *)get_property(cpu_node, "clock-frequency", NULL);
-	if (fp)
-		seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000);
-	return 0;
-}
-
-void __init
-intuit_machine_type(void)
-{
-	char *model;
-	struct device_node *root;
-	
-	/* ask the OF info if we're a chrp or pmac */
-	root = find_path_device("/");
-	if (root != 0) {
-		/* assume pmac unless proven to be chrp -- Cort */
-		_machine = _MACH_Pmac;
-		model = get_property(root, "device_type", NULL);
-		if (model && !strncmp("chrp", model, 4))
-			_machine = _MACH_chrp;
-		else {
-			model = get_property(root, "model", NULL);
-			if (model && !strncmp(model, "IBM", 3))
-				_machine = _MACH_chrp;
-		}
-	}
-}
-#endif
-
-#ifdef CONFIG_PPC_MULTIPLATFORM
-/*
- * The PPC_MULTIPLATFORM version of platform_init...
+ * The PPC_PREP version of platform_init...
  */
 void __init
 platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
@@ -399,161 +334,9 @@
 
 	parse_bootinfo(find_bootinfo());
 
-	/* if we didn't get any bootinfo telling us what we are... */
-	if (_machine == 0) {
-		/* prep boot loader tells us if we're prep or not */
-		if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) )
-			_machine = _MACH_prep;
-	}
-
-#ifdef CONFIG_PPC_PREP
-	/* not much more to do here, if prep */
-	if (_machine == _MACH_prep) {
-		prep_init(r3, r4, r5, r6, r7);
-		return;
-	}
-#endif
-
-#ifdef CONFIG_PPC_OF
-	have_of = 1;
-
-	/* prom_init has already been called from __start */
-	if (boot_infos)
-		relocate_nodes();
-
-	/* If we aren't PReP, we can find out if we're Pmac
-	 * or CHRP with this. */
-	if (_machine == 0)
-		intuit_machine_type();
-
-	/* finish_device_tree may need _machine defined. */
-	finish_device_tree();
-
-	/*
-	 * If we were booted via quik, r3 points to the physical
-	 * address of the command-line parameters.
-	 * If we were booted from an xcoff image (i.e. netbooted or
-	 * booted from floppy), we get the command line from the
-	 * bootargs property of the /chosen node.
-	 * If an initial ramdisk is present, r3 and r4
-	 * are used for initrd_start and initrd_size,
-	 * otherwise they contain 0xdeadbeef.
-	 */
-	if (r3 >= 0x4000 && r3 < 0x800000 && r4 == 0) {
-		strlcpy(cmd_line, (char *)r3 + KERNELBASE,
-			sizeof(cmd_line));
-	} else if (boot_infos != 0) {
-		/* booted by BootX - check for ramdisk */
-		if (boot_infos->kernelParamsOffset != 0)
-			strlcpy(cmd_line, (char *) boot_infos
-				+ boot_infos->kernelParamsOffset,
-				sizeof(cmd_line));
-#ifdef CONFIG_BLK_DEV_INITRD
-		if (boot_infos->ramDisk) {
-			initrd_start = (unsigned long) boot_infos
-				+ boot_infos->ramDisk;
-			initrd_end = initrd_start + boot_infos->ramDiskSize;
-			initrd_below_start_ok = 1;
-		}
-#endif
-	} else {
-		struct device_node *chosen;
-		char *p;
-	
-#ifdef CONFIG_BLK_DEV_INITRD
-		if (r3 && r4 && r4 != 0xdeadbeef) {
-			if (r3 < KERNELBASE)
-				r3 += KERNELBASE;
-			initrd_start = r3;
-			initrd_end = r3 + r4;
-			ROOT_DEV = Root_RAM0;
-			initrd_below_start_ok = 1;
-		}
-#endif
-		chosen = find_devices("chosen");
-		if (chosen != NULL) {
-			p = get_property(chosen, "bootargs", NULL);
-			if (p && *p) {
-				strlcpy(cmd_line, p, sizeof(cmd_line));
-			}
-		}
-	}
-#ifdef CONFIG_ADB
-	if (strstr(cmd_line, "adb_sync")) {
-		extern int __adb_probe_sync;
-		__adb_probe_sync = 1;
-	}
-#endif /* CONFIG_ADB */
-
-	switch (_machine) {
-#ifdef CONFIG_PPC_CHRP
-	case _MACH_chrp:
-		chrp_init(r3, r4, r5, r6, r7);
-		break;
-#endif
-	}
-#endif /* CONFIG_PPC_OF */
+	prep_init(r3, r4, r5, r6, r7);
 }
-#endif /* CONFIG_PPC_MULTIPLATFORM */
-
-#ifdef CONFIG_PPC_OF
-#ifdef CONFIG_SERIAL_CORE_CONSOLE
-extern char *of_stdout_device;
-
-static int __init set_preferred_console(void)
-{
-	struct device_node *prom_stdout;
-	char *name;
-	int offset = 0;
-
-	if (of_stdout_device == NULL)
-		return -ENODEV;
-
-	/* The user has requested a console so this is already set up. */
-	if (strstr(saved_command_line, "console="))
-		return -EBUSY;
-
-	prom_stdout = find_path_device(of_stdout_device);
-	if (!prom_stdout)
-		return -ENODEV;
-
-	name = (char *)get_property(prom_stdout, "name", NULL);
-	if (!name)
-		return -ENODEV;
-
-	if (strcmp(name, "serial") == 0) {
-		int i;
-		u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i);
-		if (i > 8) {
-			switch (reg[1]) {
-				case 0x3f8:
-					offset = 0;
-					break;
-				case 0x2f8:
-					offset = 1;
-					break;
-				case 0x898:
-					offset = 2;
-					break;
-				case 0x890:
-					offset = 3;
-					break;
-				default:
-					/* We dont recognise the serial port */
-					return -ENODEV;
-			}
-		}
-	} else if (strcmp(name, "ch-a") == 0)
-		offset = 0;
-	else if (strcmp(name, "ch-b") == 0)
-		offset = 1;
-	else
-		return -ENODEV;
-	return add_preferred_console("ttyS", offset, NULL);
-}
-console_initcall(set_preferred_console);
-#endif /* CONFIG_SERIAL_CORE_CONSOLE */
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_PREP */
 
 struct bi_record *find_bootinfo(void)
 {
@@ -589,23 +372,6 @@
 			initrd_end = data[0] + data[1] + KERNELBASE;
 			break;
 #endif /* CONFIG_BLK_DEV_INITRD */
-#ifdef CONFIG_PPC_MULTIPLATFORM
-		case BI_MACHTYPE:
-			/* Machine types changed with the merge. Since the
-			 * bootinfo are now deprecated, we can just hard code
-			 * the appropriate conversion here for when we are
-			 * called with yaboot which passes us a machine type
-			 * this way.
-			 */
-			switch(data[0]) {
-			case 1: _machine = _MACH_prep; break;
-			case 2: _machine = _MACH_Pmac; break;
-			case 4: _machine = _MACH_chrp; break;
-			default:
-				_machine = data[0];
-			}
-			break;
-#endif
 		case BI_MEMSIZE:
 			boot_mem_size = data[0];
 			break;
@@ -631,9 +397,6 @@
 #ifdef CONFIG_6xx
 	ppc_md.power_save = ppc6xx_idle;
 #endif
-#ifdef CONFIG_POWER4
-	ppc_md.power_save = power4_idle;
-#endif
 
 	platform_init(r3, r4, r5, r6, r7);
 
@@ -711,7 +474,7 @@
 	if ( ppc_md.progress ) ppc_md.progress("             ", 0xffff);
 
 	/* register CPU devices */
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 		register_cpu(&cpu_devices[i], i, NULL);
 
 	/* call platform init */
@@ -799,7 +562,4 @@
 	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
 
 	paging_init();
-
-	/* this is for modules since _machine can be a define -- Cort */
-	ppc_md.ppc_machine = _machine;
 }
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index e55cdda..f77795a 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -311,7 +311,7 @@
 	/* Backup CPU 0 state */
 	__save_cpu_setup();
 
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		if (cpu == smp_processor_id())
 			continue;
 		/* create a process for the processor */
diff --git a/arch/ppc/lib/strcase.c b/arch/ppc/lib/strcase.c
index 36b5210..3b0094c 100644
--- a/arch/ppc/lib/strcase.c
+++ b/arch/ppc/lib/strcase.c
@@ -1,4 +1,5 @@
 #include <linux/ctype.h>
+#include <linux/types.h>
 
 int strcasecmp(const char *s1, const char *s2)
 {
@@ -11,7 +12,7 @@
 	return c1 - c2;
 }
 
-int strncasecmp(const char *s1, const char *s2, int n)
+int strncasecmp(const char *s1, const char *s2, size_t n)
 {
 	int c1, c2;
 
diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
index 0217188..8e08ca3 100644
--- a/arch/ppc/mm/fault.c
+++ b/arch/ppc/mm/fault.c
@@ -202,6 +202,7 @@
 	/* an exec  - 4xx/Book-E allows for per-page execute permission */
 	} else if (TRAP(regs) == 0x400) {
 		pte_t *ptep;
+		pmd_t *pmdp;
 
 #if 0
 		/* It would be nice to actually enforce the VM execute
@@ -215,21 +216,24 @@
 		/* Since 4xx/Book-E supports per-page execute permission,
 		 * we lazily flush dcache to icache. */
 		ptep = NULL;
-		if (get_pteptr(mm, address, &ptep) && pte_present(*ptep)) {
-			struct page *page = pte_page(*ptep);
+		if (get_pteptr(mm, address, &ptep, &pmdp)) {
+			spinlock_t *ptl = pte_lockptr(mm, pmdp);
+			spin_lock(ptl);
+			if (pte_present(*ptep)) {
+				struct page *page = pte_page(*ptep);
 
-			if (! test_bit(PG_arch_1, &page->flags)) {
-				flush_dcache_icache_page(page);
-				set_bit(PG_arch_1, &page->flags);
+				if (!test_bit(PG_arch_1, &page->flags)) {
+					flush_dcache_icache_page(page);
+					set_bit(PG_arch_1, &page->flags);
+				}
+				pte_update(ptep, 0, _PAGE_HWEXEC);
+				_tlbie(address);
+				pte_unmap_unlock(ptep, ptl);
+				up_read(&mm->mmap_sem);
+				return 0;
 			}
-			pte_update(ptep, 0, _PAGE_HWEXEC);
-			_tlbie(address);
-			pte_unmap(ptep);
-			up_read(&mm->mmap_sem);
-			return 0;
+			pte_unmap_unlock(ptep, ptl);
 		}
-		if (ptep != NULL)
-			pte_unmap(ptep);
 #endif
 	/* a read */
 	} else {
diff --git a/arch/ppc/mm/hashtable.S b/arch/ppc/mm/hashtable.S
index f09fa88..31d0a92 100644
--- a/arch/ppc/mm/hashtable.S
+++ b/arch/ppc/mm/hashtable.S
@@ -74,12 +74,6 @@
  */
 	.text
 _GLOBAL(hash_page)
-#ifdef CONFIG_PPC64BRIDGE
-	mfmsr	r0
-	clrldi	r0,r0,1		/* make sure it's in 32-bit mode */
-	MTMSRD(r0)
-	isync
-#endif
 	tophys(r7,0)			/* gets -KERNELBASE into r7 */
 #ifdef CONFIG_SMP
 	addis	r8,r7,mmu_hash_lock@h
@@ -303,7 +297,6 @@
 Hash_bits = 12				/* e.g. 256kB hash table */
 Hash_msk = (((1 << Hash_bits) - 1) * 64)
 
-#ifndef CONFIG_PPC64BRIDGE
 /* defines for the PTE format for 32-bit PPCs */
 #define PTE_SIZE	8
 #define PTEG_SIZE	64
@@ -317,21 +310,6 @@
 #define SET_V(r)	oris r,r,PTE_V@h
 #define CLR_V(r,t)	rlwinm r,r,0,1,31
 
-#else
-/* defines for the PTE format for 64-bit PPCs */
-#define PTE_SIZE	16
-#define PTEG_SIZE	128
-#define LG_PTEG_SIZE	7
-#define LDPTEu		ldu
-#define STPTE		std
-#define CMPPTE		cmpd
-#define PTE_H		2
-#define PTE_V		1
-#define TST_V(r)	andi. r,r,PTE_V
-#define SET_V(r)	ori r,r,PTE_V
-#define CLR_V(r,t)	li t,PTE_V; andc r,r,t
-#endif /* CONFIG_PPC64BRIDGE */
-
 #define HASH_LEFT	31-(LG_PTEG_SIZE+Hash_bits-1)
 #define HASH_RIGHT	31-LG_PTEG_SIZE
 
@@ -349,14 +327,8 @@
 END_FTR_SECTION_IFSET(CPU_FTR_NEED_COHERENT)
 
 	/* Construct the high word of the PPC-style PTE (r5) */
-#ifndef CONFIG_PPC64BRIDGE
 	rlwinm	r5,r3,7,1,24		/* put VSID in 0x7fffff80 bits */
 	rlwimi	r5,r4,10,26,31		/* put in API (abbrev page index) */
-#else /* CONFIG_PPC64BRIDGE */
-	clrlwi	r3,r3,8			/* reduce vsid to 24 bits */
-	sldi	r5,r3,12		/* shift vsid into position */
-	rlwimi	r5,r4,16,20,24		/* put in API (abbrev page index) */
-#endif /* CONFIG_PPC64BRIDGE */
 	SET_V(r5)			/* set V (valid) bit */
 
 	/* Get the address of the primary PTE group in the hash table (r3) */
@@ -540,14 +512,8 @@
 	add	r3,r3,r0		/* note code below trims to 24 bits */
 
 	/* Construct the high word of the PPC-style PTE (r11) */
-#ifndef CONFIG_PPC64BRIDGE
 	rlwinm	r11,r3,7,1,24		/* put VSID in 0x7fffff80 bits */
 	rlwimi	r11,r4,10,26,31		/* put in API (abbrev page index) */
-#else /* CONFIG_PPC64BRIDGE */
-	clrlwi	r3,r3,8			/* reduce vsid to 24 bits */
-	sldi	r11,r3,12		/* shift vsid into position */
-	rlwimi	r11,r4,16,20,24		/* put in API (abbrev page index) */
-#endif /* CONFIG_PPC64BRIDGE */
 	SET_V(r11)			/* set V (valid) bit */
 
 #ifdef CONFIG_SMP
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index cb1c294..386e000 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -412,14 +412,6 @@
 	}
 #endif /* CONFIG_BLK_DEV_INITRD */
 
-#ifdef CONFIG_PPC_OF
-	/* mark the RTAS pages as reserved */
-	if ( rtas_data )
-		for (addr = (ulong)__va(rtas_data);
-		     addr < PAGE_ALIGN((ulong)__va(rtas_data)+rtas_size) ;
-		     addr += PAGE_SIZE)
-			SetPageReserved(virt_to_page(addr));
-#endif
 	for (addr = PAGE_OFFSET; addr < (unsigned long)high_memory;
 	     addr += PAGE_SIZE) {
 		if (!PageReserved(virt_to_page(addr)))
@@ -494,11 +486,6 @@
 				  initrd_end - initrd_start, 1);
 	}
 #endif /* CONFIG_BLK_DEV_INITRD */
-#ifdef CONFIG_PPC_OF
-	/* remove the RTAS pages from the available memory */
-	if (rtas_data)
-		mem_pieces_remove(&phys_avail, rtas_data, rtas_size, 1);
-#endif
 }
 
 /* Mark some memory as reserved by removing it from phys_avail. */
diff --git a/arch/ppc/mm/mmu_context.c b/arch/ppc/mm/mmu_context.c
index a8816e0..b4a4b3f 100644
--- a/arch/ppc/mm/mmu_context.c
+++ b/arch/ppc/mm/mmu_context.c
@@ -2,7 +2,7 @@
  * This file contains the routines for handling the MMU on those
  * PowerPC implementations where the MMU substantially follows the
  * architecture specification.  This includes the 6xx, 7xx, 7xxx,
- * 8260, and POWER3 implementations but excludes the 8xx and 4xx.
+ * 8260, and 83xx implementations but excludes the 8xx and 4xx.
  *  -- paulus
  *
  *  Derived from arch/ppc/mm/init.c:
diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c
index 6ea9185..706bca8 100644
--- a/arch/ppc/mm/pgtable.c
+++ b/arch/ppc/mm/pgtable.c
@@ -39,7 +39,7 @@
 unsigned long ioremap_bot;
 int io_bat_index;
 
-#if defined(CONFIG_6xx) || defined(CONFIG_POWER3)
+#if defined(CONFIG_6xx)
 #define HAVE_BATS	1
 #endif
 
@@ -368,7 +368,7 @@
  * the PTE pointer is unmodified if PTE is not found.
  */
 int
-get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep)
+get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp)
 {
         pgd_t	*pgd;
         pmd_t	*pmd;
@@ -383,6 +383,8 @@
                         if (pte) {
 				retval = 1;
 				*ptep = pte;
+				if (pmdp)
+					*pmdp = pmd;
 				/* XXX caller needs to do pte_unmap, yuck */
                         }
                 }
@@ -420,7 +422,7 @@
 		mm = &init_mm;
 
 	pa = 0;
-	if (get_pteptr(mm, addr, &pte)) {
+	if (get_pteptr(mm, addr, &pte, NULL)) {
 		pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK);
 		pte_unmap(pte);
 	}
diff --git a/arch/ppc/mm/ppc_mmu.c b/arch/ppc/mm/ppc_mmu.c
index 9a381ed5..25bb6f3 100644
--- a/arch/ppc/mm/ppc_mmu.c
+++ b/arch/ppc/mm/ppc_mmu.c
@@ -2,7 +2,7 @@
  * This file contains the routines for handling the MMU on those
  * PowerPC implementations where the MMU substantially follows the
  * architecture specification.  This includes the 6xx, 7xx, 7xxx,
- * 8260, and POWER3 implementations but excludes the 8xx and 4xx.
+ * 8260, and 83xx implementations but excludes the 8xx and 4xx.
  *  -- paulus
  *
  *  Derived from arch/ppc/mm/init.c:
@@ -42,11 +42,7 @@
 
 union ubat {			/* BAT register values to be loaded */
 	BAT	bat;
-#ifdef CONFIG_PPC64BRIDGE
-	u64	word[2];
-#else
 	u32	word[2];
-#endif
 } BATS[4][2];			/* 4 pairs of IBAT, DBAT */
 
 struct batrange {		/* stores address ranges mapped by BATs */
@@ -83,9 +79,6 @@
 
 unsigned long __init mmu_mapin_ram(void)
 {
-#ifdef CONFIG_POWER4
-	return 0;
-#else
 	unsigned long tot, bl, done;
 	unsigned long max_size = (256<<20);
 	unsigned long align;
@@ -122,7 +115,6 @@
 	}
 
 	return done;
-#endif
 }
 
 /*
@@ -205,27 +197,10 @@
 
 	if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105);
 
-#ifdef CONFIG_PPC64BRIDGE
-#define LG_HPTEG_SIZE	7		/* 128 bytes per HPTEG */
-#define SDR1_LOW_BITS	(lg_n_hpteg - 11)
-#define MIN_N_HPTEG	2048		/* min 256kB hash table */
-#else
 #define LG_HPTEG_SIZE	6		/* 64 bytes per HPTEG */
 #define SDR1_LOW_BITS	((n_hpteg - 1) >> 10)
 #define MIN_N_HPTEG	1024		/* min 64kB hash table */
-#endif
 
-#ifdef CONFIG_POWER4
-	/* The hash table has already been allocated and initialized
-	   in prom.c */
-	n_hpteg = Hash_size >> LG_HPTEG_SIZE;
-	lg_n_hpteg = __ilog2(n_hpteg);
-
-	/* Remove the hash table from the available memory */
-	if (Hash)
-		reserve_phys_mem(__pa(Hash), Hash_size);
-
-#else /* CONFIG_POWER4 */
 	/*
 	 * Allow 1 HPTE (1/8 HPTEG) for each page of memory.
 	 * This is less than the recommended amount, but then
@@ -248,7 +223,6 @@
 	Hash = mem_pieces_find(Hash_size, Hash_size);
 	cacheable_memzero(Hash, Hash_size);
 	_SDR1 = __pa(Hash) | SDR1_LOW_BITS;
-#endif /* CONFIG_POWER4 */
 
 	Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
 
diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
index e8b91a3..90c6222 100644
--- a/arch/ppc/platforms/Makefile
+++ b/arch/ppc/platforms/Makefile
@@ -2,18 +2,10 @@
 # Makefile for the linux kernel.
 #
 
-# Extra CFLAGS so we don't have to do relative includes
-CFLAGS_chrp_setup.o	+= -Iarch/$(ARCH)/mm
-
 obj-$(CONFIG_APUS)		+= apus_setup.o
 ifeq ($(CONFIG_APUS),y)
 obj-$(CONFIG_PCI)		+= apus_pci.o
 endif
-obj-$(CONFIG_PPC_CHRP)		+= chrp_setup.o chrp_time.o chrp_pci.o \
-					chrp_pegasos_eth.o
-ifeq ($(CONFIG_PPC_CHRP),y)
-obj-$(CONFIG_NVRAM)		+= chrp_nvram.o
-endif
 obj-$(CONFIG_PPC_PREP)		+= prep_pci.o prep_setup.o
 obj-$(CONFIG_PREP_RESIDUAL)	+= residual.o
 obj-$(CONFIG_PQ2ADS)		+= pq2ads.o
@@ -40,7 +32,3 @@
 obj-$(CONFIG_MPC86XADS)		+= mpc866ads_setup.o
 obj-$(CONFIG_MPC885ADS)		+= mpc885ads_setup.o
 obj-$(CONFIG_ADS8272)		+= mpc8272ads_setup.o
-
-ifeq ($(CONFIG_SMP),y)
-obj-$(CONFIG_PPC_CHRP)		+= chrp_smp.o
-endif
diff --git a/arch/ppc/platforms/chrp_nvram.c b/arch/ppc/platforms/chrp_nvram.c
deleted file mode 100644
index 465ba9b..0000000
--- a/arch/ppc/platforms/chrp_nvram.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- *  c 2001 PPC 64 Team, 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.
- *
- * /dev/nvram driver for PPC
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <asm/uaccess.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-
-static unsigned int nvram_size;
-static unsigned char nvram_buf[4];
-static DEFINE_SPINLOCK(nvram_lock);
-
-static unsigned char chrp_nvram_read(int addr)
-{
-	unsigned long done, flags;
-	unsigned char ret;
-
-	if (addr >= nvram_size) {
-		printk(KERN_DEBUG "%s: read addr %d > nvram_size %u\n",
-		       current->comm, addr, nvram_size);
-		return 0xff;
-	}
-	spin_lock_irqsave(&nvram_lock, flags);
-	if ((call_rtas("nvram-fetch", 3, 2, &done, addr, __pa(nvram_buf), 1) != 0) || 1 != done)
-		ret = 0xff;
-	else
-		ret = nvram_buf[0];
-	spin_unlock_irqrestore(&nvram_lock, flags);
-
-	return ret;
-}
-
-static void chrp_nvram_write(int addr, unsigned char val)
-{
-	unsigned long done, flags;
-
-	if (addr >= nvram_size) {
-		printk(KERN_DEBUG "%s: write addr %d > nvram_size %u\n",
-		       current->comm, addr, nvram_size);
-		return;
-	}
-	spin_lock_irqsave(&nvram_lock, flags);
-	nvram_buf[0] = val;
-	if ((call_rtas("nvram-store", 3, 2, &done, addr, __pa(nvram_buf), 1) != 0) || 1 != done)
-		printk(KERN_DEBUG "rtas IO error storing 0x%02x at %d", val, addr);
-	spin_unlock_irqrestore(&nvram_lock, flags);
-}
-
-void __init chrp_nvram_init(void)
-{
-	struct device_node *nvram;
-	unsigned int *nbytes_p, proplen;
-
-	nvram = of_find_node_by_type(NULL, "nvram");
-	if (nvram == NULL)
-		return;
-
-	nbytes_p = (unsigned int *)get_property(nvram, "#bytes", &proplen);
-	if (nbytes_p == NULL || proplen != sizeof(unsigned int))
-		return;
-
-	nvram_size = *nbytes_p;
-
-	printk(KERN_INFO "CHRP nvram contains %u bytes\n", nvram_size);
-	of_node_put(nvram);
-
-	ppc_md.nvram_read_val = chrp_nvram_read;
-	ppc_md.nvram_write_val = chrp_nvram_write;
-
-	return;
-}
diff --git a/arch/ppc/platforms/chrp_pci.c b/arch/ppc/platforms/chrp_pci.c
deleted file mode 100644
index c7fe618..0000000
--- a/arch/ppc/platforms/chrp_pci.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * CHRP pci routines.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/hydra.h>
-#include <asm/prom.h>
-#include <asm/gg2.h>
-#include <asm/machdep.h>
-#include <asm/sections.h>
-#include <asm/pci-bridge.h>
-#include <asm/open_pic.h>
-
-/* LongTrail */
-void __iomem *gg2_pci_config_base;
-
-/*
- * The VLSI Golden Gate II has only 512K of PCI configuration space, so we
- * limit the bus number to 3 bits
- */
-
-int gg2_read_config(struct pci_bus *bus, unsigned int devfn, int off,
-			   int len, u32 *val)
-{
-	volatile void __iomem *cfg_data;
-	struct pci_controller *hose = bus->sysdata;
-
-	if (bus->number > 7)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	/*
-	 * Note: the caller has already checked that off is
-	 * suitably aligned and that len is 1, 2 or 4.
-	 */
-	cfg_data = hose->cfg_data + ((bus->number<<16) | (devfn<<8) | off);
-	switch (len) {
-	case 1:
-		*val =  in_8(cfg_data);
-		break;
-	case 2:
-		*val = in_le16(cfg_data);
-		break;
-	default:
-		*val = in_le32(cfg_data);
-		break;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int gg2_write_config(struct pci_bus *bus, unsigned int devfn, int off,
-			    int len, u32 val)
-{
-	volatile void __iomem *cfg_data;
-	struct pci_controller *hose = bus->sysdata;
-
-	if (bus->number > 7)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	/*
-	 * Note: the caller has already checked that off is
-	 * suitably aligned and that len is 1, 2 or 4.
-	 */
-	cfg_data = hose->cfg_data + ((bus->number<<16) | (devfn<<8) | off);
-	switch (len) {
-	case 1:
-		out_8(cfg_data, val);
-		break;
-	case 2:
-		out_le16(cfg_data, val);
-		break;
-	default:
-		out_le32(cfg_data, val);
-		break;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops gg2_pci_ops =
-{
-	gg2_read_config,
-	gg2_write_config
-};
-
-/*
- * Access functions for PCI config space using RTAS calls.
- */
-int
-rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
-		 int len, u32 *val)
-{
-	struct pci_controller *hose = bus->sysdata;
-	unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
-		| (((bus->number - hose->first_busno) & 0xff) << 16)
-		| (hose->index << 24);
-        unsigned long ret = ~0UL;
-	int rval;
-
-	rval = call_rtas("read-pci-config", 2, 2, &ret, addr, len);
-	*val = ret;
-	return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;
-}
-
-int
-rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
-		  int len, u32 val)
-{
-	struct pci_controller *hose = bus->sysdata;
-	unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
-		| (((bus->number - hose->first_busno) & 0xff) << 16)
-		| (hose->index << 24);
-	int rval;
-
-	rval = call_rtas("write-pci-config", 3, 1, NULL, addr, len, val);
-	return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops rtas_pci_ops =
-{
-	rtas_read_config,
-	rtas_write_config
-};
-
-volatile struct Hydra __iomem *Hydra = NULL;
-
-int __init
-hydra_init(void)
-{
-	struct device_node *np;
-
-	np = find_devices("mac-io");
-	if (np == NULL || np->n_addrs == 0)
-		return 0;
-	Hydra = ioremap(np->addrs[0].address, np->addrs[0].size);
-	printk("Hydra Mac I/O at %x\n", np->addrs[0].address);
-	printk("Hydra Feature_Control was %x",
-	       in_le32(&Hydra->Feature_Control));
-	out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN |
-					   HYDRA_FC_SCSI_CELL_EN |
-					   HYDRA_FC_SCCA_ENABLE |
-					   HYDRA_FC_SCCB_ENABLE |
-					   HYDRA_FC_ARB_BYPASS |
-					   HYDRA_FC_MPIC_ENABLE |
-					   HYDRA_FC_SLOW_SCC_PCLK |
-					   HYDRA_FC_MPIC_IS_MASTER));
-	printk(", now %x\n", in_le32(&Hydra->Feature_Control));
-	return 1;
-}
-
-void __init
-chrp_pcibios_fixup(void)
-{
-	struct pci_dev *dev = NULL;
-	struct device_node *np;
-
-	/* PCI interrupts are controlled by the OpenPIC */
-	for_each_pci_dev(dev) {
-		np = pci_device_to_OF_node(dev);
-		if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0))
-			dev->irq = np->intrs[0].line;
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-	}
-}
-
-#define PRG_CL_RESET_VALID 0x00010000
-
-static void __init
-setup_python(struct pci_controller *hose, struct device_node *dev)
-{
-	u32 __iomem *reg;
-	u32 val;
-	unsigned long addr = dev->addrs[0].address;
-
-	setup_indirect_pci(hose, addr + 0xf8000, addr + 0xf8010);
-
-	/* Clear the magic go-slow bit */
-	reg = ioremap(dev->addrs[0].address + 0xf6000, 0x40);
-	val = in_be32(&reg[12]);
-	if (val & PRG_CL_RESET_VALID) {
-		out_be32(&reg[12], val & ~PRG_CL_RESET_VALID);
-		in_be32(&reg[12]);
-	}
-	iounmap(reg);
-}
-
-/* Marvell Discovery II based Pegasos 2 */
-static void __init setup_peg2(struct pci_controller *hose, struct device_node *dev)
-{
-	struct device_node *root = find_path_device("/");
-	struct device_node *rtas;
-
-	rtas = of_find_node_by_name (root, "rtas");
-	if (rtas) {
-		hose->ops = &rtas_pci_ops;
-	} else {
-		printk ("RTAS supporting Pegasos OF not found, please upgrade"
-			" your firmware\n");
-	}
-	pci_assign_all_buses = 1;
-}
-
-void __init
-chrp_find_bridges(void)
-{
-	struct device_node *dev;
-	int *bus_range;
-	int len, index = -1;
-	struct pci_controller *hose;
-	unsigned int *dma;
-	char *model, *machine;
-	int is_longtrail = 0, is_mot = 0, is_pegasos = 0;
-	struct device_node *root = find_path_device("/");
-
-	/*
-	 * The PCI host bridge nodes on some machines don't have
-	 * properties to adequately identify them, so we have to
-	 * look at what sort of machine this is as well.
-	 */
-	machine = get_property(root, "model", NULL);
-	if (machine != NULL) {
-		is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0;
-		is_mot = strncmp(machine, "MOT", 3) == 0;
-		if (strncmp(machine, "Pegasos2", 8) == 0)
-			is_pegasos = 2;
-		else if (strncmp(machine, "Pegasos", 7) == 0)
-			is_pegasos = 1;
-	}
-	for (dev = root->child; dev != NULL; dev = dev->sibling) {
-		if (dev->type == NULL || strcmp(dev->type, "pci") != 0)
-			continue;
-		++index;
-		/* The GG2 bridge on the LongTrail doesn't have an address */
-		if (dev->n_addrs < 1 && !is_longtrail) {
-			printk(KERN_WARNING "Can't use %s: no address\n",
-			       dev->full_name);
-			continue;
-		}
-		bus_range = (int *) get_property(dev, "bus-range", &len);
-		if (bus_range == NULL || len < 2 * sizeof(int)) {
-			printk(KERN_WARNING "Can't get bus-range for %s\n",
-				dev->full_name);
-			continue;
-		}
-		if (bus_range[1] == bus_range[0])
-			printk(KERN_INFO "PCI bus %d", bus_range[0]);
-		else
-			printk(KERN_INFO "PCI buses %d..%d",
-			       bus_range[0], bus_range[1]);
-		printk(" controlled by %s", dev->type);
-		if (dev->n_addrs > 0)
-			printk(" at %x", dev->addrs[0].address);
-		printk("\n");
-
-		hose = pcibios_alloc_controller();
-		if (!hose) {
-			printk("Can't allocate PCI controller structure for %s\n",
-				dev->full_name);
-			continue;
-		}
-		hose->arch_data = dev;
-		hose->first_busno = bus_range[0];
-		hose->last_busno = bus_range[1];
-
-		model = get_property(dev, "model", NULL);
-		if (model == NULL)
-			model = "<none>";
-		if (device_is_compatible(dev, "IBM,python")) {
-			setup_python(hose, dev);
-		} else if (is_mot
-			   || strncmp(model, "Motorola, Grackle", 17) == 0) {
-			setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
-		} else if (is_longtrail) {
-			void __iomem *p = ioremap(GG2_PCI_CONFIG_BASE, 0x80000);
-			hose->ops = &gg2_pci_ops;
-			hose->cfg_data = p;
-			gg2_pci_config_base = p;
-		} else if (is_pegasos == 1) {
-			setup_indirect_pci(hose, 0xfec00cf8, 0xfee00cfc);
-		} else if (is_pegasos == 2) {
-			setup_peg2(hose, dev);
-		} else {
-			printk("No methods for %s (model %s), using RTAS\n",
-			       dev->full_name, model);
-			hose->ops = &rtas_pci_ops;
-		}
-
-		pci_process_bridge_OF_ranges(hose, dev, index == 0);
-
-		/* check the first bridge for a property that we can
-		   use to set pci_dram_offset */
-		dma = (unsigned int *)
-			get_property(dev, "ibm,dma-ranges", &len);
-		if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) {
-			pci_dram_offset = dma[2] - dma[3];
-			printk("pci_dram_offset = %lx\n", pci_dram_offset);
-		}
-	}
-
-	/* Do not fixup interrupts from OF tree on pegasos */
-	if (is_pegasos == 0)
-		ppc_md.pcibios_fixup = chrp_pcibios_fixup;
-}
diff --git a/arch/ppc/platforms/chrp_pegasos_eth.c b/arch/ppc/platforms/chrp_pegasos_eth.c
deleted file mode 100644
index 9305c8a..0000000
--- a/arch/ppc/platforms/chrp_pegasos_eth.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- *  Copyright (C) 2005 Sven Luther <sl@bplan-gmbh.de>
- *  Thanks to :
- *	Dale Farnsworth <dale@farnsworth.org>
- *	Mark A. Greer <mgreer@mvista.com>
- *	Nicolas DET <nd@bplan-gmbh.de>
- *	Benjamin Herrenschmidt <benh@kernel.crashing.org>
- *  And anyone else who helped me on this.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/mv643xx.h>
-#include <linux/pci.h>
-
-#define PEGASOS2_MARVELL_REGBASE 		(0xf1000000)
-#define PEGASOS2_MARVELL_REGSIZE 		(0x00004000)
-#define PEGASOS2_SRAM_BASE 			(0xf2000000)
-#define PEGASOS2_SRAM_SIZE			(256*1024)
-
-#define PEGASOS2_SRAM_BASE_ETH0			(PEGASOS2_SRAM_BASE)
-#define PEGASOS2_SRAM_BASE_ETH1			(PEGASOS2_SRAM_BASE_ETH0 + (PEGASOS2_SRAM_SIZE / 2) )
-
-
-#define PEGASOS2_SRAM_RXRING_SIZE		(PEGASOS2_SRAM_SIZE/4)
-#define PEGASOS2_SRAM_TXRING_SIZE		(PEGASOS2_SRAM_SIZE/4)
-
-#undef BE_VERBOSE
-
-static struct resource mv643xx_eth_shared_resources[] = {
-	[0] = {
-		.name	= "ethernet shared base",
-		.start	= 0xf1000000 + MV643XX_ETH_SHARED_REGS,
-		.end	= 0xf1000000 + MV643XX_ETH_SHARED_REGS +
-					MV643XX_ETH_SHARED_REGS_SIZE - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-};
-
-static struct platform_device mv643xx_eth_shared_device = {
-	.name		= MV643XX_ETH_SHARED_NAME,
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(mv643xx_eth_shared_resources),
-	.resource	= mv643xx_eth_shared_resources,
-};
-
-static struct resource mv643xx_eth0_resources[] = {
-	[0] = {
-		.name	= "eth0 irq",
-		.start	= 9,
-		.end	= 9,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-
-static struct mv643xx_eth_platform_data eth0_pd = {
-	.tx_sram_addr = PEGASOS2_SRAM_BASE_ETH0,
-	.tx_sram_size = PEGASOS2_SRAM_TXRING_SIZE,
-	.tx_queue_size = PEGASOS2_SRAM_TXRING_SIZE/16,
-
-	.rx_sram_addr = PEGASOS2_SRAM_BASE_ETH0 + PEGASOS2_SRAM_TXRING_SIZE,
-	.rx_sram_size = PEGASOS2_SRAM_RXRING_SIZE,
-	.rx_queue_size = PEGASOS2_SRAM_RXRING_SIZE/16,
-};
-
-static struct platform_device eth0_device = {
-	.name		= MV643XX_ETH_NAME,
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(mv643xx_eth0_resources),
-	.resource	= mv643xx_eth0_resources,
-	.dev = {
-		.platform_data = &eth0_pd,
-	},
-};
-
-static struct resource mv643xx_eth1_resources[] = {
-	[0] = {
-		.name	= "eth1 irq",
-		.start	= 9,
-		.end	= 9,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct mv643xx_eth_platform_data eth1_pd = {
-	.tx_sram_addr = PEGASOS2_SRAM_BASE_ETH1,
-	.tx_sram_size = PEGASOS2_SRAM_TXRING_SIZE,
-	.tx_queue_size = PEGASOS2_SRAM_TXRING_SIZE/16,
-
-	.rx_sram_addr = PEGASOS2_SRAM_BASE_ETH1 + PEGASOS2_SRAM_TXRING_SIZE,
-	.rx_sram_size = PEGASOS2_SRAM_RXRING_SIZE,
-	.rx_queue_size = PEGASOS2_SRAM_RXRING_SIZE/16,
-};
-
-static struct platform_device eth1_device = {
-	.name		= MV643XX_ETH_NAME,
-	.id		= 1,
-	.num_resources	= ARRAY_SIZE(mv643xx_eth1_resources),
-	.resource	= mv643xx_eth1_resources,
-	.dev = {
-		.platform_data = &eth1_pd,
-	},
-};
-
-static struct platform_device *mv643xx_eth_pd_devs[] __initdata = {
-	&mv643xx_eth_shared_device,
-	&eth0_device,
-	&eth1_device,
-};
-
-/***********/
-/***********/
-#define MV_READ(offset,val) 	{ val = readl(mv643xx_reg_base + offset); }
-#define MV_WRITE(offset,data) writel(data, mv643xx_reg_base + offset)
-
-static void __iomem *mv643xx_reg_base;
-
-static int Enable_SRAM(void)
-{
-	u32 ALong;
-
-	if (mv643xx_reg_base == NULL)
-		mv643xx_reg_base = ioremap(PEGASOS2_MARVELL_REGBASE,
-					PEGASOS2_MARVELL_REGSIZE);
-
-	if (mv643xx_reg_base == NULL)
-		return -ENOMEM;
-
-#ifdef BE_VERBOSE
-	printk("Pegasos II/Marvell MV64361: register remapped from %p to %p\n",
-		(void *)PEGASOS2_MARVELL_REGBASE, (void *)mv643xx_reg_base);
-#endif
-
-	MV_WRITE(MV64340_SRAM_CONFIG, 0);
-
-	MV_WRITE(MV64340_INTEGRATED_SRAM_BASE_ADDR, PEGASOS2_SRAM_BASE >> 16);
-
-	MV_READ(MV64340_BASE_ADDR_ENABLE, ALong);
-	ALong &= ~(1 << 19);
-	MV_WRITE(MV64340_BASE_ADDR_ENABLE, ALong);
-
-	ALong = 0x02;
-	ALong |= PEGASOS2_SRAM_BASE & 0xffff0000;
-	MV_WRITE(MV643XX_ETH_BAR_4, ALong);
-
-	MV_WRITE(MV643XX_ETH_SIZE_REG_4, (PEGASOS2_SRAM_SIZE-1) & 0xffff0000);
-
-	MV_READ(MV643XX_ETH_BASE_ADDR_ENABLE_REG, ALong);
-	ALong &= ~(1 << 4);
-	MV_WRITE(MV643XX_ETH_BASE_ADDR_ENABLE_REG, ALong);
-
-#ifdef BE_VERBOSE
-	printk("Pegasos II/Marvell MV64361: register unmapped\n");
-	printk("Pegasos II/Marvell MV64361: SRAM at %p, size=%x\n", (void*) PEGASOS2_SRAM_BASE, PEGASOS2_SRAM_SIZE);
-#endif
-
-	iounmap(mv643xx_reg_base);
-	mv643xx_reg_base = NULL;
-
-	return 1;
-}
-
-
-/***********/
-/***********/
-int mv643xx_eth_add_pds(void)
-{
-	int ret = 0;
-	static struct pci_device_id pci_marvell_mv64360[] = {
-		{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_MV64360) },
-		{ }
-	};
-
-#ifdef BE_VERBOSE
-	printk("Pegasos II/Marvell MV64361: init\n");
-#endif
-
-	if (pci_dev_present(pci_marvell_mv64360)) {
-		ret = platform_add_devices(mv643xx_eth_pd_devs,
-				ARRAY_SIZE(mv643xx_eth_pd_devs));
-
-		if ( Enable_SRAM() < 0)
-		{
-			eth0_pd.tx_sram_addr = 0;
-			eth0_pd.tx_sram_size = 0;
-			eth0_pd.rx_sram_addr = 0;
-			eth0_pd.rx_sram_size = 0;
-
-			eth1_pd.tx_sram_addr = 0;
-			eth1_pd.tx_sram_size = 0;
-			eth1_pd.rx_sram_addr = 0;
-			eth1_pd.rx_sram_size = 0;
-
-#ifdef BE_VERBOSE
-			printk("Pegasos II/Marvell MV64361: Can't enable the "
-				"SRAM\n");
-#endif
-		}
-	}
-
-#ifdef BE_VERBOSE
-	printk("Pegasos II/Marvell MV64361: init is over\n");
-#endif
-
-	return ret;
-}
-
-device_initcall(mv643xx_eth_add_pds);
diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c
deleted file mode 100644
index f9fd3f4..0000000
--- a/arch/ppc/platforms/chrp_setup.c
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- *  Copyright (C) 1995  Linus Torvalds
- *  Adapted from 'alpha' version by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu)
- */
-
-/*
- * bootup setup stuff..
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/version.h>
-#include <linux/adb.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/console.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-#include <linux/initrd.h>
-#include <linux/module.h>
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/prom.h>
-#include <asm/gg2.h>
-#include <asm/pci-bridge.h>
-#include <asm/dma.h>
-#include <asm/machdep.h>
-#include <asm/irq.h>
-#include <asm/hydra.h>
-#include <asm/sections.h>
-#include <asm/time.h>
-#include <asm/btext.h>
-#include <asm/i8259.h>
-#include <asm/open_pic.h>
-#include <asm/xmon.h>
-#include "mem_pieces.h"
-
-unsigned long chrp_get_rtc_time(void);
-int chrp_set_rtc_time(unsigned long nowtime);
-void chrp_calibrate_decr(void);
-long chrp_time_init(void);
-
-void chrp_find_bridges(void);
-void chrp_event_scan(void);
-void rtas_display_progress(char *, unsigned short);
-void rtas_indicator_progress(char *, unsigned short);
-void btext_progress(char *, unsigned short);
-
-extern int of_show_percpuinfo(struct seq_file *, int);
-
-int _chrp_type;
-EXPORT_SYMBOL(_chrp_type);
-
-/*
- * XXX this should be in xmon.h, but putting it there means xmon.h
- * has to include <linux/interrupt.h> (to get irqreturn_t), which
- * causes all sorts of problems.  -- paulus
- */
-extern irqreturn_t xmon_irq(int, void *, struct pt_regs *);
-
-extern dev_t boot_dev;
-
-extern PTE *Hash, *Hash_end;
-extern unsigned long Hash_size, Hash_mask;
-extern int probingmem;
-extern unsigned long loops_per_jiffy;
-static int max_width;
-
-#ifdef CONFIG_SMP
-extern struct smp_ops_t chrp_smp_ops;
-#endif
-
-static const char *gg2_memtypes[4] = {
-	"FPM", "SDRAM", "EDO", "BEDO"
-};
-static const char *gg2_cachesizes[4] = {
-	"256 KB", "512 KB", "1 MB", "Reserved"
-};
-static const char *gg2_cachetypes[4] = {
-	"Asynchronous", "Reserved", "Flow-Through Synchronous",
-	"Pipelined Synchronous"
-};
-static const char *gg2_cachemodes[4] = {
-	"Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
-};
-
-int
-chrp_show_cpuinfo(struct seq_file *m)
-{
-	int i, sdramen;
-	unsigned int t;
-	struct device_node *root;
-	const char *model = "";
-
-	root = find_path_device("/");
-	if (root)
-		model = get_property(root, "model", NULL);
-	seq_printf(m, "machine\t\t: CHRP %s\n", model);
-
-	/* longtrail (goldengate) stuff */
-	if (!strncmp(model, "IBM,LongTrail", 13)) {
-		/* VLSI VAS96011/12 `Golden Gate 2' */
-		/* Memory banks */
-		sdramen = (in_le32(gg2_pci_config_base + GG2_PCI_DRAM_CTRL)
-			   >>31) & 1;
-		for (i = 0; i < (sdramen ? 4 : 6); i++) {
-			t = in_le32(gg2_pci_config_base+
-						 GG2_PCI_DRAM_BANK0+
-						 i*4);
-			if (!(t & 1))
-				continue;
-			switch ((t>>8) & 0x1f) {
-			case 0x1f:
-				model = "4 MB";
-				break;
-			case 0x1e:
-				model = "8 MB";
-				break;
-			case 0x1c:
-				model = "16 MB";
-				break;
-			case 0x18:
-				model = "32 MB";
-				break;
-			case 0x10:
-				model = "64 MB";
-				break;
-			case 0x00:
-				model = "128 MB";
-				break;
-			default:
-				model = "Reserved";
-				break;
-			}
-			seq_printf(m, "memory bank %d\t: %s %s\n", i, model,
-				   gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]);
-		}
-		/* L2 cache */
-		t = in_le32(gg2_pci_config_base+GG2_PCI_CC_CTRL);
-		seq_printf(m, "board l2\t: %s %s (%s)\n",
-			   gg2_cachesizes[(t>>7) & 3],
-			   gg2_cachetypes[(t>>2) & 3],
-			   gg2_cachemodes[t & 3]);
-	}
-	return 0;
-}
-
-/*
- *  Fixes for the National Semiconductor PC78308VUL SuperI/O
- *
- *  Some versions of Open Firmware incorrectly initialize the IRQ settings
- *  for keyboard and mouse
- */
-static inline void __init sio_write(u8 val, u8 index)
-{
-	outb(index, 0x15c);
-	outb(val, 0x15d);
-}
-
-static inline u8 __init sio_read(u8 index)
-{
-	outb(index, 0x15c);
-	return inb(0x15d);
-}
-
-static void __init sio_fixup_irq(const char *name, u8 device, u8 level,
-				     u8 type)
-{
-	u8 level0, type0, active;
-
-	/* select logical device */
-	sio_write(device, 0x07);
-	active = sio_read(0x30);
-	level0 = sio_read(0x70);
-	type0 = sio_read(0x71);
-	if (level0 != level || type0 != type || !active) {
-		printk(KERN_WARNING "sio: %s irq level %d, type %d, %sactive: "
-		       "remapping to level %d, type %d, active\n",
-		       name, level0, type0, !active ? "in" : "", level, type);
-		sio_write(0x01, 0x30);
-		sio_write(level, 0x70);
-		sio_write(type, 0x71);
-	}
-}
-
-static void __init sio_init(void)
-{
-	struct device_node *root;
-
-	if ((root = find_path_device("/")) &&
-	    !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) {
-		/* logical device 0 (KBC/Keyboard) */
-		sio_fixup_irq("keyboard", 0, 1, 2);
-		/* select logical device 1 (KBC/Mouse) */
-		sio_fixup_irq("mouse", 1, 12, 2);
-	}
-}
-
-
-static void __init pegasos_set_l2cr(void)
-{
-	struct device_node *np;
-
-	/* On Pegasos, enable the l2 cache if needed, as the OF forgets it */
-	if (_chrp_type != _CHRP_Pegasos)
-		return;
-
-	/* Enable L2 cache if needed */
-	np = find_type_devices("cpu");
-	if (np != NULL) {
-		unsigned int *l2cr = (unsigned int *)
-			get_property (np, "l2cr", NULL);
-		if (l2cr == NULL) {
-			printk ("Pegasos l2cr : no cpu l2cr property found\n");
-			return;
-		}
-		if (!((*l2cr) & 0x80000000)) {
-			printk ("Pegasos l2cr : L2 cache was not active, "
-				"activating\n");
-			_set_L2CR(0);
-			_set_L2CR((*l2cr) | 0x80000000);
-		}
-	}
-}
-
-void __init chrp_setup_arch(void)
-{
-	struct device_node *device;
-
-	/* init to some ~sane value until calibrate_delay() runs */
-	loops_per_jiffy = 50000000/HZ;
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* this is fine for chrp */
-	initrd_below_start_ok = 1;
-
-	if (initrd_start)
-		ROOT_DEV = Root_RAM0;
-	else
-#endif
-		ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */
-
-	/* On pegasos, enable the L2 cache if not already done by OF */
-	pegasos_set_l2cr();
-
-	/* Lookup PCI host bridges */
-	chrp_find_bridges();
-
-#ifndef CONFIG_PPC64BRIDGE
-	/*
-	 *  Temporary fixes for PCI devices.
-	 *  -- Geert
-	 */
-	hydra_init();		/* Mac I/O */
-
-#endif /* CONFIG_PPC64BRIDGE */
-
-	/*
-	 *  Fix the Super I/O configuration
-	 */
-	sio_init();
-
-	/* Get the event scan rate for the rtas so we know how
-	 * often it expects a heartbeat. -- Cort
-	 */
-	if ( rtas_data ) {
-		struct property *p;
-		device = find_devices("rtas");
-		for ( p = device->properties;
-		      p && strncmp(p->name, "rtas-event-scan-rate", 20);
-		      p = p->next )
-			/* nothing */ ;
-		if ( p && *(unsigned long *)p->value ) {
-			ppc_md.heartbeat = chrp_event_scan;
-			ppc_md.heartbeat_reset = (HZ/(*(unsigned long *)p->value)*30)-1;
-			ppc_md.heartbeat_count = 1;
-			printk("RTAS Event Scan Rate: %lu (%lu jiffies)\n",
-			       *(unsigned long *)p->value, ppc_md.heartbeat_reset );
-		}
-	}
-
-	pci_create_OF_bus_map();
-}
-
-void
-chrp_event_scan(void)
-{
-	unsigned char log[1024];
-	unsigned long ret = 0;
-	/* XXX: we should loop until the hardware says no more error logs -- Cort */
-	call_rtas( "event-scan", 4, 1, &ret, 0xffffffff, 0,
-		   __pa(log), 1024 );
-	ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
-}
-
-void
-chrp_restart(char *cmd)
-{
-	printk("RTAS system-reboot returned %d\n",
-	       call_rtas("system-reboot", 0, 1, NULL));
-	for (;;);
-}
-
-void
-chrp_power_off(void)
-{
-	/* allow power on only with power button press */
-	printk("RTAS power-off returned %d\n",
-	       call_rtas("power-off", 2, 1, NULL,0xffffffff,0xffffffff));
-	for (;;);
-}
-
-void
-chrp_halt(void)
-{
-	chrp_power_off();
-}
-
-/*
- * Finds the open-pic node and sets OpenPIC_Addr based on its reg property.
- * Then checks if it has an interrupt-ranges property.  If it does then
- * we have a distributed open-pic, so call openpic_set_sources to tell
- * the openpic code where to find the interrupt source registers.
- */
-static void __init chrp_find_openpic(void)
-{
-	struct device_node *np;
-	int len, i;
-	unsigned int *iranges;
-	void __iomem *isu;
-
-	np = find_type_devices("open-pic");
-	if (np == NULL || np->n_addrs == 0)
-		return;
-	printk(KERN_INFO "OpenPIC at %x (size %x)\n",
-	       np->addrs[0].address, np->addrs[0].size);
-	OpenPIC_Addr = ioremap(np->addrs[0].address, 0x40000);
-	if (OpenPIC_Addr == NULL) {
-		printk(KERN_ERR "Failed to map OpenPIC!\n");
-		return;
-	}
-
-	iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len);
-	if (iranges == NULL || len < 2 * sizeof(unsigned int))
-		return;		/* not distributed */
-
-	/*
-	 * The first pair of cells in interrupt-ranges refers to the
-	 * IDU; subsequent pairs refer to the ISUs.
-	 */
-	len /= 2 * sizeof(unsigned int);
-	if (np->n_addrs < len) {
-		printk(KERN_ERR "Insufficient addresses for distributed"
-		       " OpenPIC (%d < %d)\n", np->n_addrs, len);
-		return;
-	}
-	if (iranges[1] != 0) {
-		printk(KERN_INFO "OpenPIC irqs %d..%d in IDU\n",
-		       iranges[0], iranges[0] + iranges[1] - 1);
-		openpic_set_sources(iranges[0], iranges[1], NULL);
-	}
-	for (i = 1; i < len; ++i) {
-		iranges += 2;
-		printk(KERN_INFO "OpenPIC irqs %d..%d in ISU at %x (%x)\n",
-		       iranges[0], iranges[0] + iranges[1] - 1,
-		       np->addrs[i].address, np->addrs[i].size);
-		isu = ioremap(np->addrs[i].address, np->addrs[i].size);
-		if (isu != NULL)
-			openpic_set_sources(iranges[0], iranges[1], isu);
-		else
-			printk(KERN_ERR "Failed to map OpenPIC ISU at %x!\n",
-			       np->addrs[i].address);
-	}
-}
-
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
-static struct irqaction xmon_irqaction = {
-	.handler = xmon_irq,
-	.mask = CPU_MASK_NONE,
-	.name = "XMON break",
-};
-#endif
-
-void __init chrp_init_IRQ(void)
-{
-	struct device_node *np;
-	unsigned long chrp_int_ack = 0;
-	unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
-	struct device_node *kbd;
-#endif
-
-	for (np = find_devices("pci"); np != NULL; np = np->next) {
-		unsigned int *addrp = (unsigned int *)
-			get_property(np, "8259-interrupt-acknowledge", NULL);
-
-		if (addrp == NULL)
-			continue;
-		chrp_int_ack = addrp[prom_n_addr_cells(np)-1];
-		break;
-	}
-	if (np == NULL)
-		printk(KERN_ERR "Cannot find PCI interrupt acknowledge address\n");
-
-	chrp_find_openpic();
-
-	if (OpenPIC_Addr) {
-		prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS);
-		OpenPIC_InitSenses = init_senses;
-		OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS;
-
-		openpic_init(NUM_8259_INTERRUPTS);
-		/* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */
-		openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
-				       i8259_irq);
-
-	}
-	i8259_init(chrp_int_ack, 0);
-
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
-	/* see if there is a keyboard in the device tree
-	   with a parent of type "adb" */
-	for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
-		if (kbd->parent && kbd->parent->type
-		    && strcmp(kbd->parent->type, "adb") == 0)
-			break;
-	if (kbd)
-		setup_irq(HYDRA_INT_ADB_NMI, &xmon_irqaction);
-#endif
-}
-
-void __init
-chrp_init2(void)
-{
-#ifdef CONFIG_NVRAM
-	chrp_nvram_init();
-#endif
-
-	request_region(0x20,0x20,"pic1");
-	request_region(0xa0,0x20,"pic2");
-	request_region(0x00,0x20,"dma1");
-	request_region(0x40,0x20,"timer");
-	request_region(0x80,0x10,"dma page reg");
-	request_region(0xc0,0x20,"dma2");
-
-	if (ppc_md.progress)
-		ppc_md.progress("  Have fun!    ", 0x7777);
-}
-
-static struct device_node *memory_node;
-
-static int __init get_mem_prop(char *name, struct mem_pieces *mp)
-{
-	struct reg_property *rp;
-	int i, s;
-	unsigned int *ip;
-	int nac = prom_n_addr_cells(memory_node);
-	int nsc = prom_n_size_cells(memory_node);
-
-	ip = (unsigned int *) get_property(memory_node, name, &s);
-	if (ip == NULL) {
-		printk(KERN_ERR "error: couldn't get %s property on /memory\n",
-		       name);
-		return 0;
-	}
-	s /= (nsc + nac) * 4;
-	rp = mp->regions;
-	for (i = 0; i < s; ++i, ip += nac+nsc) {
-		if (nac >= 2 && ip[nac-2] != 0)
-			continue;
-		rp->address = ip[nac-1];
-		if (nsc >= 2 && ip[nac+nsc-2] != 0)
-			rp->size = ~0U;
-		else
-			rp->size = ip[nac+nsc-1];
-		++rp;
-	}
-	mp->n_regions = rp - mp->regions;
-
-	/* Make sure the pieces are sorted. */
-	mem_pieces_sort(mp);
-	mem_pieces_coalesce(mp);
-	return 1;
-}
-
-static unsigned long __init chrp_find_end_of_memory(void)
-{
-	unsigned long a, total;
-	struct mem_pieces phys_mem;
-
-	/*
-	 * Find out where physical memory is, and check that it
-	 * starts at 0 and is contiguous.  It seems that RAM is
-	 * always physically contiguous on Power Macintoshes.
-	 *
-	 * Supporting discontiguous physical memory isn't hard,
-	 * it just makes the virtual <-> physical mapping functions
-	 * more complicated (or else you end up wasting space
-	 * in mem_map).
-	 */
-	memory_node = find_devices("memory");
-	if (memory_node == NULL || !get_mem_prop("reg", &phys_mem)
-	    || phys_mem.n_regions == 0)
-		panic("No RAM??");
-	a = phys_mem.regions[0].address;
-	if (a != 0)
-		panic("RAM doesn't start at physical address 0");
-	total = phys_mem.regions[0].size;
-
-	if (phys_mem.n_regions > 1) {
-		printk("RAM starting at 0x%x is not contiguous\n",
-		       phys_mem.regions[1].address);
-		printk("Using RAM from 0 to 0x%lx\n", total-1);
-	}
-
-	return total;
-}
-
-void __init
-chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
-	  unsigned long r6, unsigned long r7)
-{
-	struct device_node *root = find_path_device ("/");
-	char *machine = NULL;
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* take care of initrd if we have one */
-	if ( r6 )
-	{
-		initrd_start = r6 + KERNELBASE;
-		initrd_end = r6 + r7 + KERNELBASE;
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-	ISA_DMA_THRESHOLD = ~0L;
-	DMA_MODE_READ = 0x44;
-	DMA_MODE_WRITE = 0x48;
-	isa_io_base = CHRP_ISA_IO_BASE;		/* default value */
-	ppc_do_canonicalize_irqs = 1;
-
-	if (root)
-		machine = get_property(root, "model", NULL);
-	if (machine && strncmp(machine, "Pegasos", 7) == 0) {
-		_chrp_type = _CHRP_Pegasos;
-	} else if (machine && strncmp(machine, "IBM", 3) == 0) {
-		_chrp_type = _CHRP_IBM;
-	} else if (machine && strncmp(machine, "MOT", 3) == 0) {
-		_chrp_type = _CHRP_Motorola;
-	} else {
-		/* Let's assume it is an IBM chrp if all else fails */
-		_chrp_type = _CHRP_IBM;
-	}
-
-	ppc_md.setup_arch     = chrp_setup_arch;
-	ppc_md.show_percpuinfo = of_show_percpuinfo;
-	ppc_md.show_cpuinfo   = chrp_show_cpuinfo;
-
-	ppc_md.init_IRQ       = chrp_init_IRQ;
-	if (_chrp_type == _CHRP_Pegasos)
-		ppc_md.get_irq        = i8259_irq;
-	else
-		ppc_md.get_irq        = openpic_get_irq;
-
-	ppc_md.init           = chrp_init2;
-
-	ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
-
-	ppc_md.restart        = chrp_restart;
-	ppc_md.power_off      = chrp_power_off;
-	ppc_md.halt           = chrp_halt;
-
-	ppc_md.time_init      = chrp_time_init;
-	ppc_md.set_rtc_time   = chrp_set_rtc_time;
-	ppc_md.get_rtc_time   = chrp_get_rtc_time;
-	ppc_md.calibrate_decr = chrp_calibrate_decr;
-
-	ppc_md.find_end_of_memory = chrp_find_end_of_memory;
-
-	if (rtas_data) {
-		struct device_node *rtas;
-		unsigned int *p;
-
-		rtas = find_devices("rtas");
-		if (rtas != NULL) {
-			if (get_property(rtas, "display-character", NULL)) {
-				ppc_md.progress = rtas_display_progress;
-				p = (unsigned int *) get_property
-				       (rtas, "ibm,display-line-length", NULL);
-				if (p)
-					max_width = *p;
-			} else if (get_property(rtas, "set-indicator", NULL))
-				ppc_md.progress = rtas_indicator_progress;
-		}
-	}
-#ifdef CONFIG_BOOTX_TEXT
-	if (ppc_md.progress == NULL && boot_text_mapped)
-		ppc_md.progress = btext_progress;
-#endif
-
-#ifdef CONFIG_SMP
-	smp_ops = &chrp_smp_ops;
-#endif /* CONFIG_SMP */
-
-	/*
-	 * Print the banner, then scroll down so boot progress
-	 * can be printed.  -- Cort
-	 */
-	if (ppc_md.progress) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0);
-}
-
-void
-rtas_display_progress(char *s, unsigned short hex)
-{
-	int width;
-	char *os = s;
-
-	if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) )
-		return;
-
-	width = max_width;
-	while ( *os )
-	{
-		if ( (*os == '\n') || (*os == '\r') )
-			width = max_width;
-		else
-			width--;
-		call_rtas( "display-character", 1, 1, NULL, *os++ );
-		/* if we overwrite the screen length */
-		if ( width == 0 )
-			while ( (*os != 0) && (*os != '\n') && (*os != '\r') )
-				os++;
-	}
-
-	/*while ( width-- > 0 )*/
-	call_rtas( "display-character", 1, 1, NULL, ' ' );
-}
-
-void
-rtas_indicator_progress(char *s, unsigned short hex)
-{
-	call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex);
-}
-
-#ifdef CONFIG_BOOTX_TEXT
-void
-btext_progress(char *s, unsigned short hex)
-{
-	prom_print(s);
-	prom_print("\n");
-}
-#endif /* CONFIG_BOOTX_TEXT */
diff --git a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c
deleted file mode 100644
index 97e5395..0000000
--- a/arch/ppc/platforms/chrp_smp.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Smp support for CHRP machines.
- *
- * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
- * deal of code from the sparc and intel versions.
- *
- * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <asm/ptrace.h>
-#include <asm/atomic.h>
-#include <asm/irq.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/smp.h>
-#include <asm/residual.h>
-#include <asm/time.h>
-#include <asm/open_pic.h>
-#include <asm/machdep.h>
-
-extern unsigned long smp_chrp_cpu_nr;
-
-static int __init
-smp_chrp_probe(void)
-{
-	if (smp_chrp_cpu_nr > 1)
-		openpic_request_IPIs();
-
-	return smp_chrp_cpu_nr;
-}
-
-static void __devinit
-smp_chrp_kick_cpu(int nr)
-{
-	*(unsigned long *)KERNELBASE = nr;
-	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
-}
-
-static void __devinit
-smp_chrp_setup_cpu(int cpu_nr)
-{
-	if (OpenPIC_Addr)
-		do_openpic_setup_cpu();
-}
-
-static DEFINE_SPINLOCK(timebase_lock);
-static unsigned int timebase_upper = 0, timebase_lower = 0;
-
-void __devinit
-smp_chrp_give_timebase(void)
-{
-	spin_lock(&timebase_lock);
-	call_rtas("freeze-time-base", 0, 1, NULL);
-	timebase_upper = get_tbu();
-	timebase_lower = get_tbl();
-	spin_unlock(&timebase_lock);
-
-	while (timebase_upper || timebase_lower)
-		barrier();
-	call_rtas("thaw-time-base", 0, 1, NULL);
-}
-
-void __devinit
-smp_chrp_take_timebase(void)
-{
-	while (!(timebase_upper || timebase_lower))
-		barrier();
-	spin_lock(&timebase_lock);
-	set_tb(timebase_upper, timebase_lower);
-	timebase_upper = 0;
-	timebase_lower = 0;
-	spin_unlock(&timebase_lock);
-	printk("CPU %i taken timebase\n", smp_processor_id());
-}
-
-/* CHRP with openpic */
-struct smp_ops_t chrp_smp_ops = {
-	.message_pass = smp_openpic_message_pass,
-	.probe = smp_chrp_probe,
-	.kick_cpu = smp_chrp_kick_cpu,
-	.setup_cpu = smp_chrp_setup_cpu,
-	.give_timebase = smp_chrp_give_timebase,
-	.take_timebase = smp_chrp_take_timebase,
-};
diff --git a/arch/ppc/platforms/chrp_time.c b/arch/ppc/platforms/chrp_time.c
deleted file mode 100644
index c862777..0000000
--- a/arch/ppc/platforms/chrp_time.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * Adapted for PowerPC (PReP) by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu).
- * Copied and modified from arch/i386/kernel/time.c
- *
- */
-#include <linux/errno.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/timex.h>
-#include <linux/kernel_stat.h>
-#include <linux/mc146818rtc.h>
-#include <linux/init.h>
-#include <linux/bcd.h>
-
-#include <asm/io.h>
-#include <asm/nvram.h>
-#include <asm/prom.h>
-#include <asm/sections.h>
-#include <asm/time.h>
-
-extern spinlock_t rtc_lock;
-
-static int nvram_as1 = NVRAM_AS1;
-static int nvram_as0 = NVRAM_AS0;
-static int nvram_data = NVRAM_DATA;
-
-long __init chrp_time_init(void)
-{
-	struct device_node *rtcs;
-	int base;
-
-	rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
-	if (rtcs == NULL)
-		rtcs = find_compatible_devices("rtc", "ds1385-rtc");
-	if (rtcs == NULL || rtcs->addrs == NULL)
-		return 0;
-	base = rtcs->addrs[0].address;
-	nvram_as1 = 0;
-	nvram_as0 = base;
-	nvram_data = base + 1;
-
-	return 0;
-}
-
-int chrp_cmos_clock_read(int addr)
-{
-	if (nvram_as1 != 0)
-		outb(addr>>8, nvram_as1);
-	outb(addr, nvram_as0);
-	return (inb(nvram_data));
-}
-
-void chrp_cmos_clock_write(unsigned long val, int addr)
-{
-	if (nvram_as1 != 0)
-		outb(addr>>8, nvram_as1);
-	outb(addr, nvram_as0);
-	outb(val, nvram_data);
-	return;
-}
-
-/*
- * Set the hardware clock. -- Cort
- */
-int chrp_set_rtc_time(unsigned long nowtime)
-{
-	unsigned char save_control, save_freq_select;
-	struct rtc_time tm;
-
-	spin_lock(&rtc_lock);
-	to_tm(nowtime, &tm);
-
-	save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
-
-	chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
-
-	save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
-
-	chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-        tm.tm_year -= 1900;
-	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-		BIN_TO_BCD(tm.tm_sec);
-		BIN_TO_BCD(tm.tm_min);
-		BIN_TO_BCD(tm.tm_hour);
-		BIN_TO_BCD(tm.tm_mon);
-		BIN_TO_BCD(tm.tm_mday);
-		BIN_TO_BCD(tm.tm_year);
-	}
-	chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
-	chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES);
-	chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS);
-	chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH);
-	chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
-	chrp_cmos_clock_write(tm.tm_year,RTC_YEAR);
-
-	/* The following flags have to be released exactly in this order,
-	 * otherwise the DS12887 (popular MC146818A clone with integrated
-	 * battery and quartz) will not reset the oscillator and will not
-	 * update precisely 500 ms later. You won't find this mentioned in
-	 * the Dallas Semiconductor data sheets, but who believes data
-	 * sheets anyway ...                           -- Markus Kuhn
-	 */
-	chrp_cmos_clock_write(save_control, RTC_CONTROL);
-	chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
-
-	spin_unlock(&rtc_lock);
-	return 0;
-}
-
-unsigned long chrp_get_rtc_time(void)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	int uip, i;
-
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-
-	/* Since the UIP flag is set for about 2.2 ms and the clock
-	 * is typically written with a precision of 1 jiffy, trying
-	 * to obtain a precision better than a few milliseconds is
-	 * an illusion. Only consistency is interesting, this also
-	 * allows to use the routine for /dev/rtc without a potential
-	 * 1 second kernel busy loop triggered by any reader of /dev/rtc.
-	 */
-
-	for ( i = 0; i<1000000; i++) {
-		uip = chrp_cmos_clock_read(RTC_FREQ_SELECT);
-		sec = chrp_cmos_clock_read(RTC_SECONDS);
-		min = chrp_cmos_clock_read(RTC_MINUTES);
-		hour = chrp_cmos_clock_read(RTC_HOURS);
-		day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH);
-		mon = chrp_cmos_clock_read(RTC_MONTH);
-		year = chrp_cmos_clock_read(RTC_YEAR);
-		uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT);
-		if ((uip & RTC_UIP)==0) break;
-	}
-
-	if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-	  {
-	    BCD_TO_BIN(sec);
-	    BCD_TO_BIN(min);
-	    BCD_TO_BIN(hour);
-	    BCD_TO_BIN(day);
-	    BCD_TO_BIN(mon);
-	    BCD_TO_BIN(year);
-	  }
-	if ((year += 1900) < 1970)
-		year += 100;
-	return mktime(year, mon, day, hour, min, sec);
-}
-
-/*
- * Calibrate the decrementer frequency with the VIA timer 1.
- */
-#define VIA_TIMER_FREQ_6	4700000	/* time 1 frequency * 6 */
-
-/* VIA registers */
-#define RS		0x200		/* skip between registers */
-#define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */
-#define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */
-#define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */
-#define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */
-#define ACR		(11*RS)		/* Auxiliary control register */
-#define IFR		(13*RS)		/* Interrupt flag register */
-
-/* Bits in ACR */
-#define T1MODE		0xc0		/* Timer 1 mode */
-#define T1MODE_CONT	0x40		/*  continuous interrupts */
-
-/* Bits in IFR and IER */
-#define T1_INT		0x40		/* Timer 1 interrupt */
-
-static int __init chrp_via_calibrate_decr(void)
-{
-	struct device_node *vias;
-	volatile unsigned char __iomem *via;
-	int count = VIA_TIMER_FREQ_6 / 100;
-	unsigned int dstart, dend;
-
-	vias = find_devices("via-cuda");
-	if (vias == 0)
-		vias = find_devices("via");
-	if (vias == 0 || vias->n_addrs == 0)
-		return 0;
-	via = ioremap(vias->addrs[0].address, vias->addrs[0].size);
-
-	/* set timer 1 for continuous interrupts */
-	out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
-	/* set the counter to a small value */
-	out_8(&via[T1CH], 2);
-	/* set the latch to `count' */
-	out_8(&via[T1LL], count);
-	out_8(&via[T1LH], count >> 8);
-	/* wait until it hits 0 */
-	while ((in_8(&via[IFR]) & T1_INT) == 0)
-		;
-	dstart = get_dec();
-	/* clear the interrupt & wait until it hits 0 again */
-	in_8(&via[T1CL]);
-	while ((in_8(&via[IFR]) & T1_INT) == 0)
-		;
-	dend = get_dec();
-
-	tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100);
-	tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
-
-	printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
-	       tb_ticks_per_jiffy, dstart - dend);
-
-	iounmap(via);
-	
-	return 1;
-}
-
-void __init chrp_calibrate_decr(void)
-{
-	struct device_node *cpu;
-	unsigned int freq, *fp;
-
-	if (chrp_via_calibrate_decr())
-		return;
-
-	/*
-	 * The cpu node should have a timebase-frequency property
-	 * to tell us the rate at which the decrementer counts.
-	 */
-	freq = 16666000;		/* hardcoded default */
-	cpu = find_type_devices("cpu");
-	if (cpu != 0) {
-		fp = (unsigned int *)
-			get_property(cpu, "timebase-frequency", NULL);
-		if (fp != 0)
-			freq = *fp;
-	}
-	printk("time_init: decrementer frequency = %u.%.6u MHz\n",
- 	       freq/1000000, freq%1000000);
-	tb_ticks_per_jiffy = freq / HZ;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
-}
diff --git a/arch/ppc/platforms/lite5200.c b/arch/ppc/platforms/lite5200.c
index 5171b53..fecbe9a 100644
--- a/arch/ppc/platforms/lite5200.c
+++ b/arch/ppc/platforms/lite5200.c
@@ -34,8 +34,7 @@
 #include <asm/mpc52xx.h>
 #include <asm/ppc_sys.h>
 #include <asm/machdep.h>
-
-#include <syslib/mpc52xx_pci.h>
+#include <asm/pci-bridge.h>
 
 
 extern int powersave_nap;
@@ -68,44 +67,53 @@
 }
 
 #ifdef CONFIG_PCI
+#ifdef CONFIG_LITE5200B
+static int
+lite5200_map_irq(struct pci_dev *dev, unsigned char idsel,
+		    unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	/*
+	 *      PCI IDSEL/INTPIN->INTLINE
+	 *        A             B             C             D
+	 */
+	{
+		{MPC52xx_IRQ0, MPC52xx_IRQ1, MPC52xx_IRQ2, MPC52xx_IRQ3},
+		{MPC52xx_IRQ1, MPC52xx_IRQ2, MPC52xx_IRQ3, MPC52xx_IRQ0},
+	};
+
+	const long min_idsel = 24, max_idsel = 25, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+#else /* Original Lite */
 static int
 lite5200_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
 {
 	return (pin == 1) && (idsel==24) ? MPC52xx_IRQ0 : -1;
 }
 #endif
+#endif
 
 static void __init
 lite5200_setup_cpu(void)
 {
-	struct mpc52xx_cdm  __iomem *cdm;
 	struct mpc52xx_gpio __iomem *gpio;
 	struct mpc52xx_intr __iomem *intr;
-	struct mpc52xx_xlb  __iomem *xlb;
 
 	u32 port_config;
 	u32 intr_ctrl;
 
 	/* Map zones */
-	cdm  = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
 	gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
-	xlb  = ioremap(MPC52xx_PA(MPC52xx_XLB_OFFSET), MPC52xx_XLB_SIZE);
 	intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE);
 
-	if (!cdm || !gpio || !xlb || !intr) {
-		printk("lite5200.c: Error while mapping CDM/GPIO/XLB/INTR during"
-				"lite5200_setup_cpu\n");
+	if (!gpio || !intr) {
+		printk(KERN_ERR __FILE__ ": "
+			"Error while mapping GPIO/INTR during "
+			"lite5200_setup_cpu\n");
 		goto unmap_regs;
 	}
 
-	/* Use internal 48 Mhz */
-	out_8(&cdm->ext_48mhz_en, 0x00);
-	out_8(&cdm->fd_enable, 0x01);
-	if (in_be32(&cdm->rstcfg) & 0x40)	/* Assumes 33Mhz clock */
-		out_be16(&cdm->fd_counters, 0x0001);
-	else
-		out_be16(&cdm->fd_counters, 0x5555);
-
 	/* Get port mux config */
 	port_config = in_be32(&gpio->port_config);
 
@@ -116,29 +124,29 @@
 	port_config &= ~0x00007000;	/* Differential mode - USB1 only */
 	port_config |=  0x00001000;
 
+	/* ATA CS is on csb_4/5 */
+	port_config &= ~0x03000000;
+	port_config |=  0x01000000;
+
 	/* Commit port config */
 	out_be32(&gpio->port_config, port_config);
 
-	/* Configure the XLB Arbiter */
-	out_be32(&xlb->master_pri_enable, 0xff);
-	out_be32(&xlb->master_priority, 0x11111111);
-
-	/* Enable ram snooping for 1GB window */
-	out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_SNOOP);
-	out_be32(&xlb->snoop_window, MPC52xx_PCI_TARGET_MEM | 0x1d);
-
-	/* IRQ[0-3] setup : IRQ0     - Level Active Low  */
-	/*                  IRQ[1-3] - Level Active High */
+	/* IRQ[0-3] setup */
 	intr_ctrl = in_be32(&intr->ctrl);
 	intr_ctrl &= ~0x00ff0000;
-	intr_ctrl |=  0x00c00000;
+#ifdef CONFIG_LITE5200B
+	/* IRQ[0-3] Level Active Low */
+	intr_ctrl |=  0x00ff0000;
+#else
+	/* IRQ0 Level Active Low
+	 * IRQ[1-3] Level Active High */
+ 	intr_ctrl |=  0x00c00000;
+#endif
 	out_be32(&intr->ctrl, intr_ctrl);
 
 	/* Unmap reg zone */
 unmap_regs:
-	if (cdm)  iounmap(cdm);
 	if (gpio) iounmap(gpio);
-	if (xlb)  iounmap(xlb);
 	if (intr) iounmap(intr);
 }
 
@@ -146,7 +154,8 @@
 lite5200_setup_arch(void)
 {
 	/* CPU & Port mux setup */
-	lite5200_setup_cpu();
+	mpc52xx_setup_cpu();	/* Generic */
+	lite5200_setup_cpu();	/* Platform specific */
 
 #ifdef CONFIG_PCI
 	/* PCI Bridge setup */
diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
index a0fc628..e86f615 100644
--- a/arch/ppc/platforms/prep_setup.c
+++ b/arch/ppc/platforms/prep_setup.c
@@ -736,7 +736,7 @@
 		hex = 0xfff;
 		if (!notifier_installed) {
 			++notifier_installed;
-			notifier_chain_register(&panic_notifier_list,
+			atomic_notifier_chain_register(&panic_notifier_list,
 						&ibm_statusled_block);
 		}
 	}
@@ -1067,15 +1067,13 @@
 static int __init
 prep_request_io(void)
 {
-	if (_machine == _MACH_prep) {
 #ifdef CONFIG_NVRAM
-		request_region(PREP_NVRAM_AS0, 0x8, "nvram");
+	request_region(PREP_NVRAM_AS0, 0x8, "nvram");
 #endif
-		request_region(0x00,0x20,"dma1");
-		request_region(0x40,0x20,"timer");
-		request_region(0x80,0x10,"dma page reg");
-		request_region(0xc0,0x20,"dma2");
-	}
+	request_region(0x00,0x20,"dma1");
+	request_region(0x40,0x20,"timer");
+	request_region(0x80,0x10,"dma page reg");
+	request_region(0xc0,0x20,"dma2");
 
 	return 0;
 }
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index 5cb62c6..490749c 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -38,8 +38,6 @@
 obj-$(CONFIG_8xx)		+= m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y) \
 				   ppc_sys.o mpc8xx_devices.o mpc8xx_sys.o
 obj-$(CONFIG_PCI_QSPAN)		+= qspan_pci.o
-obj-$(CONFIG_PPC_OF)		+= prom_init.o prom.o
-obj-$(CONFIG_PPC_CHRP)		+= open_pic.o
 obj-$(CONFIG_PPC_PREP)		+= open_pic.o todc_time.o
 obj-$(CONFIG_BAMBOO)		+= pci_auto.o todc_time.o
 obj-$(CONFIG_CPCI690)		+= todc_time.o pci_auto.o
diff --git a/arch/ppc/syslib/mpc52xx_pci.c b/arch/ppc/syslib/mpc52xx_pci.c
index 9ec525f..5a5a7a9 100644
--- a/arch/ppc/syslib/mpc52xx_pci.c
+++ b/arch/ppc/syslib/mpc52xx_pci.c
@@ -225,7 +225,8 @@
 	/* The PCI Host bridge of MPC52xx has a prefetch memory resource
 	   fixed to 1Gb. Doesn't fit in the resource system so we remove it */
 	if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
-	     (dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200) ) {
+	     (   dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
+	      || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
 		struct resource *res = &dev->resource[1];
 		res->start = res->end = res->flags = 0;
 	}
diff --git a/arch/ppc/syslib/mpc52xx_setup.c b/arch/ppc/syslib/mpc52xx_setup.c
index 2ee48ce..ee6379b 100644
--- a/arch/ppc/syslib/mpc52xx_setup.c
+++ b/arch/ppc/syslib/mpc52xx_setup.c
@@ -24,6 +24,8 @@
 #include <asm/pgtable.h>
 #include <asm/ppcboot.h>
 
+#include <syslib/mpc52xx_pci.h>
+
 extern bd_t __res;
 
 static int core_mult[] = {		/* CPU Frequency multiplier, taken    */
@@ -216,6 +218,52 @@
 	tb_to_us = mulhwu_scale_factor(xlbfreq / divisor, 1000000);
 }
 
+
+void __init
+mpc52xx_setup_cpu(void)
+{
+	struct mpc52xx_cdm  __iomem *cdm;
+	struct mpc52xx_xlb  __iomem *xlb;
+
+	/* Map zones */
+	cdm  = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
+	xlb  = ioremap(MPC52xx_PA(MPC52xx_XLB_OFFSET), MPC52xx_XLB_SIZE);
+
+	if (!cdm || !xlb) {
+		printk(KERN_ERR __FILE__ ": "
+			"Error while mapping CDM/XLB during "
+			"mpc52xx_setup_cpu\n");
+		goto unmap_regs;
+	}
+
+	/* Use internal 48 Mhz */
+	out_8(&cdm->ext_48mhz_en, 0x00);
+	out_8(&cdm->fd_enable, 0x01);
+	if (in_be32(&cdm->rstcfg) & 0x40)	/* Assumes 33Mhz clock */
+		out_be16(&cdm->fd_counters, 0x0001);
+	else
+		out_be16(&cdm->fd_counters, 0x5555);
+
+	/* Configure the XLB Arbiter priorities */
+	out_be32(&xlb->master_pri_enable, 0xff);
+	out_be32(&xlb->master_priority, 0x11111111);
+
+	/* Enable ram snooping for 1GB window */
+	out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_SNOOP);
+	out_be32(&xlb->snoop_window, MPC52xx_PCI_TARGET_MEM | 0x1d);
+
+	/* Disable XLB pipelining */
+	/* (cfr errate 292. We could do this only just before ATA PIO
+	    transaction and re-enable it after ...) */
+	out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS);
+
+	/* Unmap reg zone */
+unmap_regs:
+	if (cdm)  iounmap(cdm);
+	if (xlb)  iounmap(xlb);
+}
+
+
 int mpc52xx_match_psc_function(int psc_idx, const char *func)
 {
 	struct mpc52xx_psc_func *cf = mpc52xx_psc_functions;
diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c
index 38e5b93..70456c8 100644
--- a/arch/ppc/syslib/open_pic.c
+++ b/arch/ppc/syslib/open_pic.c
@@ -216,7 +216,7 @@
 u_int openpic_read_IPI(volatile u_int __iomem * addr)
 {
          u_int val = 0;
-#if defined(OPENPIC_BIG_ENDIAN) || defined(CONFIG_POWER3)
+#if defined(OPENPIC_BIG_ENDIAN)
         val = in_be32(addr);
 #else
         val = in_le32(addr);
diff --git a/arch/ppc/syslib/prom.c b/arch/ppc/syslib/prom.c
deleted file mode 100644
index 482f837..0000000
--- a/arch/ppc/syslib/prom.c
+++ /dev/null
@@ -1,1429 +0,0 @@
-/*
- * Procedures for interfacing to the Open Firmware PROM on
- * Power Macintosh computers.
- *
- * In particular, we are interested in the device tree
- * and in using some of its services (exit, write to stdout).
- *
- * Paul Mackerras	August 1996.
- * Copyright (C) 1996 Paul Mackerras.
- */
-#include <stdarg.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/threads.h>
-#include <linux/spinlock.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/bitops.h>
-
-#include <asm/sections.h>
-#include <asm/prom.h>
-#include <asm/page.h>
-#include <asm/processor.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/bootx.h>
-#include <asm/system.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/bootinfo.h>
-#include <asm/btext.h>
-#include <asm/pci-bridge.h>
-#include <asm/open_pic.h>
-
-
-struct pci_address {
-	unsigned a_hi;
-	unsigned a_mid;
-	unsigned a_lo;
-};
-
-struct pci_reg_property {
-	struct pci_address addr;
-	unsigned size_hi;
-	unsigned size_lo;
-};
-
-struct isa_reg_property {
-	unsigned space;
-	unsigned address;
-	unsigned size;
-};
-
-typedef unsigned long interpret_func(struct device_node *, unsigned long,
-				     int, int);
-static interpret_func interpret_pci_props;
-static interpret_func interpret_dbdma_props;
-static interpret_func interpret_isa_props;
-static interpret_func interpret_macio_props;
-static interpret_func interpret_root_props;
-
-extern char *klimit;
-
-/* Set for a newworld or CHRP machine */
-int use_of_interrupt_tree;
-struct device_node *dflt_interrupt_controller;
-int num_interrupt_controllers;
-
-extern unsigned int rtas_entry;  /* physical pointer */
-
-extern struct device_node *allnodes;
-
-static unsigned long finish_node(struct device_node *, unsigned long,
-				 interpret_func *, int, int);
-static unsigned long finish_node_interrupts(struct device_node *, unsigned long);
-static struct device_node *find_phandle(phandle);
-
-extern void enter_rtas(void *);
-void phys_call_rtas(int, int, int, ...);
-
-extern char cmd_line[512];	/* XXX */
-extern boot_infos_t *boot_infos;
-unsigned long dev_tree_size;
-
-void
-phys_call_rtas(int service, int nargs, int nret, ...)
-{
-	va_list list;
-	union {
-		unsigned long words[16];
-		double align;
-	} u;
-	void (*rtas)(void *, unsigned long);
-	int i;
-
-	u.words[0] = service;
-	u.words[1] = nargs;
-	u.words[2] = nret;
-	va_start(list, nret);
-	for (i = 0; i < nargs; ++i)
-		u.words[i+3] = va_arg(list, unsigned long);
-	va_end(list);
-
-	rtas = (void (*)(void *, unsigned long)) rtas_entry;
-	rtas(&u, rtas_data);
-}
-
-/*
- * finish_device_tree is called once things are running normally
- * (i.e. with text and data mapped to the address they were linked at).
- * It traverses the device tree and fills in the name, type,
- * {n_}addrs and {n_}intrs fields of each node.
- */
-void __init
-finish_device_tree(void)
-{
-	unsigned long mem = (unsigned long) klimit;
-	struct device_node *np;
-
-	/* All CHRPs now use the interrupt tree */
-	for (np = allnodes; np != NULL; np = np->allnext) {
-		if (get_property(np, "interrupt-parent", NULL)) {
-			use_of_interrupt_tree = 1;
-			break;
-		}
-	}
-
-	if (use_of_interrupt_tree) {
-		/*
-		 * We want to find out here how many interrupt-controller
-		 * nodes there are, and if we are booted from BootX,
-		 * we need a pointer to the first (and hopefully only)
-		 * such node.  But we can't use find_devices here since
-		 * np->name has not been set yet.  -- paulus
-		 */
-		int n = 0;
-		char *name, *ic;
-		int iclen;
-
-		for (np = allnodes; np != NULL; np = np->allnext) {
-			ic = get_property(np, "interrupt-controller", &iclen);
-			name = get_property(np, "name", NULL);
-			/* checking iclen makes sure we don't get a false
-			   match on /chosen.interrupt_controller */
-			if ((name != NULL
-			     && strcmp(name, "interrupt-controller") == 0)
-			    || (ic != NULL && iclen == 0 && strcmp(name, "AppleKiwi"))) {
-				if (n == 0)
-					dflt_interrupt_controller = np;
-				++n;
-			}
-		}
-		num_interrupt_controllers = n;
-	}
-
-	mem = finish_node(allnodes, mem, NULL, 1, 1);
-	dev_tree_size = mem - (unsigned long) allnodes;
-	klimit = (char *) mem;
-}
-
-static unsigned long __init
-finish_node(struct device_node *np, unsigned long mem_start,
-	    interpret_func *ifunc, int naddrc, int nsizec)
-{
-	struct device_node *child;
-	int *ip;
-
-	np->name = get_property(np, "name", NULL);
-	np->type = get_property(np, "device_type", NULL);
-
-	if (!np->name)
-		np->name = "<NULL>";
-	if (!np->type)
-		np->type = "<NULL>";
-
-	/* get the device addresses and interrupts */
-	if (ifunc != NULL)
-		mem_start = ifunc(np, mem_start, naddrc, nsizec);
-
-	if (use_of_interrupt_tree)
-		mem_start = finish_node_interrupts(np, mem_start);
-
-	/* Look for #address-cells and #size-cells properties. */
-	ip = (int *) get_property(np, "#address-cells", NULL);
-	if (ip != NULL)
-		naddrc = *ip;
-	ip = (int *) get_property(np, "#size-cells", NULL);
-	if (ip != NULL)
-		nsizec = *ip;
-
-	if (np->parent == NULL)
-		ifunc = interpret_root_props;
-	else if (np->type == 0)
-		ifunc = NULL;
-	else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
-		ifunc = interpret_pci_props;
-	else if (!strcmp(np->type, "dbdma"))
-		ifunc = interpret_dbdma_props;
-	else if (!strcmp(np->type, "mac-io")
-		 || ifunc == interpret_macio_props)
-		ifunc = interpret_macio_props;
-	else if (!strcmp(np->type, "isa"))
-		ifunc = interpret_isa_props;
-	else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3"))
-		ifunc = interpret_root_props;
-	else if (!((ifunc == interpret_dbdma_props
-		    || ifunc == interpret_macio_props)
-		   && (!strcmp(np->type, "escc")
-		       || !strcmp(np->type, "media-bay"))))
-		ifunc = NULL;
-
-	/* if we were booted from BootX, convert the full name */
-	if (boot_infos
-	    && strncmp(np->full_name, "Devices:device-tree", 19) == 0) {
-		if (np->full_name[19] == 0) {
-			strcpy(np->full_name, "/");
-		} else if (np->full_name[19] == ':') {
-			char *p = np->full_name + 19;
-			np->full_name = p;
-			for (; *p; ++p)
-				if (*p == ':')
-					*p = '/';
-		}
-	}
-
-	for (child = np->child; child != NULL; child = child->sibling)
-		mem_start = finish_node(child, mem_start, ifunc,
-					naddrc, nsizec);
-
-	return mem_start;
-}
-
-/*
- * Find the interrupt parent of a node.
- */
-static struct device_node * __init
-intr_parent(struct device_node *p)
-{
-	phandle *parp;
-
-	parp = (phandle *) get_property(p, "interrupt-parent", NULL);
-	if (parp == NULL)
-		return p->parent;
-	p = find_phandle(*parp);
-	if (p != NULL)
-		return p;
-	/*
-	 * On a powermac booted with BootX, we don't get to know the
-	 * phandles for any nodes, so find_phandle will return NULL.
-	 * Fortunately these machines only have one interrupt controller
-	 * so there isn't in fact any ambiguity.  -- paulus
-	 */
-	if (num_interrupt_controllers == 1)
-		p = dflt_interrupt_controller;
-	return p;
-}
-
-/*
- * Find out the size of each entry of the interrupts property
- * for a node.
- */
-static int __init
-prom_n_intr_cells(struct device_node *np)
-{
-	struct device_node *p;
-	unsigned int *icp;
-
-	for (p = np; (p = intr_parent(p)) != NULL; ) {
-		icp = (unsigned int *)
-			get_property(p, "#interrupt-cells", NULL);
-		if (icp != NULL)
-			return *icp;
-		if (get_property(p, "interrupt-controller", NULL) != NULL
-		    || get_property(p, "interrupt-map", NULL) != NULL) {
-			printk("oops, node %s doesn't have #interrupt-cells\n",
-			       p->full_name);
-			return 1;
-		}
-	}
-	printk("prom_n_intr_cells failed for %s\n", np->full_name);
-	return 1;
-}
-
-/*
- * Map an interrupt from a device up to the platform interrupt
- * descriptor.
- */
-static int __init
-map_interrupt(unsigned int **irq, struct device_node **ictrler,
-	      struct device_node *np, unsigned int *ints, int nintrc)
-{
-	struct device_node *p, *ipar;
-	unsigned int *imap, *imask, *ip;
-	int i, imaplen, match;
-	int newintrc = 1, newaddrc = 1;
-	unsigned int *reg;
-	int naddrc;
-
-	reg = (unsigned int *) get_property(np, "reg", NULL);
-	naddrc = prom_n_addr_cells(np);
-	p = intr_parent(np);
-	while (p != NULL) {
-		if (get_property(p, "interrupt-controller", NULL) != NULL)
-			/* this node is an interrupt controller, stop here */
-			break;
-		imap = (unsigned int *)
-			get_property(p, "interrupt-map", &imaplen);
-		if (imap == NULL) {
-			p = intr_parent(p);
-			continue;
-		}
-		imask = (unsigned int *)
-			get_property(p, "interrupt-map-mask", NULL);
-		if (imask == NULL) {
-			printk("oops, %s has interrupt-map but no mask\n",
-			       p->full_name);
-			return 0;
-		}
-		imaplen /= sizeof(unsigned int);
-		match = 0;
-		ipar = NULL;
-		while (imaplen > 0 && !match) {
-			/* check the child-interrupt field */
-			match = 1;
-			for (i = 0; i < naddrc && match; ++i)
-				match = ((reg[i] ^ imap[i]) & imask[i]) == 0;
-			for (; i < naddrc + nintrc && match; ++i)
-				match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0;
-			imap += naddrc + nintrc;
-			imaplen -= naddrc + nintrc;
-			/* grab the interrupt parent */
-			ipar = find_phandle((phandle) *imap++);
-			--imaplen;
-			if (ipar == NULL && num_interrupt_controllers == 1)
-				/* cope with BootX not giving us phandles */
-				ipar = dflt_interrupt_controller;
-			if (ipar == NULL) {
-				printk("oops, no int parent %x in map of %s\n",
-				       imap[-1], p->full_name);
-				return 0;
-			}
-			/* find the parent's # addr and intr cells */
-			ip = (unsigned int *)
-				get_property(ipar, "#interrupt-cells", NULL);
-			if (ip == NULL) {
-				printk("oops, no #interrupt-cells on %s\n",
-				       ipar->full_name);
-				return 0;
-			}
-			newintrc = *ip;
-			ip = (unsigned int *)
-				get_property(ipar, "#address-cells", NULL);
-			newaddrc = (ip == NULL)? 0: *ip;
-			imap += newaddrc + newintrc;
-			imaplen -= newaddrc + newintrc;
-		}
-		if (imaplen < 0) {
-			printk("oops, error decoding int-map on %s, len=%d\n",
-			       p->full_name, imaplen);
-			return 0;
-		}
-		if (!match) {
-			printk("oops, no match in %s int-map for %s\n",
-			       p->full_name, np->full_name);
-			return 0;
-		}
-		p = ipar;
-		naddrc = newaddrc;
-		nintrc = newintrc;
-		ints = imap - nintrc;
-		reg = ints - naddrc;
-	}
-	if (p == NULL)
-		printk("hmmm, int tree for %s doesn't have ctrler\n",
-		       np->full_name);
-	*irq = ints;
-	*ictrler = p;
-	return nintrc;
-}
-
-/*
- * New version of finish_node_interrupts.
- */
-static unsigned long __init
-finish_node_interrupts(struct device_node *np, unsigned long mem_start)
-{
-	unsigned int *ints;
-	int intlen, intrcells;
-	int i, j, n, offset;
-	unsigned int *irq;
-	struct device_node *ic;
-
-	ints = (unsigned int *) get_property(np, "interrupts", &intlen);
-	if (ints == NULL)
-		return mem_start;
-	intrcells = prom_n_intr_cells(np);
-	intlen /= intrcells * sizeof(unsigned int);
-	np->n_intrs = intlen;
-	np->intrs = (struct interrupt_info *) mem_start;
-	mem_start += intlen * sizeof(struct interrupt_info);
-
-	for (i = 0; i < intlen; ++i) {
-		np->intrs[i].line = 0;
-		np->intrs[i].sense = 1;
-		n = map_interrupt(&irq, &ic, np, ints, intrcells);
-		if (n <= 0)
-			continue;
-		offset = 0;
-		/*
-		 * On a CHRP we have an 8259 which is subordinate to
-		 * the openpic in the interrupt tree, but we want the
-		 * openpic's interrupt numbers offsetted, not the 8259's.
-		 * So we apply the offset if the controller is at the
-		 * root of the interrupt tree, i.e. has no interrupt-parent.
-		 * This doesn't cope with the general case of multiple
-		 * cascaded interrupt controllers, but then neither will
-		 * irq.c at the moment either.  -- paulus
-		 * The G5 triggers that code, I add a machine test. On
-		 * those machines, we want to offset interrupts from the
-		 * second openpic by 128 -- BenH
-		 */
-		if (num_interrupt_controllers > 1
-		    && ic != NULL
-		    && get_property(ic, "interrupt-parent", NULL) == NULL)
-			offset = 16;
-
-		np->intrs[i].line = irq[0] + offset;
-		if (n > 1)
-			np->intrs[i].sense = irq[1];
-		if (n > 2) {
-			printk("hmmm, got %d intr cells for %s:", n,
-			       np->full_name);
-			for (j = 0; j < n; ++j)
-				printk(" %d", irq[j]);
-			printk("\n");
-		}
-		ints += intrcells;
-	}
-
-	return mem_start;
-}
-
-/*
- * When BootX makes a copy of the device tree from the MacOS
- * Name Registry, it is in the format we use but all of the pointers
- * are offsets from the start of the tree.
- * This procedure updates the pointers.
- */
-void __init
-relocate_nodes(void)
-{
-	unsigned long base;
-	struct device_node *np;
-	struct property *pp;
-
-#define ADDBASE(x)	(x = (typeof (x))((x)? ((unsigned long)(x) + base): 0))
-
-	base = (unsigned long) boot_infos + boot_infos->deviceTreeOffset;
-	allnodes = (struct device_node *)(base + 4);
-	for (np = allnodes; np != 0; np = np->allnext) {
-		ADDBASE(np->full_name);
-		ADDBASE(np->properties);
-		ADDBASE(np->parent);
-		ADDBASE(np->child);
-		ADDBASE(np->sibling);
-		ADDBASE(np->allnext);
-		for (pp = np->properties; pp != 0; pp = pp->next) {
-			ADDBASE(pp->name);
-			ADDBASE(pp->value);
-			ADDBASE(pp->next);
-		}
-	}
-}
-
-int
-prom_n_addr_cells(struct device_node* np)
-{
-	int* ip;
-	do {
-		if (np->parent)
-			np = np->parent;
-		ip = (int *) 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;
-}
-
-int
-prom_n_size_cells(struct device_node* np)
-{
-	int* ip;
-	do {
-		if (np->parent)
-			np = np->parent;
-		ip = (int *) 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;
-}
-
-static unsigned long __init
-map_addr(struct device_node *np, unsigned long space, unsigned long addr)
-{
-	int na;
-	unsigned int *ranges;
-	int rlen = 0;
-	unsigned int type;
-
-	type = (space >> 24) & 3;
-	if (type == 0)
-		return addr;
-
-	while ((np = np->parent) != NULL) {
-		if (strcmp(np->type, "pci") != 0)
-			continue;
-		/* PCI bridge: map the address through the ranges property */
-		na = prom_n_addr_cells(np);
-		ranges = (unsigned int *) get_property(np, "ranges", &rlen);
-		while ((rlen -= (na + 5) * sizeof(unsigned int)) >= 0) {
-			if (((ranges[0] >> 24) & 3) == type
-			    && ranges[2] <= addr
-			    && addr - ranges[2] < ranges[na+4]) {
-				/* ok, this matches, translate it */
-				addr += ranges[na+2] - ranges[2];
-				break;
-			}
-			ranges += na + 5;
-		}
-	}
-	return addr;
-}
-
-static unsigned long __init
-interpret_pci_props(struct device_node *np, unsigned long mem_start,
-		    int naddrc, int nsizec)
-{
-	struct address_range *adr;
-	struct pci_reg_property *pci_addrs;
-	int i, l, *ip;
-
-	pci_addrs = (struct pci_reg_property *)
-		get_property(np, "assigned-addresses", &l);
-	if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) {
-		i = 0;
-		adr = (struct address_range *) mem_start;
-		while ((l -= sizeof(struct pci_reg_property)) >= 0) {
-			adr[i].space = pci_addrs[i].addr.a_hi;
-			adr[i].address = map_addr(np, pci_addrs[i].addr.a_hi,
-						  pci_addrs[i].addr.a_lo);
-			adr[i].size = pci_addrs[i].size_lo;
-			++i;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
-	}
-
-	if (use_of_interrupt_tree)
-		return mem_start;
-
-	ip = (int *) get_property(np, "AAPL,interrupts", &l);
-	if (ip == 0 && np->parent)
-		ip = (int *) get_property(np->parent, "AAPL,interrupts", &l);
-	if (ip == 0)
-		ip = (int *) get_property(np, "interrupts", &l);
-	if (ip != 0) {
-		np->intrs = (struct interrupt_info *) mem_start;
-		np->n_intrs = l / sizeof(int);
-		mem_start += np->n_intrs * sizeof(struct interrupt_info);
-		for (i = 0; i < np->n_intrs; ++i) {
-			np->intrs[i].line = *ip++;
-			np->intrs[i].sense = 1;
-		}
-	}
-
-	return mem_start;
-}
-
-static unsigned long __init
-interpret_dbdma_props(struct device_node *np, unsigned long mem_start,
-		      int naddrc, int nsizec)
-{
-	struct reg_property *rp;
-	struct address_range *adr;
-	unsigned long base_address;
-	int i, l, *ip;
-	struct device_node *db;
-
-	base_address = 0;
-	for (db = np->parent; db != NULL; db = db->parent) {
-		if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
-			base_address = db->addrs[0].address;
-			break;
-		}
-	}
-
-	rp = (struct reg_property *) get_property(np, "reg", &l);
-	if (rp != 0 && l >= sizeof(struct reg_property)) {
-		i = 0;
-		adr = (struct address_range *) mem_start;
-		while ((l -= sizeof(struct reg_property)) >= 0) {
-			adr[i].space = 2;
-			adr[i].address = rp[i].address + base_address;
-			adr[i].size = rp[i].size;
-			++i;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
-	}
-
-	if (use_of_interrupt_tree)
-		return mem_start;
-
-	ip = (int *) get_property(np, "AAPL,interrupts", &l);
-	if (ip == 0)
-		ip = (int *) get_property(np, "interrupts", &l);
-	if (ip != 0) {
-		np->intrs = (struct interrupt_info *) mem_start;
-		np->n_intrs = l / sizeof(int);
-		mem_start += np->n_intrs * sizeof(struct interrupt_info);
-		for (i = 0; i < np->n_intrs; ++i) {
-			np->intrs[i].line = *ip++;
-			np->intrs[i].sense = 1;
-		}
-	}
-
-	return mem_start;
-}
-
-static unsigned long __init
-interpret_macio_props(struct device_node *np, unsigned long mem_start,
-		      int naddrc, int nsizec)
-{
-	struct reg_property *rp;
-	struct address_range *adr;
-	unsigned long base_address;
-	int i, l, *ip;
-	struct device_node *db;
-
-	base_address = 0;
-	for (db = np->parent; db != NULL; db = db->parent) {
-		if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
-			base_address = db->addrs[0].address;
-			break;
-		}
-	}
-
-	rp = (struct reg_property *) get_property(np, "reg", &l);
-	if (rp != 0 && l >= sizeof(struct reg_property)) {
-		i = 0;
-		adr = (struct address_range *) mem_start;
-		while ((l -= sizeof(struct reg_property)) >= 0) {
-			adr[i].space = 2;
-			adr[i].address = rp[i].address + base_address;
-			adr[i].size = rp[i].size;
-			++i;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
-	}
-
-	if (use_of_interrupt_tree)
-		return mem_start;
-
-	ip = (int *) get_property(np, "interrupts", &l);
-	if (ip == 0)
-		ip = (int *) get_property(np, "AAPL,interrupts", &l);
-	if (ip != 0) {
-		np->intrs = (struct interrupt_info *) mem_start;
-		np->n_intrs = l / sizeof(int);
-		for (i = 0; i < np->n_intrs; ++i) {
-			np->intrs[i].line = *ip++;
-			np->intrs[i].sense = 1;
-		}
-		mem_start += np->n_intrs * sizeof(struct interrupt_info);
-	}
-
-	return mem_start;
-}
-
-static unsigned long __init
-interpret_isa_props(struct device_node *np, unsigned long mem_start,
-		    int naddrc, int nsizec)
-{
-	struct isa_reg_property *rp;
-	struct address_range *adr;
-	int i, l, *ip;
-
-	rp = (struct isa_reg_property *) get_property(np, "reg", &l);
-	if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
-		i = 0;
-		adr = (struct address_range *) mem_start;
-		while ((l -= sizeof(struct reg_property)) >= 0) {
-			adr[i].space = rp[i].space;
-			adr[i].address = rp[i].address
-				+ (adr[i].space? 0: _ISA_MEM_BASE);
-			adr[i].size = rp[i].size;
-			++i;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
-	}
-
-	if (use_of_interrupt_tree)
-		return mem_start;
-
-	ip = (int *) get_property(np, "interrupts", &l);
-	if (ip != 0) {
-		np->intrs = (struct interrupt_info *) mem_start;
-		np->n_intrs = l / (2 * sizeof(int));
-		mem_start += np->n_intrs * sizeof(struct interrupt_info);
-		for (i = 0; i < np->n_intrs; ++i) {
-			np->intrs[i].line = *ip++;
-			np->intrs[i].sense = *ip++;
-		}
-	}
-
-	return mem_start;
-}
-
-static unsigned long __init
-interpret_root_props(struct device_node *np, unsigned long mem_start,
-		     int naddrc, int nsizec)
-{
-	struct address_range *adr;
-	int i, l, *ip;
-	unsigned int *rp;
-	int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
-
-	rp = (unsigned int *) get_property(np, "reg", &l);
-	if (rp != 0 && l >= rpsize) {
-		i = 0;
-		adr = (struct address_range *) mem_start;
-		while ((l -= rpsize) >= 0) {
-			adr[i].space = (naddrc >= 2? rp[naddrc-2]: 2);
-			adr[i].address = rp[naddrc - 1];
-			adr[i].size = rp[naddrc + nsizec - 1];
-			++i;
-			rp += naddrc + nsizec;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
-	}
-
-	if (use_of_interrupt_tree)
-		return mem_start;
-
-	ip = (int *) get_property(np, "AAPL,interrupts", &l);
-	if (ip == 0)
-		ip = (int *) get_property(np, "interrupts", &l);
-	if (ip != 0) {
-		np->intrs = (struct interrupt_info *) mem_start;
-		np->n_intrs = l / sizeof(int);
-		mem_start += np->n_intrs * sizeof(struct interrupt_info);
-		for (i = 0; i < np->n_intrs; ++i) {
-			np->intrs[i].line = *ip++;
-			np->intrs[i].sense = 1;
-		}
-	}
-
-	return mem_start;
-}
-
-/*
- * Work out the sense (active-low level / active-high edge)
- * of each interrupt from the device tree.
- */
-void __init
-prom_get_irq_senses(unsigned char *senses, int off, int max)
-{
-	struct device_node *np;
-	int i, j;
-
-	/* default to level-triggered */
-	memset(senses, 1, max - off);
-	if (!use_of_interrupt_tree)
-		return;
-
-	for (np = allnodes; np != 0; np = np->allnext) {
-		for (j = 0; j < np->n_intrs; j++) {
-			i = np->intrs[j].line;
-			if (i >= off && i < max) {
-				if (np->intrs[j].sense == 1)
-					senses[i-off] = (IRQ_SENSE_LEVEL
-						| IRQ_POLARITY_NEGATIVE);
-				else
-					senses[i-off] = (IRQ_SENSE_EDGE
-						| IRQ_POLARITY_POSITIVE);
-			}
-		}
-	}
-}
-
-/*
- * Construct and return a list of the device_nodes with a given name.
- */
-struct device_node *
-find_devices(const char *name)
-{
-	struct device_node *head, **prevp, *np;
-
-	prevp = &head;
-	for (np = allnodes; np != 0; np = np->allnext) {
-		if (np->name != 0 && strcasecmp(np->name, name) == 0) {
-			*prevp = np;
-			prevp = &np->next;
-		}
-	}
-	*prevp = NULL;
-	return head;
-}
-
-/*
- * Construct and return a list of the device_nodes with a given type.
- */
-struct device_node *
-find_type_devices(const char *type)
-{
-	struct device_node *head, **prevp, *np;
-
-	prevp = &head;
-	for (np = allnodes; np != 0; np = np->allnext) {
-		if (np->type != 0 && strcasecmp(np->type, type) == 0) {
-			*prevp = np;
-			prevp = &np->next;
-		}
-	}
-	*prevp = NULL;
-	return head;
-}
-
-/*
- * Returns all nodes linked together
- */
-struct device_node *
-find_all_nodes(void)
-{
-	struct device_node *head, **prevp, *np;
-
-	prevp = &head;
-	for (np = allnodes; np != 0; np = np->allnext) {
-		*prevp = np;
-		prevp = &np->next;
-	}
-	*prevp = NULL;
-	return head;
-}
-
-/* Checks if the given "compat" string matches one of the strings in
- * the device's "compatible" property
- */
-int
-device_is_compatible(struct device_node *device, const char *compat)
-{
-	const char* cp;
-	int cplen, l;
-
-	cp = (char *) 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;
-}
-
-
-/*
- * Indicates whether the root node has a given value in its
- * compatible property.
- */
-int
-machine_is_compatible(const char *compat)
-{
-	struct device_node *root;
-
-	root = find_path_device("/");
-	if (root == 0)
-		return 0;
-	return device_is_compatible(root, compat);
-}
-
-/*
- * Construct and return a list of the device_nodes with a given type
- * and compatible property.
- */
-struct device_node *
-find_compatible_devices(const char *type, const char *compat)
-{
-	struct device_node *head, **prevp, *np;
-
-	prevp = &head;
-	for (np = allnodes; np != 0; np = np->allnext) {
-		if (type != NULL
-		    && !(np->type != 0 && strcasecmp(np->type, type) == 0))
-			continue;
-		if (device_is_compatible(np, compat)) {
-			*prevp = np;
-			prevp = &np->next;
-		}
-	}
-	*prevp = NULL;
-	return head;
-}
-
-/*
- * Find the device_node with a given full_name.
- */
-struct device_node *
-find_path_device(const char *path)
-{
-	struct device_node *np;
-
-	for (np = allnodes; np != 0; np = np->allnext)
-		if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
-			return np;
-	return NULL;
-}
-
-/*******
- *
- * New implementation of the OF "find" APIs, return a refcounted
- * object, call of_node_put() when done. Currently, still lacks
- * locking as old implementation, this is beeing done for ppc64.
- *
- * Note that property management will need some locking as well,
- * this isn't dealt with yet
- *
- *******/
-
-/**
- *	of_find_node_by_name - Find a node by it's "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 = from ? from->allnext : allnodes;
-
-	for (; np != 0; np = np->allnext)
-		if (np->name != 0 && strcasecmp(np->name, name) == 0)
-			break;
-	if (from)
-		of_node_put(from);
-	return of_node_get(np);
-}
-
-/**
- *	of_find_node_by_type - Find a node by it's "device_type" 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 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 = from ? from->allnext : allnodes;
-
-	for (; np != 0; np = np->allnext)
-		if (np->type != 0 && strcasecmp(np->type, type) == 0)
-			break;
-	if (from)
-		of_node_put(from);
-	return of_node_get(np);
-}
-
-/**
- *	of_find_compatible_node - Find a node based on type and one of the
- *                                tokens in it's "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 = from ? from->allnext : allnodes;
-
-	for (; np != 0; np = np->allnext) {
-		if (type != NULL
-		    && !(np->type != 0 && strcasecmp(np->type, type) == 0))
-			continue;
-		if (device_is_compatible(np, compatible))
-			break;
-	}
-	if (from)
-		of_node_put(from);
-	return of_node_get(np);
-}
-
-/**
- *	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;
-
-	for (; np != 0; np = np->allnext)
-		if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
-			break;
-	return of_node_get(np);
-}
-
-/**
- *	of_find_all_nodes - Get next node in global list
- *	@prev:	Previous node or NULL to start iteration
- *		of_node_put() will be called on it
- *
- *	Returns a node pointer with refcount incremented, use
- *	of_node_put() on it when done.
- */
-struct device_node *of_find_all_nodes(struct device_node *prev)
-{
-	return of_node_get(prev ? prev->allnext : allnodes);
-}
-
-/**
- *	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)
-{
-	return node ? of_node_get(node->parent) : NULL;
-}
-
-/**
- *	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 = prev ? prev->sibling : node->child;
-
-	for (; next != 0; next = next->sibling)
-		if (of_node_get(next))
-			break;
-	if (prev)
-		of_node_put(prev);
-	return next;
-}
-
-/**
- *	of_node_get - Increment refcount of a node
- *	@node:	Node to inc refcount, NULL is supported to
- *		simplify writing of callers
- *
- *	Returns the node itself or NULL if gone. Current implementation
- *	does nothing as we don't yet do dynamic node allocation on ppc32
- */
-struct device_node *of_node_get(struct device_node *node)
-{
-	return node;
-}
-
-/**
- *	of_node_put - Decrement refcount of a node
- *	@node:	Node to dec refcount, NULL is supported to
- *		simplify writing of callers
- *
- *	Current implementation does nothing as we don't yet do dynamic node
- *	allocation on ppc32
- */
-void  of_node_put(struct device_node *node)
-{
-}
-
-/*
- * Find the device_node with a given phandle.
- */
-static struct device_node * __init
-find_phandle(phandle ph)
-{
-	struct device_node *np;
-
-	for (np = allnodes; np != 0; np = np->allnext)
-		if (np->node == ph)
-			return np;
-	return NULL;
-}
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-unsigned char *
-get_property(struct device_node *np, const char *name, int *lenp)
-{
-	struct property *pp;
-
-	for (pp = np->properties; pp != 0; pp = pp->next)
-		if (pp->name != NULL && strcmp(pp->name, name) == 0) {
-			if (lenp != 0)
-				*lenp = pp->length;
-			return pp->value;
-		}
-	return NULL;
-}
-
-/*
- * Add a property to a node
- */
-int
-prom_add_property(struct device_node* np, struct property* prop)
-{
-	struct property **next = &np->properties;
-
-	prop->next = NULL;
-	while (*next)
-		next = &(*next)->next;
-	*next = prop;
-
-	return 0;
-}
-
-/* I quickly hacked that one, check against spec ! */
-static inline unsigned long
-bus_space_to_resource_flags(unsigned int bus_space)
-{
-	u8 space = (bus_space >> 24) & 0xf;
-	if (space == 0)
-		space = 0x02;
-	if (space == 0x02)
-		return IORESOURCE_MEM;
-	else if (space == 0x01)
-		return IORESOURCE_IO;
-	else {
-		printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n",
-		    	bus_space);
-		return 0;
-	}
-}
-
-static struct resource*
-find_parent_pci_resource(struct pci_dev* pdev, struct address_range *range)
-{
-	unsigned long mask;
-	int i;
-
-	/* Check this one */
-	mask = bus_space_to_resource_flags(range->space);
-	for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
-		if ((pdev->resource[i].flags & mask) == mask &&
-			pdev->resource[i].start <= range->address &&
-			pdev->resource[i].end > range->address) {
-				if ((range->address + range->size - 1) > pdev->resource[i].end) {
-					/* Add better message */
-					printk(KERN_WARNING "PCI/OF resource overlap !\n");
-					return NULL;
-				}
-				break;
-			}
-	}
-	if (i == DEVICE_COUNT_RESOURCE)
-		return NULL;
-	return &pdev->resource[i];
-}
-
-/*
- * Request an OF device resource. Currently handles child of PCI devices,
- * or other nodes attached to the root node. Ultimately, put some
- * link to resources in the OF node.
- */
-struct resource*
-request_OF_resource(struct device_node* node, int index, const char* name_postfix)
-{
-	struct pci_dev* pcidev;
-	u8 pci_bus, pci_devfn;
-	unsigned long iomask;
-	struct device_node* nd;
-	struct resource* parent;
-	struct resource *res = NULL;
-	int nlen, plen;
-
-	if (index >= node->n_addrs)
-		goto fail;
-
-	/* Sanity check on bus space */
-	iomask = bus_space_to_resource_flags(node->addrs[index].space);
-	if (iomask & IORESOURCE_MEM)
-		parent = &iomem_resource;
-	else if (iomask & IORESOURCE_IO)
-		parent = &ioport_resource;
-	else
-		goto fail;
-
-	/* Find a PCI parent if any */
-	nd = node;
-	pcidev = NULL;
-	while(nd) {
-		if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
-			pcidev = pci_find_slot(pci_bus, pci_devfn);
-		if (pcidev) break;
-		nd = nd->parent;
-	}
-	if (pcidev)
-		parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
-	if (!parent) {
-		printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
-			node->name);
-		goto fail;
-	}
-
-	res = __request_region(parent, node->addrs[index].address, node->addrs[index].size, NULL);
-	if (!res)
-		goto fail;
-	nlen = strlen(node->name);
-	plen = name_postfix ? strlen(name_postfix) : 0;
-	res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL);
-	if (res->name) {
-		strcpy((char *)res->name, node->name);
-		if (plen)
-			strcpy((char *)res->name+nlen, name_postfix);
-	}
-	return res;
-fail:
-	return NULL;
-}
-
-int
-release_OF_resource(struct device_node* node, int index)
-{
-	struct pci_dev* pcidev;
-	u8 pci_bus, pci_devfn;
-	unsigned long iomask, start, end;
-	struct device_node* nd;
-	struct resource* parent;
-	struct resource *res = NULL;
-
-	if (index >= node->n_addrs)
-		return -EINVAL;
-
-	/* Sanity check on bus space */
-	iomask = bus_space_to_resource_flags(node->addrs[index].space);
-	if (iomask & IORESOURCE_MEM)
-		parent = &iomem_resource;
-	else if (iomask & IORESOURCE_IO)
-		parent = &ioport_resource;
-	else
-		return -EINVAL;
-
-	/* Find a PCI parent if any */
-	nd = node;
-	pcidev = NULL;
-	while(nd) {
-		if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
-			pcidev = pci_find_slot(pci_bus, pci_devfn);
-		if (pcidev) break;
-		nd = nd->parent;
-	}
-	if (pcidev)
-		parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
-	if (!parent) {
-		printk(KERN_WARNING "release_OF_resource(%s), parent not found\n",
-			node->name);
-		return -ENODEV;
-	}
-
-	/* Find us in the parent and its childs */
-	res = parent->child;
-	start = node->addrs[index].address;
-	end = start + node->addrs[index].size - 1;
-	while (res) {
-		if (res->start == start && res->end == end &&
-		    (res->flags & IORESOURCE_BUSY))
-		    	break;
-		if (res->start <= start && res->end >= end)
-			res = res->child;
-		else
-			res = res->sibling;
-	}
-	if (!res)
-		return -ENODEV;
-
-	kfree(res->name);
-	res->name = NULL;
-	release_resource(res);
-	kfree(res);
-
-	return 0;
-}
-
-#if 0
-void
-print_properties(struct device_node *np)
-{
-	struct property *pp;
-	char *cp;
-	int i, n;
-
-	for (pp = np->properties; pp != 0; pp = pp->next) {
-		printk(KERN_INFO "%s", pp->name);
-		for (i = strlen(pp->name); i < 16; ++i)
-			printk(" ");
-		cp = (char *) pp->value;
-		for (i = pp->length; i > 0; --i, ++cp)
-			if ((i > 1 && (*cp < 0x20 || *cp > 0x7e))
-			    || (i == 1 && *cp != 0))
-				break;
-		if (i == 0 && pp->length > 1) {
-			/* looks like a string */
-			printk(" %s\n", (char *) pp->value);
-		} else {
-			/* dump it in hex */
-			n = pp->length;
-			if (n > 64)
-				n = 64;
-			if (pp->length % 4 == 0) {
-				unsigned int *p = (unsigned int *) pp->value;
-
-				n /= 4;
-				for (i = 0; i < n; ++i) {
-					if (i != 0 && (i % 4) == 0)
-						printk("\n                ");
-					printk(" %08x", *p++);
-				}
-			} else {
-				unsigned char *bp = pp->value;
-
-				for (i = 0; i < n; ++i) {
-					if (i != 0 && (i % 16) == 0)
-						printk("\n                ");
-					printk(" %02x", *bp++);
-				}
-			}
-			printk("\n");
-			if (pp->length > 64)
-				printk("                 ... (length = %d)\n",
-				       pp->length);
-		}
-	}
-}
-#endif
-
-static DEFINE_SPINLOCK(rtas_lock);
-
-/* this can be called after setup -- Cort */
-int
-call_rtas(const char *service, int nargs, int nret,
-	  unsigned long *outputs, ...)
-{
-	va_list list;
-	int i;
-	unsigned long s;
-	struct device_node *rtas;
-	int *tokp;
-	union {
-		unsigned long words[16];
-		double align;
-	} u;
-
-	rtas = find_devices("rtas");
-	if (rtas == NULL)
-		return -1;
-	tokp = (int *) get_property(rtas, service, NULL);
-	if (tokp == NULL) {
-		printk(KERN_ERR "No RTAS service called %s\n", service);
-		return -1;
-	}
-	u.words[0] = *tokp;
-	u.words[1] = nargs;
-	u.words[2] = nret;
-	va_start(list, outputs);
-	for (i = 0; i < nargs; ++i)
-		u.words[i+3] = va_arg(list, unsigned long);
-	va_end(list);
-
-	/*
-	 * RTAS doesn't use floating point.
-	 * Or at least, according to the CHRP spec we enter RTAS
-	 * with FP disabled, and it doesn't change the FP registers.
-	 *  -- paulus.
-	 */
-	spin_lock_irqsave(&rtas_lock, s);
-	enter_rtas((void *)__pa(&u));
-	spin_unlock_irqrestore(&rtas_lock, s);
-
-	if (nret > 1 && outputs != NULL)
-		for (i = 0; i < nret-1; ++i)
-			outputs[i] = u.words[i+nargs+4];
-	return u.words[nargs+3];
-}
diff --git a/arch/ppc/syslib/prom_init.c b/arch/ppc/syslib/prom_init.c
deleted file mode 100644
index df14422..0000000
--- a/arch/ppc/syslib/prom_init.c
+++ /dev/null
@@ -1,1011 +0,0 @@
-/*
- * Note that prom_init() and anything called from prom_init()
- * may be running at an address that is different from the address
- * that it was linked at.  References to static data items are
- * handled by compiling this file with -mrelocatable-lib.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/threads.h>
-#include <linux/spinlock.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/bitops.h>
-
-#include <asm/sections.h>
-#include <asm/prom.h>
-#include <asm/page.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/bootx.h>
-#include <asm/system.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/bootinfo.h>
-#include <asm/btext.h>
-#include <asm/pci-bridge.h>
-#include <asm/open_pic.h>
-#include <asm/cacheflush.h>
-
-#ifdef CONFIG_LOGO_LINUX_CLUT224
-#include <linux/linux_logo.h>
-extern const struct linux_logo logo_linux_clut224;
-#endif
-
-/*
- * Properties whose value is longer than this get excluded from our
- * copy of the device tree.  This way we don't waste space storing
- * things like "driver,AAPL,MacOS,PowerPC" properties.  But this value
- * does need to be big enough to ensure that we don't lose things
- * like the interrupt-map property on a PCI-PCI bridge.
- */
-#define MAX_PROPERTY_LENGTH	4096
-
-#ifndef FB_MAX			/* avoid pulling in all of the fb stuff */
-#define FB_MAX	8
-#endif
-
-#define ALIGNUL(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
-
-typedef u32 prom_arg_t;
-
-struct prom_args {
-	const char *service;
-	int nargs;
-	int nret;
-	prom_arg_t args[10];
-};
-
-struct pci_address {
-	unsigned a_hi;
-	unsigned a_mid;
-	unsigned a_lo;
-};
-
-struct pci_reg_property {
-	struct pci_address addr;
-	unsigned size_hi;
-	unsigned size_lo;
-};
-
-struct pci_range {
-	struct pci_address addr;
-	unsigned phys;
-	unsigned size_hi;
-	unsigned size_lo;
-};
-
-struct isa_reg_property {
-	unsigned space;
-	unsigned address;
-	unsigned size;
-};
-
-struct pci_intr_map {
-	struct pci_address addr;
-	unsigned dunno;
-	phandle int_ctrler;
-	unsigned intr;
-};
-
-static void prom_exit(void);
-static int  call_prom(const char *service, int nargs, int nret, ...);
-static int  call_prom_ret(const char *service, int nargs, int nret,
-			  prom_arg_t *rets, ...);
-static void prom_print_hex(unsigned int v);
-static int  prom_set_color(ihandle ih, int i, int r, int g, int b);
-static int  prom_next_node(phandle *nodep);
-static unsigned long check_display(unsigned long mem);
-static void setup_disp_fake_bi(ihandle dp);
-static unsigned long copy_device_tree(unsigned long mem_start,
-				unsigned long mem_end);
-static unsigned long inspect_node(phandle node, struct device_node *dad,
-				unsigned long mem_start, unsigned long mem_end,
-				struct device_node ***allnextpp);
-static void prom_hold_cpus(unsigned long mem);
-static void prom_instantiate_rtas(void);
-static void * early_get_property(unsigned long base, unsigned long node,
-				char *prop);
-
-prom_entry prom __initdata;
-ihandle prom_chosen __initdata;
-ihandle prom_stdout __initdata;
-
-static char *prom_display_paths[FB_MAX] __initdata;
-static phandle prom_display_nodes[FB_MAX] __initdata;
-static unsigned int prom_num_displays __initdata;
-static ihandle prom_disp_node __initdata;
-char *of_stdout_device __initdata;
-
-unsigned int rtas_data;   /* physical pointer */
-unsigned int rtas_entry;  /* physical pointer */
-unsigned int rtas_size;
-unsigned int old_rtas;
-
-boot_infos_t *boot_infos;
-char *bootpath;
-char *bootdevice;
-struct device_node *allnodes;
-
-extern char *klimit;
-
-static void __init
-prom_exit(void)
-{
-	struct prom_args args;
-
-	args.service = "exit";
-	args.nargs = 0;
-	args.nret = 0;
-	prom(&args);
-	for (;;)			/* should never get here */
-		;
-}
-
-static int __init
-call_prom(const char *service, int nargs, int nret, ...)
-{
-	va_list list;
-	int i;
-	struct prom_args prom_args;
-
-	prom_args.service = service;
-	prom_args.nargs = nargs;
-	prom_args.nret = nret;
-	va_start(list, nret);
-	for (i = 0; i < nargs; ++i)
-		prom_args.args[i] = va_arg(list, prom_arg_t);
-	va_end(list);
-	for (i = 0; i < nret; ++i)
-		prom_args.args[i + nargs] = 0;
-	prom(&prom_args);
-	return prom_args.args[nargs];
-}
-
-static int __init
-call_prom_ret(const char *service, int nargs, int nret, prom_arg_t *rets, ...)
-{
-	va_list list;
-	int i;
-	struct prom_args prom_args;
-
-	prom_args.service = service;
-	prom_args.nargs = nargs;
-	prom_args.nret = nret;
-	va_start(list, rets);
-	for (i = 0; i < nargs; ++i)
-		prom_args.args[i] = va_arg(list, int);
-	va_end(list);
-	for (i = 0; i < nret; ++i)
-		prom_args.args[i + nargs] = 0;
-	prom(&prom_args);
-	for (i = 1; i < nret; ++i)
-		rets[i-1] = prom_args.args[nargs + i];
-	return prom_args.args[nargs];
-}
-
-void __init
-prom_print(const char *msg)
-{
-	const char *p, *q;
-
-	if (prom_stdout == 0)
-		return;
-
-	for (p = msg; *p != 0; p = q) {
-		for (q = p; *q != 0 && *q != '\n'; ++q)
-			;
-		if (q > p)
-			call_prom("write", 3, 1, prom_stdout, p, q - p);
-		if (*q != 0) {
-			++q;
-			call_prom("write", 3, 1, prom_stdout, "\r\n", 2);
-		}
-	}
-}
-
-static void __init
-prom_print_hex(unsigned int v)
-{
-	char buf[16];
-	int i, c;
-
-	for (i = 0; i < 8; ++i) {
-		c = (v >> ((7-i)*4)) & 0xf;
-		c += (c >= 10)? ('a' - 10): '0';
-		buf[i] = c;
-	}
-	buf[i] = ' ';
-	buf[i+1] = 0;
-	prom_print(buf);
-}
-
-static int __init
-prom_set_color(ihandle ih, int i, int r, int g, int b)
-{
-	return call_prom("call-method", 6, 1, "color!", ih, i, b, g, r);
-}
-
-static int __init
-prom_next_node(phandle *nodep)
-{
-	phandle node;
-
-	if ((node = *nodep) != 0
-	    && (*nodep = call_prom("child", 1, 1, node)) != 0)
-		return 1;
-	if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
-		return 1;
-	for (;;) {
-		if ((node = call_prom("parent", 1, 1, node)) == 0)
-			return 0;
-		if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
-			return 1;
-	}
-}
-
-#ifdef CONFIG_POWER4
-/*
- * Set up a hash table with a set of entries in it to map the
- * first 64MB of RAM.  This is used on 64-bit machines since
- * some of them don't have BATs.
- */
-
-static inline void make_pte(unsigned long htab, unsigned int hsize,
-			    unsigned int va, unsigned int pa, int mode)
-{
-	unsigned int *pteg;
-	unsigned int hash, i, vsid;
-
-	vsid = ((va >> 28) * 0x111) << 12;
-	hash = ((va ^ vsid) >> 5) & 0x7fff80;
-	pteg = (unsigned int *)(htab + (hash & (hsize - 1)));
-	for (i = 0; i < 8; ++i, pteg += 4) {
-		if ((pteg[1] & 1) == 0) {
-			pteg[1] = vsid | ((va >> 16) & 0xf80) | 1;
-			pteg[3] = pa | mode;
-			break;
-		}
-	}
-}
-
-extern unsigned long _SDR1;
-extern PTE *Hash;
-extern unsigned long Hash_size;
-
-static void __init
-prom_alloc_htab(void)
-{
-	unsigned int hsize;
-	unsigned long htab;
-	unsigned int addr;
-
-	/*
-	 * Because of OF bugs we can't use the "claim" client
-	 * interface to allocate memory for the hash table.
-	 * This code is only used on 64-bit PPCs, and the only
-	 * 64-bit PPCs at the moment are RS/6000s, and their
-	 * OF is based at 0xc00000 (the 12M point), so we just
-	 * arbitrarily use the 0x800000 - 0xc00000 region for the
-	 * hash table.
-	 *  -- paulus.
-	 */
-	hsize = 4 << 20;	/* POWER4 has no BATs */
-	htab = (8 << 20);
-	call_prom("claim", 3, 1, htab, hsize, 0);
-	Hash = (void *)(htab + KERNELBASE);
-	Hash_size = hsize;
-	_SDR1 = htab + __ilog2(hsize) - 18;
-
-	/*
-	 * Put in PTEs for the first 64MB of RAM
-	 */
-	memset((void *)htab, 0, hsize);
-	for (addr = 0; addr < 0x4000000; addr += 0x1000)
-		make_pte(htab, hsize, addr + KERNELBASE, addr,
-			 _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX);
-#if 0 /* DEBUG stuff mapping the SCC */
-	make_pte(htab, hsize, 0x80013000, 0x80013000,
-		 _PAGE_ACCESSED | _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX);
-#endif
-}
-#endif /* CONFIG_POWER4 */
-
-
-/*
- * If we have a display that we don't know how to drive,
- * we will want to try to execute OF's open method for it
- * later.  However, OF will probably fall over if we do that
- * we've taken over the MMU.
- * So we check whether we will need to open the display,
- * and if so, open it now.
- */
-static unsigned long __init
-check_display(unsigned long mem)
-{
-	phandle node;
-	ihandle ih;
-	int i, j;
-	char type[16], *path;
-	static unsigned char default_colors[] = {
-		0x00, 0x00, 0x00,
-		0x00, 0x00, 0xaa,
-		0x00, 0xaa, 0x00,
-		0x00, 0xaa, 0xaa,
-		0xaa, 0x00, 0x00,
-		0xaa, 0x00, 0xaa,
-		0xaa, 0xaa, 0x00,
-		0xaa, 0xaa, 0xaa,
-		0x55, 0x55, 0x55,
-		0x55, 0x55, 0xff,
-		0x55, 0xff, 0x55,
-		0x55, 0xff, 0xff,
-		0xff, 0x55, 0x55,
-		0xff, 0x55, 0xff,
-		0xff, 0xff, 0x55,
-		0xff, 0xff, 0xff
-	};
-	const unsigned char *clut;
-
-	prom_disp_node = 0;
-
-	for (node = 0; prom_next_node(&node); ) {
-		type[0] = 0;
-		call_prom("getprop", 4, 1, node, "device_type",
-			  type, sizeof(type));
-		if (strcmp(type, "display") != 0)
-			continue;
-		/* It seems OF doesn't null-terminate the path :-( */
-		path = (char *) mem;
-		memset(path, 0, 256);
-		if (call_prom("package-to-path", 3, 1, node, path, 255) < 0)
-			continue;
-
-		/*
-		 * If this display is the device that OF is using for stdout,
-		 * move it to the front of the list.
-		 */
-		mem += strlen(path) + 1;
-		i = prom_num_displays++;
-		if (of_stdout_device != 0 && i > 0
-		    && strcmp(of_stdout_device, path) == 0) {
-			for (; i > 0; --i) {
-				prom_display_paths[i]
-					= prom_display_paths[i-1];
-				prom_display_nodes[i]
-					= prom_display_nodes[i-1];
-			}
-		}
-		prom_display_paths[i] = path;
-		prom_display_nodes[i] = node;
-		if (i == 0)
-			prom_disp_node = node;
-		if (prom_num_displays >= FB_MAX)
-			break;
-	}
-
-	for (j=0; j<prom_num_displays; j++) {
-		path = prom_display_paths[j];
-		node = prom_display_nodes[j];
-		prom_print("opening display ");
-		prom_print(path);
-		ih = call_prom("open", 1, 1, path);
-		if (ih == 0 || ih == (ihandle) -1) {
-			prom_print("... failed\n");
-			for (i=j+1; i<prom_num_displays; i++) {
-				prom_display_paths[i-1] = prom_display_paths[i];
-				prom_display_nodes[i-1] = prom_display_nodes[i];
-			}
-			if (--prom_num_displays > 0) {
-				prom_disp_node = prom_display_nodes[j];
-				j--;
-			} else
-				prom_disp_node = 0;
-			continue;
-		} else {
-			prom_print("... ok\n");
-			call_prom("setprop", 4, 1, node, "linux,opened", 0, 0);
-
-			/*
-			 * Setup a usable color table when the appropriate
-			 * method is available.
-			 * Should update this to use set-colors.
-			 */
-			clut = default_colors;
-			for (i = 0; i < 32; i++, clut += 3)
-				if (prom_set_color(ih, i, clut[0], clut[1],
-						   clut[2]) != 0)
-					break;
-
-#ifdef CONFIG_LOGO_LINUX_CLUT224
-			clut = PTRRELOC(logo_linux_clut224.clut);
-			for (i = 0; i < logo_linux_clut224.clutsize;
-			     i++, clut += 3)
-				if (prom_set_color(ih, i + 32, clut[0],
-						   clut[1], clut[2]) != 0)
-					break;
-#endif /* CONFIG_LOGO_LINUX_CLUT224 */
-		}
-	}
-	
-	if (prom_stdout) {
-		phandle p;
-		p = call_prom("instance-to-package", 1, 1, prom_stdout);
-		if (p && p != -1) {
-			type[0] = 0;
-			call_prom("getprop", 4, 1, p, "device_type",
-				  type, sizeof(type));
-			if (strcmp(type, "display") == 0)
-				call_prom("setprop", 4, 1, p, "linux,boot-display",
-					  0, 0);
-		}
-	}
-
-	return ALIGNUL(mem);
-}
-
-/* This function will enable the early boot text when doing OF booting. This
- * way, xmon output should work too
- */
-static void __init
-setup_disp_fake_bi(ihandle dp)
-{
-#ifdef CONFIG_BOOTX_TEXT
-	int width = 640, height = 480, depth = 8, pitch;
-	unsigned address;
-	struct pci_reg_property addrs[8];
-	int i, naddrs;
-	char name[32];
-	char *getprop = "getprop";
-
-	prom_print("Initializing fake screen: ");
-
-	memset(name, 0, sizeof(name));
-	call_prom(getprop, 4, 1, dp, "name", name, sizeof(name));
-	name[sizeof(name)-1] = 0;
-	prom_print(name);
-	prom_print("\n");
-	call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width));
-	call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height));
-	call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth));
-	pitch = width * ((depth + 7) / 8);
-	call_prom(getprop, 4, 1, dp, "linebytes",
-		  &pitch, sizeof(pitch));
-	if (pitch == 1)
-		pitch = 0x1000;		/* for strange IBM display */
-	address = 0;
-	call_prom(getprop, 4, 1, dp, "address",
-		  &address, sizeof(address));
-	if (address == 0) {
-		/* look for an assigned address with a size of >= 1MB */
-		naddrs = call_prom(getprop, 4, 1, dp, "assigned-addresses",
-				   addrs, sizeof(addrs));
-		naddrs /= sizeof(struct pci_reg_property);
-		for (i = 0; i < naddrs; ++i) {
-			if (addrs[i].size_lo >= (1 << 20)) {
-				address = addrs[i].addr.a_lo;
-				/* use the BE aperture if possible */
-				if (addrs[i].size_lo >= (16 << 20))
-					address += (8 << 20);
-				break;
-			}
-		}
-		if (address == 0) {
-			prom_print("Failed to get address\n");
-			return;
-		}
-	}
-	/* kludge for valkyrie */
-	if (strcmp(name, "valkyrie") == 0)
-		address += 0x1000;
-
-#ifdef CONFIG_POWER4
-#if CONFIG_TASK_SIZE > 0x80000000
-#error CONFIG_TASK_SIZE cannot be above 0x80000000 with BOOTX_TEXT on G5
-#endif
-	{
-		extern boot_infos_t disp_bi;
-		unsigned long va, pa, i, offset;
-       		va = 0x90000000;
-		pa = address & 0xfffff000ul;
-		offset = address & 0x00000fff;
-
-		for (i=0; i<0x4000; i++) {  
-			make_pte((unsigned long)Hash - KERNELBASE, Hash_size, va, pa, 
-				 _PAGE_ACCESSED | _PAGE_NO_CACHE |
-				 _PAGE_GUARDED | PP_RWXX);
-			va += 0x1000;
-			pa += 0x1000;
-		}
-		btext_setup_display(width, height, depth, pitch, 0x90000000 | offset);
-		disp_bi.dispDeviceBase = (u8 *)address;
-	}
-#else /* CONFIG_POWER4 */
-	btext_setup_display(width, height, depth, pitch, address);
-	btext_prepare_BAT();
-#endif /* CONFIG_POWER4 */
-#endif /* CONFIG_BOOTX_TEXT */
-}
-
-/*
- * Make a copy of the device tree from the PROM.
- */
-static unsigned long __init
-copy_device_tree(unsigned long mem_start, unsigned long mem_end)
-{
-	phandle root;
-	unsigned long new_start;
-	struct device_node **allnextp;
-
-	root = call_prom("peer", 1, 1, (phandle)0);
-	if (root == (phandle)0) {
-		prom_print("couldn't get device tree root\n");
-		prom_exit();
-	}
-	allnextp = &allnodes;
-	mem_start = ALIGNUL(mem_start);
-	new_start = inspect_node(root, NULL, mem_start, mem_end, &allnextp);
-	*allnextp = NULL;
-	return new_start;
-}
-
-static unsigned long __init
-inspect_node(phandle node, struct device_node *dad,
-	     unsigned long mem_start, unsigned long mem_end,
-	     struct device_node ***allnextpp)
-{
-	int l;
-	phandle child;
-	struct device_node *np;
-	struct property *pp, **prev_propp;
-	char *prev_name, *namep;
-	unsigned char *valp;
-
-	np = (struct device_node *) mem_start;
-	mem_start += sizeof(struct device_node);
-	memset(np, 0, sizeof(*np));
-	np->node = node;
-	**allnextpp = PTRUNRELOC(np);
-	*allnextpp = &np->allnext;
-	if (dad != 0) {
-		np->parent = PTRUNRELOC(dad);
-		/* we temporarily use the `next' field as `last_child'. */
-		if (dad->next == 0)
-			dad->child = PTRUNRELOC(np);
-		else
-			dad->next->sibling = PTRUNRELOC(np);
-		dad->next = np;
-	}
-
-	/* get and store all properties */
-	prev_propp = &np->properties;
-	prev_name = "";
-	for (;;) {
-		pp = (struct property *) mem_start;
-		namep = (char *) (pp + 1);
-		pp->name = PTRUNRELOC(namep);
-		if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0)
-			break;
-		mem_start = ALIGNUL((unsigned long)namep + strlen(namep) + 1);
-		prev_name = namep;
-		valp = (unsigned char *) mem_start;
-		pp->value = PTRUNRELOC(valp);
-		pp->length = call_prom("getprop", 4, 1, node, namep,
-				       valp, mem_end - mem_start);
-		if (pp->length < 0)
-			continue;
-#ifdef MAX_PROPERTY_LENGTH
-		if (pp->length > MAX_PROPERTY_LENGTH)
-			continue; /* ignore this property */
-#endif
-		mem_start = ALIGNUL(mem_start + pp->length);
-		*prev_propp = PTRUNRELOC(pp);
-		prev_propp = &pp->next;
-	}
-	if (np->node != 0) {
-		/* Add a "linux,phandle" property" */
-		pp = (struct property *) mem_start;
-		*prev_propp = PTRUNRELOC(pp);
-		prev_propp = &pp->next;
-		namep = (char *) (pp + 1);
-		pp->name = PTRUNRELOC(namep);
-		strcpy(namep, "linux,phandle");
-		mem_start = ALIGNUL((unsigned long)namep + strlen(namep) + 1);
-		pp->value = (unsigned char *) PTRUNRELOC(&np->node);
-		pp->length = sizeof(np->node);
-	}
-	*prev_propp = NULL;
-
-	/* get the node's full name */
-	l = call_prom("package-to-path", 3, 1, node,
-		      mem_start, mem_end - mem_start);
-	if (l >= 0) {
-		char *p, *ep;
-
-		np->full_name = PTRUNRELOC((char *) mem_start);
-		*(char *)(mem_start + l) = 0;
-		/* Fixup an Apple bug where they have bogus \0 chars in the
-		 * middle of the path in some properties
-		 */
-		for (p = (char *)mem_start, ep = p + l; p < ep; p++)
-			if ((*p) == '\0') {
-				memmove(p, p+1, ep - p);
-				ep--;
-			}
-		mem_start = ALIGNUL(mem_start + l + 1);
-	}
-
-	/* do all our children */
-	child = call_prom("child", 1, 1, node);
-	while (child != 0) {
-		mem_start = inspect_node(child, np, mem_start, mem_end,
-					 allnextpp);
-		child = call_prom("peer", 1, 1, child);
-	}
-
-	return mem_start;
-}
-
-unsigned long smp_chrp_cpu_nr __initdata = 0;
-
-/*
- * With CHRP SMP we need to use the OF to start the other
- * processors so we can't wait until smp_boot_cpus (the OF is
- * trashed by then) so we have to put the processors into
- * a holding pattern controlled by the kernel (not OF) before
- * we destroy the OF.
- *
- * This uses a chunk of high memory, puts some holding pattern
- * code there and sends the other processors off to there until
- * smp_boot_cpus tells them to do something.  We do that by using
- * physical address 0x0.  The holding pattern checks that address
- * until its cpu # is there, when it is that cpu jumps to
- * __secondary_start().  smp_boot_cpus() takes care of setting those
- * values.
- *
- * We also use physical address 0x4 here to tell when a cpu
- * is in its holding pattern code.
- *
- * -- Cort
- *
- * Note that we have to do this if we have more than one CPU,
- * even if this is a UP kernel.  Otherwise when we trash OF
- * the other CPUs will start executing some random instructions
- * and crash the system.  -- paulus
- */
-static void __init
-prom_hold_cpus(unsigned long mem)
-{
-	extern void __secondary_hold(void);
-	unsigned long i;
-	int cpu;
-	phandle node;
-	char type[16], *path;
-	unsigned int reg;
-
-	/*
-	 * XXX: hack to make sure we're chrp, assume that if we're
-	 *      chrp we have a device_type property -- Cort
-	 */
-	node = call_prom("finddevice", 1, 1, "/");
-	if (call_prom("getprop", 4, 1, node,
-		      "device_type", type, sizeof(type)) <= 0)
-		return;
-
-	/* copy the holding pattern code to someplace safe (0) */
-	/* the holding pattern is now within the first 0x100
-	   bytes of the kernel image -- paulus */
-	memcpy((void *)0, _stext, 0x100);
-	flush_icache_range(0, 0x100);
-
-	/* look for cpus */
-	*(unsigned long *)(0x0) = 0;
-	asm volatile("dcbf 0,%0": : "r" (0) : "memory");
-	for (node = 0; prom_next_node(&node); ) {
-		type[0] = 0;
-		call_prom("getprop", 4, 1, node, "device_type",
-			  type, sizeof(type));
-		if (strcmp(type, "cpu") != 0)
-			continue;
-		path = (char *) mem;
-		memset(path, 0, 256);
-		if (call_prom("package-to-path", 3, 1, node, path, 255) < 0)
-			continue;
-		reg = -1;
-		call_prom("getprop", 4, 1, node, "reg", &reg, sizeof(reg));
-		cpu = smp_chrp_cpu_nr++;
-#ifdef CONFIG_SMP
-		smp_hw_index[cpu] = reg;
-#endif /* CONFIG_SMP */
-		/* XXX: hack - don't start cpu 0, this cpu -- Cort */
-		if (cpu == 0)
-			continue;
-		prom_print("starting cpu ");
-		prom_print(path);
-		*(ulong *)(0x4) = 0;
-		call_prom("start-cpu", 3, 0, node,
-			  (char *)__secondary_hold - _stext, cpu);
-		prom_print("...");
-		for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ )
-			;
-		if (*(ulong *)(0x4) == cpu)
-			prom_print("ok\n");
-		else {
-			prom_print("failed: ");
-			prom_print_hex(*(ulong *)0x4);
-			prom_print("\n");
-		}
-	}
-}
-
-static void __init
-prom_instantiate_rtas(void)
-{
-	ihandle prom_rtas;
-	prom_arg_t result;
-
-	prom_rtas = call_prom("finddevice", 1, 1, "/rtas");
-	if (prom_rtas == -1)
-		return;
-
-	rtas_size = 0;
-	call_prom("getprop", 4, 1, prom_rtas,
-		  "rtas-size", &rtas_size, sizeof(rtas_size));
-	prom_print("instantiating rtas");
-	if (rtas_size == 0) {
-		rtas_data = 0;
-	} else {
-		/*
-		 * Ask OF for some space for RTAS.
-		 * Actually OF has bugs so we just arbitrarily
-		 * use memory at the 6MB point.
-		 */
-		rtas_data = 6 << 20;
-		prom_print(" at ");
-		prom_print_hex(rtas_data);
-	}
-
-	prom_rtas = call_prom("open", 1, 1, "/rtas");
-	prom_print("...");
-	rtas_entry = 0;
-	if (call_prom_ret("call-method", 3, 2, &result,
-			  "instantiate-rtas", prom_rtas, rtas_data) == 0)
-		rtas_entry = result;
-	if ((rtas_entry == -1) || (rtas_entry == 0))
-		prom_print(" failed\n");
-	else
-		prom_print(" done\n");
-}
-
-/*
- * We enter here early on, when the Open Firmware prom is still
- * handling exceptions and the MMU hash table for us.
- */
-unsigned long __init
-prom_init(int r3, int r4, prom_entry pp)
-{
-	unsigned long mem;
-	ihandle prom_mmu;
-	unsigned long offset = reloc_offset();
-	int i, l;
-	char *p, *d;
- 	unsigned long phys;
-	prom_arg_t result[3];
-	char model[32];
-	phandle node;
-	int rc;
-
- 	/* Default */
- 	phys = (unsigned long) &_stext;
-
-	/* First get a handle for the stdout device */
-	prom = pp;
-	prom_chosen = call_prom("finddevice", 1, 1, "/chosen");
-	if (prom_chosen == -1)
-		prom_exit();
-	if (call_prom("getprop", 4, 1, prom_chosen, "stdout",
-		      &prom_stdout, sizeof(prom_stdout)) <= 0)
-		prom_exit();
-
-	/* Get the full OF pathname of the stdout device */
-	mem = (unsigned long) klimit + offset;
-	p = (char *) mem;
-	memset(p, 0, 256);
-	call_prom("instance-to-path", 3, 1, prom_stdout, p, 255);
-	of_stdout_device = p;
-	mem += strlen(p) + 1;
-
-	/* Get the boot device and translate it to a full OF pathname. */
-	p = (char *) mem;
-	l = call_prom("getprop", 4, 1, prom_chosen, "bootpath", p, 1<<20);
-	if (l > 0) {
-		p[l] = 0;	/* should already be null-terminated */
-		bootpath = PTRUNRELOC(p);
-		mem += l + 1;
-		d = (char *) mem;
-		*d = 0;
-		call_prom("canon", 3, 1, p, d, 1<<20);
-		bootdevice = PTRUNRELOC(d);
-		mem = ALIGNUL(mem + strlen(d) + 1);
-	}
-
-	prom_instantiate_rtas();
-
-#ifdef CONFIG_POWER4
-	/*
-	 * Find out how much memory we have and allocate a
-	 * suitably-sized hash table.
-	 */
-	prom_alloc_htab();
-#endif
-	mem = check_display(mem);
-
-	prom_print("copying OF device tree...");
-	mem = copy_device_tree(mem, mem + (1<<20));
-	prom_print("done\n");
-
-	prom_hold_cpus(mem);
-
-	klimit = (char *) (mem - offset);
-
-	node = call_prom("finddevice", 1, 1, "/");
-	rc = call_prom("getprop", 4, 1, node, "model", model, sizeof(model));
-	if (rc > 0 && !strncmp (model, "Pegasos", 7)
-		&& strncmp (model, "Pegasos2", 8)) {
-		/* Pegasos 1 has a broken translate method in the OF,
-		 * and furthermore the BATs are mapped 1:1 so the phys
-		 * address calculated above is correct, so let's use
-		 * it directly.
-		 */
-	} else if (offset == 0) {
-		/* If we are already running at 0xc0000000, we assume we were
-	 	 * loaded by an OF bootloader which did set a BAT for us.
-	 	 * This breaks OF translate so we force phys to be 0.
-	 	 */
-		prom_print("(already at 0xc0000000) phys=0\n");
-		phys = 0;
-	} else if (call_prom("getprop", 4, 1, prom_chosen, "mmu",
-			     &prom_mmu, sizeof(prom_mmu)) <= 0) {
-		prom_print(" no MMU found\n");
-	} else if (call_prom_ret("call-method", 4, 4, result, "translate",
-				 prom_mmu, &_stext, 1) != 0) {
-		prom_print(" (translate failed)\n");
-	} else {
-		/* We assume the phys. address size is 3 cells */
-		phys = result[2];
-	}
-
-	if (prom_disp_node != 0)
-		setup_disp_fake_bi(prom_disp_node);
-
-	/* Use quiesce call to get OF to shut down any devices it's using */
-	prom_print("Calling quiesce ...\n");
-	call_prom("quiesce", 0, 0);
-
-	/* Relocate various pointers which will be used once the
-	   kernel is running at the address it was linked at. */
-	for (i = 0; i < prom_num_displays; ++i)
-		prom_display_paths[i] = PTRUNRELOC(prom_display_paths[i]);
-
-#ifdef CONFIG_SERIAL_CORE_CONSOLE
-	/* Relocate the of stdout for console autodetection */
-	of_stdout_device = PTRUNRELOC(of_stdout_device);
-#endif
-
-	prom_print("returning 0x");
-	prom_print_hex(phys);
-	prom_print("from prom_init\n");
-	prom_stdout = 0;
-
-	return phys;
-}
-
-/*
- * early_get_property is used to access the device tree image prepared
- * by BootX very early on, before the pointers in it have been relocated.
- */
-static void * __init
-early_get_property(unsigned long base, unsigned long node, char *prop)
-{
-	struct device_node *np = (struct device_node *)(base + node);
-	struct property *pp;
-
-	for (pp = np->properties; pp != 0; pp = pp->next) {
-		pp = (struct property *) (base + (unsigned long)pp);
-		if (strcmp((char *)((unsigned long)pp->name + base),
-			   prop) == 0) {
-			return (void *)((unsigned long)pp->value + base);
-		}
-	}
-	return NULL;
-}
-
-/* Is boot-info compatible ? */
-#define BOOT_INFO_IS_COMPATIBLE(bi)		((bi)->compatible_version <= BOOT_INFO_VERSION)
-#define BOOT_INFO_IS_V2_COMPATIBLE(bi)	((bi)->version >= 2)
-#define BOOT_INFO_IS_V4_COMPATIBLE(bi)	((bi)->version >= 4)
-
-void __init
-bootx_init(unsigned long r4, unsigned long phys)
-{
-	boot_infos_t *bi = (boot_infos_t *) r4;
-	unsigned long space;
-	unsigned long ptr, x;
-	char *model;
-
-	boot_infos = PTRUNRELOC(bi);
-	if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
-		bi->logicalDisplayBase = NULL;
-
-#ifdef CONFIG_BOOTX_TEXT
-	btext_init(bi);
-
-	/*
-	 * Test if boot-info is compatible.  Done only in config
-	 * CONFIG_BOOTX_TEXT since there is nothing much we can do
-	 * with an incompatible version, except display a message
-	 * and eventually hang the processor...
-	 *
-	 * I'll try to keep enough of boot-info compatible in the
-	 * future to always allow display of this message;
-	 */
-	if (!BOOT_INFO_IS_COMPATIBLE(bi)) {
-		btext_drawstring(" !!! WARNING - Incompatible version of BootX !!!\n\n\n");
-		btext_flushscreen();
-	}
-#endif	/* CONFIG_BOOTX_TEXT */
-
-	/* New BootX enters kernel with MMU off, i/os are not allowed
-	   here. This hack will have been done by the boostrap anyway.
-	*/
-	if (bi->version < 4) {
-		/*
-		 * XXX If this is an iMac, turn off the USB controller.
-		 */
-		model = (char *) early_get_property
-			(r4 + bi->deviceTreeOffset, 4, "model");
-		if (model
-		    && (strcmp(model, "iMac,1") == 0
-			|| strcmp(model, "PowerMac1,1") == 0)) {
-			out_le32((unsigned *)0x80880008, 1);	/* XXX */
-		}
-	}
-
-	/* Move klimit to enclose device tree, args, ramdisk, etc... */
-	if (bi->version < 5) {
-		space = bi->deviceTreeOffset + bi->deviceTreeSize;
-		if (bi->ramDisk)
-			space = bi->ramDisk + bi->ramDiskSize;
-	} else
-		space = bi->totalParamsSize;
-	klimit = PTRUNRELOC((char *) bi + space);
-
-	/* New BootX will have flushed all TLBs and enters kernel with
-	   MMU switched OFF, so this should not be useful anymore.
-	*/
-	if (bi->version < 4) {
-		/*
-		 * Touch each page to make sure the PTEs for them
-		 * are in the hash table - the aim is to try to avoid
-		 * getting DSI exceptions while copying the kernel image.
-		 */
-		for (ptr = ((unsigned long) &_stext) & PAGE_MASK;
-		     ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
-			x = *(volatile unsigned long *)ptr;
-	}
-
-#ifdef CONFIG_BOOTX_TEXT
-	/*
-	 * Note that after we call btext_prepare_BAT, we can't do
-	 * prom_draw*, flushscreen or clearscreen until we turn the MMU
-	 * on, since btext_prepare_BAT sets disp_bi.logicalDisplayBase
-	 * to a virtual address.
-	 */
-	btext_prepare_BAT();
-#endif
-}
diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c
index ff86b2d..cfc2d6a 100644
--- a/arch/ppc/xmon/start.c
+++ b/arch/ppc/xmon/start.c
@@ -58,7 +58,7 @@
 void
 xmon_map_scc(void)
 {
-#ifdef CONFIG_PPC_MULTIPLATFORM
+#ifdef CONFIG_PPC_PREP
 	volatile unsigned char *base;
 
 #elif defined(CONFIG_GEMINI)
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 2b7364e..01c5c08 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -14,6 +14,10 @@
 	bool
 	default y
 
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff --git a/arch/s390/crypto/crypt_s390_query.c b/arch/s390/crypto/crypt_s390_query.c
index def02bd..54fb11d 100644
--- a/arch/s390/crypto/crypt_s390_query.c
+++ b/arch/s390/crypto/crypt_s390_query.c
@@ -55,7 +55,7 @@
 	printk(KERN_INFO "KMC_AES_256: %d\n",
 		crypt_s390_func_available(KMC_AES_256_ENCRYPT));
 
-	/* query available KIMD fucntions */
+	/* query available KIMD functions */
 	printk(KERN_INFO "KIMD_QUERY: %d\n",
 		crypt_s390_func_available(KIMD_QUERY));
 	printk(KERN_INFO "KIMD_SHA_1: %d\n",
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index cc058dc..5e14de3 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -26,7 +26,6 @@
 #include <linux/resource.h>
 #include <linux/times.h>
 #include <linux/utsname.h>
-#include <linux/timex.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/sem.h>
@@ -705,79 +704,6 @@
 	return ret;
 }
 
-/* Handle adjtimex compatibility. */
-
-struct timex32 {
-	u32 modes;
-	s32 offset, freq, maxerror, esterror;
-	s32 status, constant, precision, tolerance;
-	struct compat_timeval time;
-	s32 tick;
-	s32 ppsfreq, jitter, shift, stabil;
-	s32 jitcnt, calcnt, errcnt, stbcnt;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-};
-
-extern int do_adjtimex(struct timex *);
-
-asmlinkage long sys32_adjtimex(struct timex32 __user *utp)
-{
-	struct timex txc;
-	int ret;
-
-	memset(&txc, 0, sizeof(struct timex));
-
-	if(get_user(txc.modes, &utp->modes) ||
-	   __get_user(txc.offset, &utp->offset) ||
-	   __get_user(txc.freq, &utp->freq) ||
-	   __get_user(txc.maxerror, &utp->maxerror) ||
-	   __get_user(txc.esterror, &utp->esterror) ||
-	   __get_user(txc.status, &utp->status) ||
-	   __get_user(txc.constant, &utp->constant) ||
-	   __get_user(txc.precision, &utp->precision) ||
-	   __get_user(txc.tolerance, &utp->tolerance) ||
-	   __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	   __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	   __get_user(txc.tick, &utp->tick) ||
-	   __get_user(txc.ppsfreq, &utp->ppsfreq) ||
-	   __get_user(txc.jitter, &utp->jitter) ||
-	   __get_user(txc.shift, &utp->shift) ||
-	   __get_user(txc.stabil, &utp->stabil) ||
-	   __get_user(txc.jitcnt, &utp->jitcnt) ||
-	   __get_user(txc.calcnt, &utp->calcnt) ||
-	   __get_user(txc.errcnt, &utp->errcnt) ||
-	   __get_user(txc.stbcnt, &utp->stbcnt))
-		return -EFAULT;
-
-	ret = do_adjtimex(&txc);
-
-	if(put_user(txc.modes, &utp->modes) ||
-	   __put_user(txc.offset, &utp->offset) ||
-	   __put_user(txc.freq, &utp->freq) ||
-	   __put_user(txc.maxerror, &utp->maxerror) ||
-	   __put_user(txc.esterror, &utp->esterror) ||
-	   __put_user(txc.status, &utp->status) ||
-	   __put_user(txc.constant, &utp->constant) ||
-	   __put_user(txc.precision, &utp->precision) ||
-	   __put_user(txc.tolerance, &utp->tolerance) ||
-	   __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	   __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	   __put_user(txc.tick, &utp->tick) ||
-	   __put_user(txc.ppsfreq, &utp->ppsfreq) ||
-	   __put_user(txc.jitter, &utp->jitter) ||
-	   __put_user(txc.shift, &utp->shift) ||
-	   __put_user(txc.stabil, &utp->stabil) ||
-	   __put_user(txc.jitcnt, &utp->jitcnt) ||
-	   __put_user(txc.calcnt, &utp->calcnt) ||
-	   __put_user(txc.errcnt, &utp->errcnt) ||
-	   __put_user(txc.stbcnt, &utp->stbcnt))
-		ret = -EFAULT;
-
-	return ret;
-}
-
 #ifdef CONFIG_SYSCTL
 struct __sysctl_args32 {
 	u32 name;
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 50e8013..199da68 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -551,10 +551,10 @@
 	llgtr	%r2,%r2			# struct new_utsname *
 	jg	s390x_newuname		# branch to system call
 
-	.globl  sys32_adjtimex_wrapper 
-sys32_adjtimex_wrapper:
-	llgtr	%r2,%r2			# struct timex_emu31 *
-	jg	sys32_adjtimex		# branch to system call
+	.globl  compat_sys_adjtimex_wrapper
+compat_sys_adjtimex_wrapper:
+	llgtr	%r2,%r2			# struct compat_timex *
+	jg	compat_sys_adjtimex	# branch to system call
 
 	.globl  sys32_mprotect_wrapper 
 sys32_mprotect_wrapper:
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 99182a4..4a0f5a1 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -76,17 +76,17 @@
 /*
  * Need to know about CPUs going idle?
  */
-static struct notifier_block *idle_chain;
+static ATOMIC_NOTIFIER_HEAD(idle_chain);
 
 int register_idle_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_register(&idle_chain, nb);
+	return atomic_notifier_chain_register(&idle_chain, nb);
 }
 EXPORT_SYMBOL(register_idle_notifier);
 
 int unregister_idle_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_unregister(&idle_chain, nb);
+	return atomic_notifier_chain_unregister(&idle_chain, nb);
 }
 EXPORT_SYMBOL(unregister_idle_notifier);
 
@@ -95,7 +95,7 @@
 	/* disable monitor call class 0 */
 	__ctl_clear_bit(8, 15);
 
-	notifier_call_chain(&idle_chain, CPU_NOT_IDLE,
+	atomic_notifier_call_chain(&idle_chain, CPU_NOT_IDLE,
 			    (void *)(long) smp_processor_id());
 }
 
@@ -116,7 +116,8 @@
 		return;
 	}
 
-	rc = notifier_call_chain(&idle_chain, CPU_IDLE, (void *)(long) cpu);
+	rc = atomic_notifier_call_chain(&idle_chain,
+			CPU_IDLE, (void *)(long) cpu);
 	if (rc != NOTIFY_OK && rc != NOTIFY_DONE)
 		BUG();
 	if (rc != NOTIFY_OK) {
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 2b8841f..343120c 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -801,7 +801,7 @@
          */
 	print_cpu_info(&S390_lowcore.cpu_data);
 
-        for_each_cpu(i) {
+        for_each_possible_cpu(i) {
 		lowcore_ptr[i] = (struct _lowcore *)
 			__get_free_pages(GFP_KERNEL|GFP_DMA, 
 					sizeof(void*) == 8 ? 1 : 0);
@@ -831,7 +831,7 @@
 #endif
 	set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]);
 
-	for_each_cpu(cpu)
+	for_each_possible_cpu(cpu)
 		if (cpu != smp_processor_id())
 			smp_create_idle(cpu);
 }
@@ -868,7 +868,7 @@
 	int cpu;
 	int ret;
 
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu, NULL);
 		if (ret)
 			printk(KERN_WARNING "topology_init: register_cpu %d "
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 7c88d85..2f56654 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -132,7 +132,7 @@
 SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper)
 SYSCALL(sys_newuname,s390x_newuname,sys32_newuname_wrapper)
 NI_SYSCALL							/* modify_ldt for i386 */
-SYSCALL(sys_adjtimex,sys_adjtimex,sys32_adjtimex_wrapper)
+SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex_wrapper)
 SYSCALL(sys_mprotect,sys_mprotect,sys32_mprotect_wrapper)	/* 125 */
 SYSCALL(sys_sigprocmask,sys_sigprocmask,compat_sys_sigprocmask_wrapper)
 NI_SYSCALL							/* old "create module" */
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index e9b275d..58583f4 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -21,6 +21,14 @@
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_HARDIRQS
 	bool
 	default y
diff --git a/arch/sh/boards/mpc1211/rtc.c b/arch/sh/boards/mpc1211/rtc.c
index 4d100f0..a76c655 100644
--- a/arch/sh/boards/mpc1211/rtc.c
+++ b/arch/sh/boards/mpc1211/rtc.c
@@ -9,36 +9,16 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/time.h>
+#include <linux/bcd.h>
 #include <linux/mc146818rtc.h>
 
-#ifndef BCD_TO_BIN
-#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
-#endif
-
-#ifndef BIN_TO_BCD
-#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
-#endif
-
-/* arc/i386/kernel/time.c */
 unsigned long get_cmos_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
-	int i;
 
 	spin_lock(&rtc_lock);
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-	/* read RTC exactly on falling edge of update flag */
-	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
-		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-			break;
-	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
-		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-			break;
-	do { /* Isn't this overkill ? UIP above should guarantee consistency */
+
+	do {
 		sec = CMOS_READ(RTC_SECONDS);
 		min = CMOS_READ(RTC_MINUTES);
 		hour = CMOS_READ(RTC_HOURS);
@@ -46,18 +26,22 @@
 		mon = CMOS_READ(RTC_MONTH);
 		year = CMOS_READ(RTC_YEAR);
 	} while (sec != CMOS_READ(RTC_SECONDS));
-	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-	  {
-	    BCD_TO_BIN(sec);
-	    BCD_TO_BIN(min);
-	    BCD_TO_BIN(hour);
-	    BCD_TO_BIN(day);
-	    BCD_TO_BIN(mon);
-	    BCD_TO_BIN(year);
-	  }
+
+	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BCD_TO_BIN(sec);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(hour);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(mon);
+		BCD_TO_BIN(year);
+	}
+
 	spin_unlock(&rtc_lock);
-	if ((year += 1900) < 1970)
+
+	year += 1900;
+	if (year < 1970)
 		year += 100;
+
 	return mktime(year, mon, day, hour, min, sec);
 }
 
diff --git a/arch/sh/boards/sh03/rtc.c b/arch/sh/boards/sh03/rtc.c
index cbeca70..d609863 100644
--- a/arch/sh/boards/sh03/rtc.c
+++ b/arch/sh/boards/sh03/rtc.c
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/time.h>
+#include <linux/bcd.h>
 #include <asm/io.h>
 #include <linux/rtc.h>
 #include <linux/spinlock.h>
@@ -33,14 +34,6 @@
 #define RTC_BUSY	1
 #define RTC_STOP	2
 
-#ifndef BCD_TO_BIN
-#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
-#endif
-
-#ifndef BIN_TO_BCD
-#define BIN_TO_BCD(val)	((val)=(((val)/10)<<4) + (val)%10)
-#endif
-
 extern void (*rtc_get_time)(struct timespec *);
 extern int (*rtc_set_time)(const time_t);
 extern spinlock_t rtc_lock;
@@ -48,13 +41,9 @@
 unsigned long get_cmos_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
-	int i;
 
 	spin_lock(&rtc_lock);
  again:
-	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
-		if (!(ctrl_inb(RTC_CTL) & RTC_BUSY))
-			break;
 	do {
 		sec  = (ctrl_inb(RTC_SEC1) & 0xf) + (ctrl_inb(RTC_SEC10) & 0x7) * 10;
 		min  = (ctrl_inb(RTC_MIN1) & 0xf) + (ctrl_inb(RTC_MIN10) & 0xf) * 10;
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index cf94e8e..868e68b 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -30,7 +30,7 @@
 static int __init x##_setup(char *opts)		\
 {						\
 	x##_disabled = 1;			\
-	return 0;				\
+	return 1;				\
 }						\
 __setup("no" __stringify(x), x##_setup);
 
diff --git a/arch/sh/kernel/cpu/rtc.c b/arch/sh/kernel/cpu/rtc.c
index f8361f5..4304cf7 100644
--- a/arch/sh/kernel/cpu/rtc.c
+++ b/arch/sh/kernel/cpu/rtc.c
@@ -9,18 +9,10 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/time.h>
-
+#include <linux/bcd.h>
 #include <asm/io.h>
 #include <asm/rtc.h>
 
-#ifndef BCD_TO_BIN
-#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
-#endif
-
-#ifndef BIN_TO_BCD
-#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
-#endif
-
 void sh_rtc_gettimeofday(struct timespec *ts)
 {
 	unsigned int sec128, sec, sec2, min, hr, wk, day, mon, yr, yr100, cf_bit;
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index c0e79843..bb229ef 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -20,6 +20,7 @@
 #include <linux/root_dev.h>
 #include <linux/utsname.h>
 #include <linux/cpu.h>
+#include <linux/pfn.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/sections.h>
@@ -275,10 +276,6 @@
 
 	sh_mv_setup(cmdline_p);
 
-#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
-#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
-
 	/*
 	 * Find the highest page frame number we have available
 	 */
@@ -404,7 +401,7 @@
 {
 	int cpu_id;
 
-	for_each_cpu(cpu_id)
+	for_each_possible_cpu(cpu_id)
 		register_cpu(&cpu[cpu_id], cpu_id, NULL);
 
 	return 0;
diff --git a/arch/sh64/Kconfig b/arch/sh64/Kconfig
index 07b172d..58c678e 100644
--- a/arch/sh64/Kconfig
+++ b/arch/sh64/Kconfig
@@ -21,6 +21,14 @@
 	bool
 	default y
 
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff --git a/arch/sh64/kernel/setup.c b/arch/sh64/kernel/setup.c
index c7a7b816..d2711c9 100644
--- a/arch/sh64/kernel/setup.c
+++ b/arch/sh64/kernel/setup.c
@@ -48,6 +48,7 @@
 #include <linux/root_dev.h>
 #include <linux/cpu.h>
 #include <linux/initrd.h>
+#include <linux/pfn.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c
index 0773c9f..6b8f4d2 100644
--- a/arch/sh64/kernel/time.c
+++ b/arch/sh64/kernel/time.c
@@ -30,6 +30,7 @@
 #include <linux/profile.h>
 #include <linux/smp.h>
 #include <linux/module.h>
+#include <linux/bcd.h>
 
 #include <asm/registers.h>	 /* required by inline __asm__ stmt. */
 
@@ -105,14 +106,6 @@
 #define RCR1    	rtc_base+0x38
 #define RCR2    	rtc_base+0x3c
 
-#ifndef BCD_TO_BIN
-#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
-#endif
-
-#ifndef BIN_TO_BCD
-#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
-#endif
-
 #define TICK_SIZE (tick_nsec / 1000)
 
 extern unsigned long wall_jiffies;
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 7c58fc1..9431e96 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -150,6 +150,14 @@
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 267afdd..d1e2fc5 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -162,6 +162,14 @@
 	bool
 	default y
 
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y if !ULTRA_HAS_POPULATION_COUNT
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index f819a96..900fb0b 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.16
-# Mon Mar 20 01:23:21 2006
+# Sun Mar 26 14:58:11 2006
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
@@ -38,6 +38,7 @@
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
+CONFIG_RELAY=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_UID16=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -53,10 +54,6 @@
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
 CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
@@ -68,7 +65,6 @@
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_OBSOLETE_MODPARM=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_KMOD=y
@@ -76,6 +72,7 @@
 #
 # Block layer
 #
+CONFIG_BLK_DEV_IO_TRACE=y
 
 #
 # IO Schedulers
@@ -111,6 +108,8 @@
 CONFIG_US3_FREQ=m
 CONFIG_US2E_FREQ=m
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HUGETLB_PAGE_SIZE_4MB=y
 # CONFIG_HUGETLB_PAGE_SIZE_512K is not set
@@ -128,7 +127,6 @@
 CONFIG_SPARSEMEM_EXTREME=y
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
-CONFIG_MIGRATION=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_SBUS=y
 CONFIG_SBUSCHAR=y
@@ -136,7 +134,6 @@
 CONFIG_SUN_IO=y
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
-# CONFIG_PCI_LEGACY_PROC is not set
 # CONFIG_PCI_DEBUG is not set
 CONFIG_SUN_OPENPROMFS=m
 CONFIG_SPARC32_COMPAT=y
@@ -201,6 +198,8 @@
 CONFIG_TCP_CONG_SCALABLE=m
 CONFIG_IPV6=m
 CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
@@ -213,10 +212,12 @@
 #
 CONFIG_IP_DCCP=m
 CONFIG_INET_DCCP_DIAG=m
+CONFIG_IP_DCCP_ACKVEC=y
 
 #
 # DCCP CCIDs Configuration (EXPERIMENTAL)
 #
+CONFIG_IP_DCCP_CCID2=m
 CONFIG_IP_DCCP_CCID3=m
 CONFIG_IP_DCCP_TFRC_LIB=m
 
@@ -224,7 +225,6 @@
 # DCCP Kernel Hacking
 #
 # CONFIG_IP_DCCP_DEBUG is not set
-# CONFIG_IP_DCCP_UNLOAD_HACK is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
@@ -309,6 +309,7 @@
 CONFIG_BLK_DEV_UB=m
 # CONFIG_BLK_DEV_RAM is not set
 CONFIG_BLK_DEV_RAM_COUNT=16
+# CONFIG_BLK_DEV_INITRD is not set
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_CDROM_PKTCDVD_BUFFERS=8
 CONFIG_CDROM_PKTCDVD_WCACHE=y
@@ -722,7 +723,6 @@
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB is not set
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
@@ -808,10 +808,6 @@
 #
 
 #
-# Multimedia Capabilities Port drivers
-#
-
-#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -820,6 +816,7 @@
 # Digital Video Broadcasting Devices
 #
 # CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
@@ -901,10 +898,12 @@
 CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=m
 CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
 CONFIG_SND_SEQUENCER_OSS=y
 # CONFIG_SND_RTCTIMER is not set
 # CONFIG_SND_DYNAMIC_MINORS is not set
 CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 
@@ -987,6 +986,7 @@
 #
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
@@ -1014,7 +1014,6 @@
 #
 # USB Device Class drivers
 #
-# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
 
@@ -1058,15 +1057,6 @@
 # CONFIG_USB_MICROTEK is not set
 
 #
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
 # USB Network Adapters
 #
 # CONFIG_USB_CATC is not set
@@ -1194,7 +1184,6 @@
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
-CONFIG_RELAYFS_FS=m
 # CONFIG_CONFIGFS_FS is not set
 
 #
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
index b9a9ce7..ffc7309 100644
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -6,9 +6,11 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/kprobes.h>
+#include <linux/module.h>
 #include <asm/kdebug.h>
 #include <asm/signal.h>
 #include <asm/cacheflush.h>
+#include <asm/uaccess.h>
 
 /* We do not have hardware single-stepping on sparc64.
  * So we implement software single-stepping with breakpoint
@@ -302,16 +304,68 @@
 {
 	struct kprobe *cur = kprobe_running();
 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	const struct exception_table_entry *entry;
 
-	if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-		return 1;
-
-	if (kcb->kprobe_status & KPROBE_HIT_SS) {
-		resume_execution(cur, regs, kcb);
-
-		reset_current_kprobe();
+	switch(kcb->kprobe_status) {
+	case KPROBE_HIT_SS:
+	case KPROBE_REENTER:
+		/*
+		 * We are here because the instruction being single
+		 * stepped caused a page fault. We reset the current
+		 * kprobe and the tpc points back to the probe address
+		 * and allow the page fault handler to continue as a
+		 * normal page fault.
+		 */
+		regs->tpc = (unsigned long)cur->addr;
+		regs->tnpc = kcb->kprobe_orig_tnpc;
+		regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
+				kcb->kprobe_orig_tstate_pil);
+		if (kcb->kprobe_status == KPROBE_REENTER)
+			restore_previous_kprobe(kcb);
+		else
+			reset_current_kprobe();
 		preempt_enable_no_resched();
+		break;
+	case KPROBE_HIT_ACTIVE:
+	case KPROBE_HIT_SSDONE:
+		/*
+		 * We increment the nmissed count for accounting,
+		 * we can also use npre/npostfault count for accouting
+		 * these specific fault cases.
+		 */
+		kprobes_inc_nmissed_count(cur);
+
+		/*
+		 * We come here because instructions in the pre/post
+		 * handler caused the page_fault, this could happen
+		 * if handler tries to access user space by
+		 * copy_from_user(), get_user() etc. Let the
+		 * user-specified handler try to fix it first.
+		 */
+		if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
+			return 1;
+
+		/*
+		 * In case the user-specified fault handler returned
+		 * zero, try to fix up.
+		 */
+
+		entry = search_exception_tables(regs->tpc);
+		if (entry) {
+			regs->tpc = entry->fixup;
+			regs->tnpc = regs->tpc + 4;
+			return 1;
+		}
+
+		/*
+		 * fixup_exception() could not handle it,
+		 * Let do_page_fault() fix it.
+		 */
+		break;
+	default:
+		break;
 	}
+
 	return 0;
 }
 
@@ -324,6 +378,9 @@
 	struct die_args *args = (struct die_args *)data;
 	int ret = NOTIFY_DONE;
 
+	if (args->regs && user_mode(args->regs))
+		return ret;
+
 	switch (val) {
 	case DIE_DEBUG:
 		if (kprobe_handler(args->regs))
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 9914a17..f5e8db1 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -175,11 +175,6 @@
 EXPORT_SYMBOL(clear_bit);
 EXPORT_SYMBOL(change_bit);
 
-/* Bit searching */
-EXPORT_SYMBOL(find_next_bit);
-EXPORT_SYMBOL(find_next_zero_bit);
-EXPORT_SYMBOL(find_next_zero_le_bit);
-
 EXPORT_SYMBOL(ivector_table);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
@@ -279,18 +274,9 @@
 
 /* sparc library symbols */
 EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(__strlen_user);
 EXPORT_SYMBOL(__strnlen_user);
-EXPORT_SYMBOL(strcpy);
-EXPORT_SYMBOL(strncpy);
-EXPORT_SYMBOL(strcat);
-EXPORT_SYMBOL(strncat);
-EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strchr);
-EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(strstr);
 
 #ifdef CONFIG_SOLARIS_EMUL_MODULE
 EXPORT_SYMBOL(linux_sparc_syscall);
@@ -324,7 +310,6 @@
 EXPORT_SYMBOL(__memscan_generic);
 EXPORT_SYMBOL(__memcmp);
 EXPORT_SYMBOL(__memset);
-EXPORT_SYMBOL(memchr);
 
 EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(csum_partial_copy_nocheck);
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 0e41df0..2e906ba 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -19,7 +19,6 @@
 #include <linux/resource.h>
 #include <linux/times.h>
 #include <linux/utsname.h>
-#include <linux/timex.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/sem.h>
@@ -945,79 +944,6 @@
 	return ret;
 }
 
-/* Handle adjtimex compatibility. */
-
-struct timex32 {
-	u32 modes;
-	s32 offset, freq, maxerror, esterror;
-	s32 status, constant, precision, tolerance;
-	struct compat_timeval time;
-	s32 tick;
-	s32 ppsfreq, jitter, shift, stabil;
-	s32 jitcnt, calcnt, errcnt, stbcnt;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-};
-
-extern int do_adjtimex(struct timex *);
-
-asmlinkage long sys32_adjtimex(struct timex32 __user *utp)
-{
-	struct timex txc;
-	int ret;
-
-	memset(&txc, 0, sizeof(struct timex));
-
-	if (get_user(txc.modes, &utp->modes) ||
-	    __get_user(txc.offset, &utp->offset) ||
-	    __get_user(txc.freq, &utp->freq) ||
-	    __get_user(txc.maxerror, &utp->maxerror) ||
-	    __get_user(txc.esterror, &utp->esterror) ||
-	    __get_user(txc.status, &utp->status) ||
-	    __get_user(txc.constant, &utp->constant) ||
-	    __get_user(txc.precision, &utp->precision) ||
-	    __get_user(txc.tolerance, &utp->tolerance) ||
-	    __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	    __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	    __get_user(txc.tick, &utp->tick) ||
-	    __get_user(txc.ppsfreq, &utp->ppsfreq) ||
-	    __get_user(txc.jitter, &utp->jitter) ||
-	    __get_user(txc.shift, &utp->shift) ||
-	    __get_user(txc.stabil, &utp->stabil) ||
-	    __get_user(txc.jitcnt, &utp->jitcnt) ||
-	    __get_user(txc.calcnt, &utp->calcnt) ||
-	    __get_user(txc.errcnt, &utp->errcnt) ||
-	    __get_user(txc.stbcnt, &utp->stbcnt))
-		return -EFAULT;
-
-	ret = do_adjtimex(&txc);
-
-	if (put_user(txc.modes, &utp->modes) ||
-	    __put_user(txc.offset, &utp->offset) ||
-	    __put_user(txc.freq, &utp->freq) ||
-	    __put_user(txc.maxerror, &utp->maxerror) ||
-	    __put_user(txc.esterror, &utp->esterror) ||
-	    __put_user(txc.status, &utp->status) ||
-	    __put_user(txc.constant, &utp->constant) ||
-	    __put_user(txc.precision, &utp->precision) ||
-	    __put_user(txc.tolerance, &utp->tolerance) ||
-	    __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	    __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	    __put_user(txc.tick, &utp->tick) ||
-	    __put_user(txc.ppsfreq, &utp->ppsfreq) ||
-	    __put_user(txc.jitter, &utp->jitter) ||
-	    __put_user(txc.shift, &utp->shift) ||
-	    __put_user(txc.stabil, &utp->stabil) ||
-	    __put_user(txc.jitcnt, &utp->jitcnt) ||
-	    __put_user(txc.calcnt, &utp->calcnt) ||
-	    __put_user(txc.errcnt, &utp->errcnt) ||
-	    __put_user(txc.stbcnt, &utp->stbcnt))
-		ret = -EFAULT;
-
-	return ret;
-}
-
 /* This is just a version for 32-bit applications which does
  * not force O_LARGEFILE on.
  */
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index c3adb7a..3b250f2 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -63,7 +63,7 @@
 /*200*/	.word sys32_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir
 	.word sys32_readahead, sys32_socketcall, sys32_syslog, sys32_lookup_dcookie, sys32_fadvise64
 /*210*/	.word sys32_fadvise64_64, sys32_tgkill, sys32_waitpid, sys_swapoff, sys32_sysinfo
-	.word sys32_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, sys32_adjtimex
+	.word sys32_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, compat_sys_adjtimex
 /*220*/	.word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid
 	.word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16
 /*230*/	.word sys32_select, compat_sys_time, sys_nis_syscall, compat_sys_stime, compat_sys_statfs64
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 7d61f1b..e55b5c6 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -641,23 +641,8 @@
 		mon = MSTK_REG_MONTH(mregs);
 		year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
 	} else {
-		int i;
-
 		/* Dallas 12887 RTC chip. */
 
-		/* Stolen from arch/i386/kernel/time.c, see there for
-		 * credits and descriptive comments.
-		 */
-		for (i = 0; i < 1000000; i++) {
-			if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-				break;
-			udelay(10);
-		}
-		for (i = 0; i < 1000000; i++) {
-			if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-				break;
-			udelay(10);
-		}
 		do {
 			sec  = CMOS_READ(RTC_SECONDS);
 			min  = CMOS_READ(RTC_MINUTES);
@@ -666,6 +651,7 @@
 			mon  = CMOS_READ(RTC_MONTH);
 			year = CMOS_READ(RTC_YEAR);
 		} while (sec != CMOS_READ(RTC_SECONDS));
+
 		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
 			BCD_TO_BIN(sec);
 			BCD_TO_BIN(min);
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index df612e4..ff090bb 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -43,18 +43,19 @@
 #include <linux/kmod.h>
 #endif
 
-struct notifier_block *sparc64die_chain;
-static DEFINE_SPINLOCK(die_notifier_lock);
+ATOMIC_NOTIFIER_HEAD(sparc64die_chain);
 
 int register_die_notifier(struct notifier_block *nb)
 {
-	int err = 0;
-	unsigned long flags;
-	spin_lock_irqsave(&die_notifier_lock, flags);
-	err = notifier_chain_register(&sparc64die_chain, nb);
-	spin_unlock_irqrestore(&die_notifier_lock, flags);
-	return err;
+	return atomic_notifier_chain_register(&sparc64die_chain, nb);
 }
+EXPORT_SYMBOL(register_die_notifier);
+
+int unregister_die_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&sparc64die_chain, nb);
+}
+EXPORT_SYMBOL(unregister_die_notifier);
 
 /* When an irrecoverable trap occurs at tl > 0, the trap entry
  * code logs the trap state registers at every level in the trap
diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile
index 8812ded..4a725d8 100644
--- a/arch/sparc64/lib/Makefile
+++ b/arch/sparc64/lib/Makefile
@@ -14,6 +14,6 @@
 	 NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o NGpatch.o \
 	 NGpage.o NGbzero.o \
 	 copy_in_user.o user_fixup.o memmove.o \
-	 mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o
+	 mcount.o ipcsum.o rwsem.o xor.o delay.o
 
 obj-y += iomap.o
diff --git a/arch/sparc64/lib/find_bit.c b/arch/sparc64/lib/find_bit.c
deleted file mode 100644
index 6059557..0000000
--- a/arch/sparc64/lib/find_bit.c
+++ /dev/null
@@ -1,127 +0,0 @@
-#include <linux/bitops.h>
-
-/**
- * find_next_bit - find the next set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
-				unsigned long offset)
-{
-	const unsigned long *p = addr + (offset >> 6);
-	unsigned long result = offset & ~63UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 63UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp &= (~0UL << offset);
-		if (size < 64)
-			goto found_first;
-		if (tmp)
-			goto found_middle;
-		size -= 64;
-		result += 64;
-	}
-	while (size & ~63UL) {
-		if ((tmp = *(p++)))
-			goto found_middle;
-		result += 64;
-		size -= 64;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp &= (~0UL >> (64 - size));
-	if (tmp == 0UL)        /* Are any bits set? */
-		return result + size; /* Nope. */
-found_middle:
-	return result + __ffs(tmp);
-}
-
-/* find_next_zero_bit() finds the first zero bit in a bit string of length
- * 'size' bits, starting the search at bit 'offset'. This is largely based
- * on Linus's ALPHA routines, which are pretty portable BTW.
- */
-
-unsigned long find_next_zero_bit(const unsigned long *addr,
-			unsigned long size, unsigned long offset)
-{
-	const unsigned long *p = addr + (offset >> 6);
-	unsigned long result = offset & ~63UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 63UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (64-offset);
-		if (size < 64)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 64;
-		result += 64;
-	}
-	while (size & ~63UL) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += 64;
-		size -= 64;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp |= ~0UL << size;
-	if (tmp == ~0UL)        /* Are any bits zero? */
-		return result + size; /* Nope. */
-found_middle:
-	return result + ffz(tmp);
-}
-
-unsigned long find_next_zero_le_bit(unsigned long *addr, unsigned long size, unsigned long offset)
-{
-	unsigned long *p = addr + (offset >> 6);
-	unsigned long result = offset & ~63UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 63UL;
-	if(offset) {
-		tmp = __swab64p(p++);
-		tmp |= (~0UL >> (64-offset));
-		if(size < 64)
-			goto found_first;
-		if(~tmp)
-			goto found_middle;
-		size -= 64;
-		result += 64;
-	}
-	while(size & ~63) {
-		if(~(tmp = __swab64p(p++)))
-			goto found_middle;
-		result += 64;
-		size -= 64;
-	}
-	if(!size)
-		return result;
-	tmp = __swab64p(p);
-found_first:
-	tmp |= (~0UL << size);
-	if (tmp == ~0UL)        /* Are any bits zero? */
-		return result + size; /* Nope. */
-found_middle:
-	return result + ffz(tmp);
-}
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index d21ff32..0db2f7d 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -413,12 +413,12 @@
 #ifdef CONFIG_HUGETLB_PAGE
 	mm_rss -= (mm->context.huge_pte_count * (HPAGE_SIZE / PAGE_SIZE));
 #endif
-	if (unlikely(mm_rss >=
+	if (unlikely(mm_rss >
 		     mm->context.tsb_block[MM_TSB_BASE].tsb_rss_limit))
 		tsb_grow(mm, MM_TSB_BASE, mm_rss);
 #ifdef CONFIG_HUGETLB_PAGE
 	mm_rss = mm->context.huge_pte_count;
-	if (unlikely(mm_rss >=
+	if (unlikely(mm_rss >
 		     mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit))
 		tsb_grow(mm, MM_TSB_HUGE, mm_rss);
 #endif
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index 5982fe2..05fbb20 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -22,6 +22,9 @@
 config PCI
 	bool
 
+config PCMCIA
+	bool
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386
index ef79ed2..85e6a55 100644
--- a/arch/um/Kconfig.i386
+++ b/arch/um/Kconfig.i386
@@ -52,3 +52,8 @@
 config ARCH_REUSE_HOST_VSYSCALL_AREA
 	bool
 	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y
+
diff --git a/arch/um/Kconfig.x86_64 b/arch/um/Kconfig.x86_64
index aae19bc..f60e9e5 100644
--- a/arch/um/Kconfig.x86_64
+++ b/arch/um/Kconfig.x86_64
@@ -46,3 +46,8 @@
 config SMP_BROKEN
 	bool
 	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y
+
diff --git a/arch/um/Makefile b/arch/um/Makefile
index 8d14c7a..24790be 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -20,7 +20,7 @@
 
 # Have to precede the include because the included Makefiles reference them.
 SYMLINK_HEADERS := archparam.h system.h sigcontext.h processor.h ptrace.h \
-	module.h vm-flags.h elf.h ldt.h
+	module.h vm-flags.h elf.h host_ldt.h
 SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header))
 
 # XXX: The "os" symlink is only used by arch/um/include/os.h, which includes
@@ -129,7 +129,7 @@
 	-DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \
 	-DELF_FORMAT="$(ELF_FORMAT)" $(CPP_MODE-y) \
 	-DKERNEL_STACK_SIZE=$(STACK_SIZE) \
-	-DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap_fin.o
+	-DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap.o
 
 #The wrappers will select whether using "malloc" or the kernel allocator.
 LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
@@ -150,8 +150,7 @@
 	$(ARCH_DIR)/include/user_constants.h \
 	$(ARCH_DIR)/include/kern_constants.h $(ARCH_DIR)/Kconfig.arch
 
-MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \
-	$(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os
+MRPROPER_FILES += $(ARCH_SYMLINKS)
 
 archclean:
 	@find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
index 38df311..dfd88b6 100644
--- a/arch/um/Makefile-x86_64
+++ b/arch/um/Makefile-x86_64
@@ -1,7 +1,7 @@
 # Copyright 2003 - 2004 Pathscale, Inc
 # Released under the GPL
 
-libs-y += arch/um/sys-x86_64/
+core-y += arch/um/sys-x86_64/
 START := 0x60000000
 
 #We #undef __x86_64__ for kernelspace, not for userspace where
diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c
index a61b7b4..53d09ed 100644
--- a/arch/um/drivers/daemon_kern.c
+++ b/arch/um/drivers/daemon_kern.c
@@ -95,18 +95,7 @@
 static int register_daemon(void)
 {
 	register_transport(&daemon_transport);
-	return(1);
+	return 0;
 }
 
 __initcall(register_daemon);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c
index 49acb2b..d18a974 100644
--- a/arch/um/drivers/harddog_kern.c
+++ b/arch/um/drivers/harddog_kern.c
@@ -104,7 +104,7 @@
 
 extern int ping_watchdog(int fd);
 
-static ssize_t harddog_write(struct file *file, const char *data, size_t len,
+static ssize_t harddog_write(struct file *file, const char __user *data, size_t len,
 			     loff_t *ppos)
 {
 	/*
@@ -118,6 +118,7 @@
 static int harddog_ioctl(struct inode *inode, struct file *file,
 			 unsigned int cmd, unsigned long arg)
 {
+	void __user *argp= (void __user *)arg;
 	static struct watchdog_info ident = {
 		WDIOC_SETTIMEOUT,
 		0,
@@ -127,13 +128,12 @@
 		default:
 			return -ENOTTY;
 		case WDIOC_GETSUPPORT:
-			if(copy_to_user((struct harddog_info *)arg, &ident,
-					sizeof(ident)))
+			if(copy_to_user(argp, &ident, sizeof(ident)))
 				return -EFAULT;
 			return 0;
 		case WDIOC_GETSTATUS:
 		case WDIOC_GETBOOTSTATUS:
-			return put_user(0,(int *)arg);
+			return put_user(0,(int __user *)argp);
 		case WDIOC_KEEPALIVE:
 			return(ping_watchdog(harddog_out_fd));
 	}
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index 59602b8..37232f9 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -67,8 +67,8 @@
 
 /* /dev/dsp file operations */
 
-static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, 
-			      loff_t *ppos)
+static ssize_t hostaudio_read(struct file *file, char __user *buffer,
+			      size_t count, loff_t *ppos)
 {
         struct hostaudio_state *state = file->private_data;
 	void *kbuf;
@@ -94,7 +94,7 @@
 	return(err);
 }
 
-static ssize_t hostaudio_write(struct file *file, const char *buffer, 
+static ssize_t hostaudio_write(struct file *file, const char __user *buffer,
 			       size_t count, loff_t *ppos)
 {
         struct hostaudio_state *state = file->private_data;
@@ -152,7 +152,7 @@
 	case SNDCTL_DSP_CHANNELS:
 	case SNDCTL_DSP_SUBDIVIDE:
 	case SNDCTL_DSP_SETFRAGMENT:
-		if(get_user(data, (int *) arg))
+		if(get_user(data, (int __user *) arg))
 			return(-EFAULT);
 		break;
 	default:
@@ -168,7 +168,7 @@
 	case SNDCTL_DSP_CHANNELS:
 	case SNDCTL_DSP_SUBDIVIDE:
 	case SNDCTL_DSP_SETFRAGMENT:
-		if(put_user(data, (int *) arg))
+		if(put_user(data, (int __user *) arg))
 			return(-EFAULT);
 		break;
 	default:
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
index c9b078f..3a7af18 100644
--- a/arch/um/drivers/mcast_kern.c
+++ b/arch/um/drivers/mcast_kern.c
@@ -124,18 +124,7 @@
 static int register_mcast(void)
 {
 	register_transport(&mcast_transport);
-	return(1);
+	return 0;
 }
 
 __initcall(register_mcast);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 54388d1..28e3760 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -20,6 +20,8 @@
 #include "linux/namei.h"
 #include "linux/proc_fs.h"
 #include "linux/syscalls.h"
+#include "linux/list.h"
+#include "linux/mm.h"
 #include "linux/console.h"
 #include "asm/irq.h"
 #include "asm/uaccess.h"
@@ -347,6 +349,142 @@
 	return(NULL);
 }
 
+#define UNPLUGGED_PER_PAGE \
+	((PAGE_SIZE - sizeof(struct list_head)) / sizeof(unsigned long))
+
+struct unplugged_pages {
+	struct list_head list;
+	void *pages[UNPLUGGED_PER_PAGE];
+};
+
+static unsigned long long unplugged_pages_count = 0;
+static struct list_head unplugged_pages = LIST_HEAD_INIT(unplugged_pages);
+static int unplug_index = UNPLUGGED_PER_PAGE;
+
+static int mem_config(char *str)
+{
+	unsigned long long diff;
+	int err = -EINVAL, i, add;
+	char *ret;
+
+	if(str[0] != '=')
+		goto out;
+
+	str++;
+	if(str[0] == '-')
+		add = 0;
+	else if(str[0] == '+'){
+		add = 1;
+	}
+	else goto out;
+
+	str++;
+	diff = memparse(str, &ret);
+	if(*ret != '\0')
+		goto out;
+
+	diff /= PAGE_SIZE;
+
+	for(i = 0; i < diff; i++){
+		struct unplugged_pages *unplugged;
+		void *addr;
+
+		if(add){
+			if(list_empty(&unplugged_pages))
+				break;
+
+			unplugged = list_entry(unplugged_pages.next,
+					       struct unplugged_pages, list);
+			if(unplug_index > 0)
+				addr = unplugged->pages[--unplug_index];
+			else {
+				list_del(&unplugged->list);
+				addr = unplugged;
+				unplug_index = UNPLUGGED_PER_PAGE;
+			}
+
+			free_page((unsigned long) addr);
+			unplugged_pages_count--;
+		}
+		else {
+			struct page *page;
+
+			page = alloc_page(GFP_ATOMIC);
+			if(page == NULL)
+				break;
+
+			unplugged = page_address(page);
+			if(unplug_index == UNPLUGGED_PER_PAGE){
+				INIT_LIST_HEAD(&unplugged->list);
+				list_add(&unplugged->list, &unplugged_pages);
+				unplug_index = 0;
+			}
+			else {
+				struct list_head *entry = unplugged_pages.next;
+				addr = unplugged;
+
+				unplugged = list_entry(entry,
+						       struct unplugged_pages,
+						       list);
+				unplugged->pages[unplug_index++] = addr;
+				err = os_drop_memory(addr, PAGE_SIZE);
+				if(err)
+					printk("Failed to release memory - "
+					       "errno = %d\n", err);
+			}
+
+			unplugged_pages_count++;
+		}
+	}
+
+	err = 0;
+out:
+	return err;
+}
+
+static int mem_get_config(char *name, char *str, int size, char **error_out)
+{
+	char buf[sizeof("18446744073709551615")];
+	int len = 0;
+
+	sprintf(buf, "%ld", uml_physmem);
+	CONFIG_CHUNK(str, size, len, buf, 1);
+
+	return len;
+}
+
+static int mem_id(char **str, int *start_out, int *end_out)
+{
+	*start_out = 0;
+	*end_out = 0;
+
+	return 0;
+}
+
+static int mem_remove(int n)
+{
+	return -EBUSY;
+}
+
+static struct mc_device mem_mc = {
+	.name		= "mem",
+	.config		= mem_config,
+	.get_config	= mem_get_config,
+	.id		= mem_id,
+	.remove		= mem_remove,
+};
+
+static int mem_mc_init(void)
+{
+	if(can_drop_memory())
+		mconsole_register_dev(&mem_mc);
+	else printk("Can't release memory to the host - memory hotplug won't "
+		    "be supported\n");
+	return 0;
+}
+
+__initcall(mem_mc_init);
+
 #define CONFIG_BUF_SIZE 64
 
 static void mconsole_get_config(int (*get_config)(char *, char *, int,
@@ -478,7 +616,7 @@
 		return;
 
 	while(1){
-		n = min(len, ARRAY_SIZE(console_buf) - console_index);
+		n = min((size_t)len, ARRAY_SIZE(console_buf) - console_index);
 		strncpy(&console_buf[console_index], string, n);
 		console_index += n;
 		string += n;
@@ -762,7 +900,8 @@
 
 static int add_notifier(void)
 {
-	notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
+	atomic_notifier_chain_register(&panic_notifier_list,
+			&panic_exit_notifier);
 	return(0);
 }
 
diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c
index 07c80f2..466ff2c 100644
--- a/arch/um/drivers/pcap_kern.c
+++ b/arch/um/drivers/pcap_kern.c
@@ -106,18 +106,7 @@
 static int register_pcap(void)
 {
 	register_transport(&pcap_transport);
-	return(1);
+	return 0;
 }
 
 __initcall(register_pcap);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
index a62f5ef..163ee0d 100644
--- a/arch/um/drivers/slip_kern.c
+++ b/arch/um/drivers/slip_kern.c
@@ -93,18 +93,7 @@
 static int register_slip(void)
 {
 	register_transport(&slip_transport);
-	return(1);
+	return 0;
 }
 
 __initcall(register_slip);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c
index 33d7982..95e50c9 100644
--- a/arch/um/drivers/slirp_kern.c
+++ b/arch/um/drivers/slirp_kern.c
@@ -77,7 +77,7 @@
 	int i=0;
 
 	*init = ((struct slirp_init)
-		{ argw :		{ { "slirp", NULL  } } });
+		{ .argw = { { "slirp", NULL  } } });
 
 	str = split_if_spec(str, mac_out, NULL);
 
@@ -116,18 +116,7 @@
 static int register_slirp(void)
 {
 	register_transport(&slirp_transport);
-	return(1);
+	return 0;
 }
 
 __initcall(register_slirp);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index fa617e0..0897852 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
@@ -71,7 +71,7 @@
 	int error;
 };
 
-extern int open_ubd_file(char *file, struct openflags *openflags,
+extern int open_ubd_file(char *file, struct openflags *openflags, int shared,
 			 char **backing_file_out, int *bitmap_offset_out,
 			 unsigned long *bitmap_len_out, int *data_offset_out,
 			 int *create_cow_out);
@@ -137,7 +137,7 @@
 
 static struct gendisk *ubd_gendisk[MAX_DEV];
 static struct gendisk *fake_gendisk[MAX_DEV];
- 
+
 #ifdef CONFIG_BLK_DEV_UBD_SYNC
 #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
 					 .cl = 1 })
@@ -168,6 +168,7 @@
 	__u64 size;
 	struct openflags boot_openflags;
 	struct openflags openflags;
+	int shared;
 	int no_cow;
 	struct cow cow;
 	struct platform_device pdev;
@@ -189,6 +190,7 @@
 	.boot_openflags =	OPEN_FLAGS, \
 	.openflags =		OPEN_FLAGS, \
         .no_cow =               0, \
+	.shared =		0, \
         .cow =			DEFAULT_COW, \
 }
 
@@ -305,7 +307,7 @@
 		}
 		major = simple_strtoul(str, &end, 0);
 		if((*end != '\0') || (end == str)){
-			printk(KERN_ERR 
+			printk(KERN_ERR
 			       "ubd_setup : didn't parse major number\n");
 			return(1);
 		}
@@ -316,7 +318,7 @@
  			printk(KERN_ERR "Can't assign a fake major twice\n");
  			goto out1;
  		}
- 
+
  		fake_major = major;
 
 		printk(KERN_INFO "Setting extra ubd major number to %d\n",
@@ -351,7 +353,7 @@
 	if (index_out)
 		*index_out = n;
 
-	for (i = 0; i < 4; i++) {
+	for (i = 0; i < sizeof("rscd="); i++) {
 		switch (*str) {
 		case 'r':
 			flags.w = 0;
@@ -362,11 +364,14 @@
 		case 'd':
 			dev->no_cow = 1;
 			break;
+		case 'c':
+			dev->shared = 1;
+			break;
 		case '=':
 			str++;
 			goto break_loop;
 		default:
-			printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r,s or d)\n");
+			printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r, s, c, or d)\n");
 			goto out;
 		}
 		str++;
@@ -515,7 +520,7 @@
 		spin_unlock(&ubd_io_lock);
 		return;
 	}
-        
+
 	ubd_finish(rq, req.error);
 	reactivate_fd(thread_fd, UBD_IRQ);	
 	do_ubd_request(ubd_queue);
@@ -532,7 +537,7 @@
 
 void kill_io_thread(void)
 {
-	if(io_pid != -1) 
+	if(io_pid != -1)
 		os_kill_process(io_pid, 1);
 }
 
@@ -567,14 +572,15 @@
 	create_cow = 0;
 	create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
 	back_ptr = dev->no_cow ? NULL : &dev->cow.file;
-	dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr,
-				&dev->cow.bitmap_offset, &dev->cow.bitmap_len, 
-				&dev->cow.data_offset, create_ptr);
+	dev->fd = open_ubd_file(dev->file, &dev->openflags, dev->shared,
+				back_ptr, &dev->cow.bitmap_offset,
+				&dev->cow.bitmap_len, &dev->cow.data_offset,
+				create_ptr);
 
 	if((dev->fd == -ENOENT) && create_cow){
-		dev->fd = create_cow_file(dev->file, dev->cow.file, 
+		dev->fd = create_cow_file(dev->file, dev->cow.file,
 					  dev->openflags, 1 << 9, PAGE_SIZE,
-					  &dev->cow.bitmap_offset, 
+					  &dev->cow.bitmap_offset,
 					  &dev->cow.bitmap_len,
 					  &dev->cow.data_offset);
 		if(dev->fd >= 0){
@@ -598,16 +604,16 @@
 		}
 		flush_tlb_kernel_vm();
 
-		err = read_cow_bitmap(dev->fd, dev->cow.bitmap, 
-				      dev->cow.bitmap_offset, 
+		err = read_cow_bitmap(dev->fd, dev->cow.bitmap,
+				      dev->cow.bitmap_offset,
 				      dev->cow.bitmap_len);
 		if(err < 0)
 			goto error;
 
 		flags = dev->openflags;
 		flags.w = 0;
-		err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, 
-				    NULL, NULL);
+		err = open_ubd_file(dev->cow.file, &flags, dev->shared, NULL,
+				    NULL, NULL, NULL, NULL);
 		if(err < 0) goto error;
 		dev->cow.fd = err;
 	}
@@ -685,11 +691,11 @@
 	dev->size = ROUND_BLOCK(dev->size);
 
 	err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]);
-	if(err) 
+	if(err)
 		goto out_close;
- 
+
 	if(fake_major != MAJOR_NR)
-		ubd_new_disk(fake_major, dev->size, n, 
+		ubd_new_disk(fake_major, dev->size, n,
 			     &fake_gendisk[n]);
 
 	/* perhaps this should also be under the "if (fake_major)" above */
@@ -854,7 +860,7 @@
 			return -1;
 	}
 	platform_driver_register(&ubd_driver);
-	for (i = 0; i < MAX_DEV; i++) 
+	for (i = 0; i < MAX_DEV; i++)
 		ubd_add(i);
 	return 0;
 }
@@ -872,20 +878,20 @@
 		 * enough. So use anyway the io thread. */
 	}
 	stack = alloc_stack(0, 0);
-	io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), 
+	io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
 				 &thread_fd);
 	if(io_pid < 0){
-		printk(KERN_ERR 
+		printk(KERN_ERR
 		       "ubd : Failed to start I/O thread (errno = %d) - "
 		       "falling back to synchronous I/O\n", -io_pid);
 		io_pid = -1;
 		return(0);
 	}
-	err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, 
+	err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
 			     SA_INTERRUPT, "ubd", ubd_dev);
 	if(err != 0)
 		printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
-	return(err);
+	return 0;
 }
 
 device_initcall(ubd_driver_init);
@@ -978,7 +984,7 @@
 	if(req->op == UBD_READ) {
 		for(i = 0; i < req->length >> 9; i++){
 			if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
-				ubd_set_bit(i, (unsigned char *) 
+				ubd_set_bit(i, (unsigned char *)
 					    &req->sector_mask);
                 }
 	}
@@ -999,7 +1005,7 @@
 
 	/* This should be impossible now */
 	if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
-		printk("Write attempted on readonly ubd device %s\n", 
+		printk("Write attempted on readonly ubd device %s\n",
 		       disk->disk_name);
 		end_request(req, 0);
 		return(1);
@@ -1182,7 +1188,7 @@
 	return(0);
 }
 
-int open_ubd_file(char *file, struct openflags *openflags,
+int open_ubd_file(char *file, struct openflags *openflags, int shared,
 		  char **backing_file_out, int *bitmap_offset_out,
 		  unsigned long *bitmap_len_out, int *data_offset_out,
 		  int *create_cow_out)
@@ -1206,10 +1212,14 @@
 			return fd;
         }
 
-	err = os_lock_file(fd, openflags->w);
-	if(err < 0){
-		printk("Failed to lock '%s', err = %d\n", file, -err);
-		goto out_close;
+	if(shared)
+		printk("Not locking \"%s\" on the host\n", file);
+	else {
+		err = os_lock_file(fd, openflags->w);
+		if(err < 0){
+			printk("Failed to lock '%s', err = %d\n", file, -err);
+			goto out_close;
+		}
 	}
 
 	/* Succesful return case! */
@@ -1260,7 +1270,7 @@
 	int err, fd;
 
 	flags.c = 1;
-	fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL);
+	fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
 	if(fd < 0){
 		err = fd;
 		printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
diff --git a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h
index b61deb8..69a93c8 100644
--- a/arch/um/include/irq_user.h
+++ b/arch/um/include/irq_user.h
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
@@ -6,6 +6,17 @@
 #ifndef __IRQ_USER_H__
 #define __IRQ_USER_H__
 
+struct irq_fd {
+	struct irq_fd *next;
+	void *id;
+	int fd;
+	int type;
+	int irq;
+	int pid;
+	int events;
+	int current_events;
+};
+
 enum { IRQ_READ, IRQ_WRITE };
 
 extern void sigio_handler(int sig, union uml_pt_regs *regs);
@@ -16,8 +27,6 @@
 extern void deactivate_fd(int fd, int irqnum);
 extern int deactivate_all_fds(void);
 extern void forward_interrupts(int pid);
-extern void init_irq_signals(int on_sigstack);
-extern void forward_ipi(int fd, int pid);
 extern int activate_ipi(int fd, int pid);
 extern unsigned long irq_lock(void);
 extern void irq_unlock(unsigned long flags);
diff --git a/arch/um/include/kern.h b/arch/um/include/kern.h
index 7d223be..4ce3fc6 100644
--- a/arch/um/include/kern.h
+++ b/arch/um/include/kern.h
@@ -29,7 +29,7 @@
 extern int getgid(void);
 extern int pause(void);
 extern int write(int, const void *, int);
-extern int exit(int);
+extern void exit(int);
 extern int close(int);
 extern int read(unsigned int, char *, int);
 extern int pipe(int *);
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 07176d9..4255713 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -116,7 +116,11 @@
 extern struct task_struct *get_task(int pid, int require);
 extern void machine_halt(void);
 extern int is_syscall(unsigned long addr);
-extern void arch_switch(void);
+
+extern void arch_switch_to_tt(struct task_struct *from, struct task_struct *to);
+
+extern void arch_switch_to_skas(struct task_struct *from, struct task_struct *to);
+
 extern void free_irq(unsigned int, void *);
 extern int cpu(void);
 
diff --git a/arch/um/include/line.h b/arch/um/include/line.h
index 6f4d680..6ac0f82 100644
--- a/arch/um/include/line.h
+++ b/arch/um/include/line.h
@@ -58,23 +58,17 @@
 };
 
 #define LINE_INIT(str, d) \
-	{ init_str :	str, \
-	  init_pri :	INIT_STATIC, \
-	  valid :	1, \
-	  throttled :	0, \
-	  lock :	SPIN_LOCK_UNLOCKED, \
-	  buffer :	NULL, \
-	  head :	NULL, \
-	  tail :	NULL, \
-	  sigio :	0, \
-	  driver :	d, \
-	  have_irq :	0 }
+	{ .init_str =	str, \
+	  .init_pri =	INIT_STATIC, \
+	  .valid =	1, \
+	  .lock =	SPIN_LOCK_UNLOCKED, \
+	  .driver =	d }
 
 struct lines {
 	int num;
 };
 
-#define LINES_INIT(n) {  num :		n }
+#define LINES_INIT(n) {  .num =	n }
 
 extern void line_close(struct tty_struct *tty, struct file * filp);
 extern int line_open(struct line *lines, struct tty_struct *tty);
diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h
index a1064c5..a54514d 100644
--- a/arch/um/include/mem_user.h
+++ b/arch/um/include/mem_user.h
@@ -49,7 +49,6 @@
 extern unsigned long host_task_size;
 extern unsigned long task_size;
 
-extern void check_devanon(void);
 extern int init_mem_user(void);
 extern void setup_memory(void *entry);
 extern unsigned long find_iomem(char *driver, unsigned long *len_out);
diff --git a/arch/um/include/misc_constants.h b/arch/um/include/misc_constants.h
new file mode 100644
index 0000000..989bc08
--- /dev/null
+++ b/arch/um/include/misc_constants.h
@@ -0,0 +1,6 @@
+#ifndef __MISC_CONSTANT_H_
+#define __MISC_CONSTANT_H_
+
+#include <user_constants.h>
+
+#endif
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 2a1c64d..f88856c 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -12,6 +12,8 @@
 #include "sysdep/ptrace.h"
 #include "kern_util.h"
 #include "skas/mm_id.h"
+#include "irq_user.h"
+#include "sysdep/tls.h"
 
 #define OS_TYPE_FILE 1 
 #define OS_TYPE_DIR 2 
@@ -121,6 +123,7 @@
 	return(flags); 
 }
   
+/* file.c */
 extern int os_stat_file(const char *file_name, struct uml_stat *buf);
 extern int os_stat_fd(const int fd, struct uml_stat *buf);
 extern int os_access(const char *file, int mode);
@@ -156,10 +159,21 @@
 extern int os_file_type(char *file);
 extern int os_file_mode(char *file, struct openflags *mode_out);
 extern int os_lock_file(int fd, int excl);
+extern void os_flush_stdout(void);
+extern int os_stat_filesystem(char *path, long *bsize_out,
+			      long long *blocks_out, long long *bfree_out,
+			      long long *bavail_out, long long *files_out,
+			      long long *ffree_out, void *fsid_out,
+			      int fsid_size, long *namelen_out,
+			      long *spare_out);
+extern int os_change_dir(char *dir);
+extern int os_fchange_dir(int fd);
 
 /* start_up.c */
 extern void os_early_checks(void);
 extern int can_do_skas(void);
+extern void os_check_bugs(void);
+extern void check_host_supports_tls(int *supports_tls, int *tls_min);
 
 /* Make sure they are clear when running in TT mode. Required by
  * SEGV_MAYBE_FIXABLE */
@@ -193,11 +207,15 @@
 extern int os_protect_memory(void *addr, unsigned long len, 
 			     int r, int w, int x);
 extern int os_unmap_memory(void *addr, int len);
+extern int os_drop_memory(void *addr, int length);
+extern int can_drop_memory(void);
 extern void os_flush_stdout(void);
 
 /* tt.c
  * for tt mode only (will be deleted in future...)
  */
+extern void forward_ipi(int fd, int pid);
+extern void kill_child_dead(int pid);
 extern void stop(void);
 extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
 extern int protect_memory(unsigned long addr, unsigned long len,
@@ -220,8 +238,12 @@
 			     int stack_order);
 extern int helper_wait(int pid);
 
-/* umid.c */
 
+/* tls.c */
+extern int os_set_thread_area(user_desc_t *info, int pid);
+extern int os_get_thread_area(user_desc_t *info, int pid);
+
+/* umid.c */
 extern int umid_file_name(char *name, char *buf, int len);
 extern int set_umid(char *name);
 extern char *get_umid(void);
@@ -294,4 +316,26 @@
 extern void halt_skas(void);
 extern void reboot_skas(void);
 
+/* irq.c */
+extern int os_waiting_for_events(struct irq_fd *active_fds);
+extern int os_isatty(int fd);
+extern int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds);
+extern void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg,
+		struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2);
+extern void os_free_irq_later(struct irq_fd *active_fds,
+		int irq, void *dev_id);
+extern int os_get_pollfd(int i);
+extern void os_set_pollfd(int i, int fd);
+extern void os_set_ioignore(void);
+extern void init_irq_signals(int on_sigstack);
+
+/* sigio.c */
+extern void write_sigio_workaround(void);
+extern int add_sigio_fd(int fd, int read);
+extern int ignore_sigio_fd(int fd);
+
+/* skas/trap */
+extern void sig_handler_common_skas(int sig, void *sc_ptr);
+extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
+
 #endif
diff --git a/arch/um/include/sigio.h b/arch/um/include/sigio.h
index 37d76e2..fe99ea1 100644
--- a/arch/um/include/sigio.h
+++ b/arch/um/include/sigio.h
@@ -8,9 +8,6 @@
 
 extern int write_sigio_irq(int fd);
 extern int register_sigio_fd(int fd);
-extern int read_sigio_fd(int fd);
-extern int add_sigio_fd(int fd, int read);
-extern int ignore_sigio_fd(int fd);
 extern void sigio_lock(void);
 extern void sigio_unlock(void);
 
diff --git a/arch/um/include/skas/mode-skas.h b/arch/um/include/skas/mode-skas.h
index 260065c..8bc6916 100644
--- a/arch/um/include/skas/mode-skas.h
+++ b/arch/um/include/skas/mode-skas.h
@@ -13,7 +13,6 @@
 extern unsigned long exec_fpx_regs[];
 extern int have_fpx_regs;
 
-extern void sig_handler_common_skas(int sig, void *sc_ptr);
 extern void kill_off_processes_skas(void);
 
 #endif
diff --git a/arch/um/include/skas/skas.h b/arch/um/include/skas/skas.h
index 8635728..853b26f 100644
--- a/arch/um/include/skas/skas.h
+++ b/arch/um/include/skas/skas.h
@@ -17,7 +17,6 @@
 extern void new_thread_proc(void *stack, void (*handler)(int sig));
 extern void new_thread_handler(int sig);
 extern void handle_syscall(union uml_pt_regs *regs);
-extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
 extern int new_mm(unsigned long stack);
 extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
 extern long execute_syscall_skas(void *r);
diff --git a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h
index 7d3d202..052bb06 100644
--- a/arch/um/include/sysdep-i386/checksum.h
+++ b/arch/um/include/sysdep-i386/checksum.h
@@ -48,7 +48,8 @@
  */
 
 static __inline__
-unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst,
+unsigned int csum_partial_copy_from_user(const unsigned char __user *src,
+					 unsigned char *dst,
 					 int len, int sum, int *err_ptr)
 {
 	if(copy_from_user(dst, src, len)){
@@ -192,7 +193,7 @@
  */
 #define HAVE_CSUM_COPY_USER
 static __inline__ unsigned int csum_and_copy_to_user(const unsigned char *src,
-						     unsigned char *dst,
+						     unsigned char __user *dst,
 						     int len, int sum, int *err_ptr)
 {
 	if (access_ok(VERIFY_WRITE, dst, len)){
diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h
index c8ee955..6670cc9 100644
--- a/arch/um/include/sysdep-i386/ptrace.h
+++ b/arch/um/include/sysdep-i386/ptrace.h
@@ -14,7 +14,12 @@
 #define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long))
 #define MAX_REG_OFFSET (UM_FRAME_SIZE)
 
+#ifdef UML_CONFIG_PT_PROXY
 extern void update_debugregs(int seq);
+#else
+static inline void update_debugregs(int seq) {}
+#endif
+
 
 /* syscall emulation path in ptrace */
 
diff --git a/arch/um/include/sysdep-i386/tls.h b/arch/um/include/sysdep-i386/tls.h
new file mode 100644
index 0000000..918fd3c
--- /dev/null
+++ b/arch/um/include/sysdep-i386/tls.h
@@ -0,0 +1,32 @@
+#ifndef _SYSDEP_TLS_H
+#define _SYSDEP_TLS_H
+
+# ifndef __KERNEL__
+
+/* Change name to avoid conflicts with the original one from <asm/ldt.h>, which
+ * may be named user_desc (but in 2.4 and in header matching its API was named
+ * modify_ldt_ldt_s). */
+
+typedef struct um_dup_user_desc {
+	unsigned int  entry_number;
+	unsigned int  base_addr;
+	unsigned int  limit;
+	unsigned int  seg_32bit:1;
+	unsigned int  contents:2;
+	unsigned int  read_exec_only:1;
+	unsigned int  limit_in_pages:1;
+	unsigned int  seg_not_present:1;
+	unsigned int  useable:1;
+} user_desc_t;
+
+# else /* __KERNEL__ */
+
+#  include <asm/ldt.h>
+typedef struct user_desc user_desc_t;
+
+# endif /* __KERNEL__ */
+
+#define GDT_ENTRY_TLS_MIN_I386 6
+#define GDT_ENTRY_TLS_MIN_X86_64 12
+
+#endif /* _SYSDEP_TLS_H */
diff --git a/arch/um/include/sysdep-x86_64/tls.h b/arch/um/include/sysdep-x86_64/tls.h
new file mode 100644
index 0000000..35f19f2
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/tls.h
@@ -0,0 +1,29 @@
+#ifndef _SYSDEP_TLS_H
+#define _SYSDEP_TLS_H
+
+# ifndef __KERNEL__
+
+/* Change name to avoid conflicts with the original one from <asm/ldt.h>, which
+ * may be named user_desc (but in 2.4 and in header matching its API was named
+ * modify_ldt_ldt_s). */
+
+typedef struct um_dup_user_desc {
+	unsigned int  entry_number;
+	unsigned int  base_addr;
+	unsigned int  limit;
+	unsigned int  seg_32bit:1;
+	unsigned int  contents:2;
+	unsigned int  read_exec_only:1;
+	unsigned int  limit_in_pages:1;
+	unsigned int  seg_not_present:1;
+	unsigned int  useable:1;
+	unsigned int  lm:1;
+} user_desc_t;
+
+# else /* __KERNEL__ */
+
+#  include <asm/ldt.h>
+typedef struct user_desc user_desc_t;
+
+# endif /* __KERNEL__ */
+#endif /* _SYSDEP_TLS_H */
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h
index a6f1f17..fe0c29b 100644
--- a/arch/um/include/user_util.h
+++ b/arch/um/include/user_util.h
@@ -8,6 +8,9 @@
 
 #include "sysdep/ptrace.h"
 
+/* Copied from kernel.h */
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
 #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
 
 extern int mode_tt;
@@ -31,7 +34,7 @@
 extern unsigned long uml_reserved;
 extern unsigned long end_vm;
 extern unsigned long start_vm;
-extern unsigned long highmem;
+extern unsigned long long highmem;
 
 extern char host_info[];
 
@@ -58,7 +61,6 @@
 extern void kill_child_dead(int pid);
 extern int cont(int pid);
 extern void check_sigio(void);
-extern void write_sigio_workaround(void);
 extern void arch_check_bugs(void);
 extern int cpu_feature(char *what, char *buf, int len);
 extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index 693018b..fe08971 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -7,23 +7,20 @@
 clean-files :=
 
 obj-y = config.o exec_kern.o exitcode.o \
-	init_task.o irq.o irq_user.o ksyms.o mem.o physmem.o \
-	process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \
+	init_task.o irq.o ksyms.o mem.o physmem.o \
+	process_kern.o ptrace.o reboot.o resource.o sigio_kern.o \
 	signal_kern.o smp.o syscall_kern.o sysrq.o \
 	time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o
 
 obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
 obj-$(CONFIG_GPROF)	+= gprof_syms.o
 obj-$(CONFIG_GCOV)	+= gmon_syms.o
-obj-$(CONFIG_TTY_LOG)	+= tty_log.o
 obj-$(CONFIG_SYSCALL_DEBUG) += syscall.o
 
 obj-$(CONFIG_MODE_TT) += tt/
 obj-$(CONFIG_MODE_SKAS) += skas/
 
-user-objs-$(CONFIG_TTY_LOG) += tty_log.o
-
-USER_OBJS := $(user-objs-y) config.o tty_log.o
+USER_OBJS := config.o
 
 include arch/um/scripts/Makefile.rules
 
diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c
index c264e1c..c0cb627 100644
--- a/arch/um/kernel/exec_kern.c
+++ b/arch/um/kernel/exec_kern.c
@@ -22,6 +22,7 @@
 
 void flush_thread(void)
 {
+	arch_flush_thread(&current->thread.arch);
 	CHOOSE_MODE(flush_thread_tt(), flush_thread_skas());
 }
 
@@ -30,8 +31,6 @@
 	CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp);
 }
 
-extern void log_exec(char **argv, void *tty);
-
 static long execve1(char *file, char __user * __user *argv,
 		    char __user *__user *env)
 {
@@ -60,14 +59,14 @@
 	return(err);
 }
 
-long sys_execve(char *file, char __user *__user *argv,
+long sys_execve(char __user *file, char __user *__user *argv,
 		char __user *__user *env)
 {
 	long error;
 	char *filename;
 
 	lock_kernel();
-	filename = getname((char __user *) file);
+	filename = getname(file);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename)) goto out;
 	error = execve1(filename, argv, env);
@@ -76,14 +75,3 @@
 	unlock_kernel();
 	return(error);
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index bbf94bf..c39ea3a 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -31,6 +31,8 @@
 #include "irq_user.h"
 #include "irq_kern.h"
 #include "os.h"
+#include "sigio.h"
+#include "misc_constants.h"
 
 /*
  * Generic, controller-independent functions:
@@ -77,6 +79,298 @@
 	return 0;
 }
 
+struct irq_fd *active_fds = NULL;
+static struct irq_fd **last_irq_ptr = &active_fds;
+
+extern void free_irqs(void);
+
+void sigio_handler(int sig, union uml_pt_regs *regs)
+{
+	struct irq_fd *irq_fd;
+	int n;
+
+	if(smp_sigio_handler()) return;
+	while(1){
+		n = os_waiting_for_events(active_fds);
+		if (n <= 0) {
+			if(n == -EINTR) continue;
+			else break;
+		}
+
+		for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
+			if(irq_fd->current_events != 0){
+				irq_fd->current_events = 0;
+				do_IRQ(irq_fd->irq, regs);
+			}
+		}
+	}
+
+	free_irqs();
+}
+
+static void maybe_sigio_broken(int fd, int type)
+{
+	if(os_isatty(fd)){
+		if((type == IRQ_WRITE) && !pty_output_sigio){
+			write_sigio_workaround();
+			add_sigio_fd(fd, 0);
+		}
+		else if((type == IRQ_READ) && !pty_close_sigio){
+			write_sigio_workaround();
+			add_sigio_fd(fd, 1);
+		}
+	}
+}
+
+
+int activate_fd(int irq, int fd, int type, void *dev_id)
+{
+	struct pollfd *tmp_pfd;
+	struct irq_fd *new_fd, *irq_fd;
+	unsigned long flags;
+	int pid, events, err, n;
+
+	pid = os_getpid();
+	err = os_set_fd_async(fd, pid);
+	if(err < 0)
+		goto out;
+
+	new_fd = um_kmalloc(sizeof(*new_fd));
+	err = -ENOMEM;
+	if(new_fd == NULL)
+		goto out;
+
+	if(type == IRQ_READ) events = UM_POLLIN | UM_POLLPRI;
+	else events = UM_POLLOUT;
+	*new_fd = ((struct irq_fd) { .next  		= NULL,
+				     .id 		= dev_id,
+				     .fd 		= fd,
+				     .type 		= type,
+				     .irq 		= irq,
+				     .pid  		= pid,
+				     .events 		= events,
+				     .current_events 	= 0 } );
+
+	/* Critical section - locked by a spinlock because this stuff can
+	 * be changed from interrupt handlers.  The stuff above is done
+	 * outside the lock because it allocates memory.
+	 */
+
+	/* Actually, it only looks like it can be called from interrupt
+	 * context.  The culprit is reactivate_fd, which calls
+	 * maybe_sigio_broken, which calls write_sigio_workaround,
+	 * which calls activate_fd.  However, write_sigio_workaround should
+	 * only be called once, at boot time.  That would make it clear that
+	 * this is called only from process context, and can be locked with
+	 * a semaphore.
+	 */
+	flags = irq_lock();
+	for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
+		if((irq_fd->fd == fd) && (irq_fd->type == type)){
+			printk("Registering fd %d twice\n", fd);
+			printk("Irqs : %d, %d\n", irq_fd->irq, irq);
+			printk("Ids : 0x%p, 0x%p\n", irq_fd->id, dev_id);
+			goto out_unlock;
+		}
+	}
+
+	/*-------------*/
+	if(type == IRQ_WRITE)
+		fd = -1;
+
+	tmp_pfd = NULL;
+	n = 0;
+
+	while(1){
+		n = os_create_pollfd(fd, events, tmp_pfd, n);
+		if (n == 0)
+			break;
+
+		/* n > 0
+		 * It means we couldn't put new pollfd to current pollfds
+		 * and tmp_fds is NULL or too small for new pollfds array.
+		 * Needed size is equal to n as minimum.
+		 *
+		 * Here we have to drop the lock in order to call
+		 * kmalloc, which might sleep.
+		 * If something else came in and changed the pollfds array
+		 * so we will not be able to put new pollfd struct to pollfds
+		 * then we free the buffer tmp_fds and try again.
+		 */
+		irq_unlock(flags);
+		if (tmp_pfd != NULL) {
+			kfree(tmp_pfd);
+			tmp_pfd = NULL;
+		}
+
+		tmp_pfd = um_kmalloc(n);
+		if (tmp_pfd == NULL)
+			goto out_kfree;
+
+		flags = irq_lock();
+	}
+	/*-------------*/
+
+	*last_irq_ptr = new_fd;
+	last_irq_ptr = &new_fd->next;
+
+	irq_unlock(flags);
+
+	/* This calls activate_fd, so it has to be outside the critical
+	 * section.
+	 */
+	maybe_sigio_broken(fd, type);
+
+	return(0);
+
+ out_unlock:
+	irq_unlock(flags);
+ out_kfree:
+	kfree(new_fd);
+ out:
+	return(err);
+}
+
+static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
+{
+	unsigned long flags;
+
+	flags = irq_lock();
+	os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr);
+	irq_unlock(flags);
+}
+
+struct irq_and_dev {
+	int irq;
+	void *dev;
+};
+
+static int same_irq_and_dev(struct irq_fd *irq, void *d)
+{
+	struct irq_and_dev *data = d;
+
+	return((irq->irq == data->irq) && (irq->id == data->dev));
+}
+
+void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
+{
+	struct irq_and_dev data = ((struct irq_and_dev) { .irq  = irq,
+							  .dev  = dev });
+
+	free_irq_by_cb(same_irq_and_dev, &data);
+}
+
+static int same_fd(struct irq_fd *irq, void *fd)
+{
+	return(irq->fd == *((int *) fd));
+}
+
+void free_irq_by_fd(int fd)
+{
+	free_irq_by_cb(same_fd, &fd);
+}
+
+static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
+{
+	struct irq_fd *irq;
+	int i = 0;
+	int fdi;
+
+	for(irq=active_fds; irq != NULL; irq = irq->next){
+		if((irq->fd == fd) && (irq->irq == irqnum)) break;
+		i++;
+	}
+	if(irq == NULL){
+		printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
+		goto out;
+	}
+	fdi = os_get_pollfd(i);
+	if((fdi != -1) && (fdi != fd)){
+		printk("find_irq_by_fd - mismatch between active_fds and "
+		       "pollfds, fd %d vs %d, need %d\n", irq->fd,
+		       fdi, fd);
+		irq = NULL;
+		goto out;
+	}
+	*index_out = i;
+ out:
+	return(irq);
+}
+
+void reactivate_fd(int fd, int irqnum)
+{
+	struct irq_fd *irq;
+	unsigned long flags;
+	int i;
+
+	flags = irq_lock();
+	irq = find_irq_by_fd(fd, irqnum, &i);
+	if(irq == NULL){
+		irq_unlock(flags);
+		return;
+	}
+	os_set_pollfd(i, irq->fd);
+	irq_unlock(flags);
+
+	/* This calls activate_fd, so it has to be outside the critical
+	 * section.
+	 */
+	maybe_sigio_broken(fd, irq->type);
+}
+
+void deactivate_fd(int fd, int irqnum)
+{
+	struct irq_fd *irq;
+	unsigned long flags;
+	int i;
+
+	flags = irq_lock();
+	irq = find_irq_by_fd(fd, irqnum, &i);
+	if(irq == NULL)
+		goto out;
+	os_set_pollfd(i, -1);
+ out:
+	irq_unlock(flags);
+}
+
+int deactivate_all_fds(void)
+{
+	struct irq_fd *irq;
+	int err;
+
+	for(irq=active_fds;irq != NULL;irq = irq->next){
+		err = os_clear_fd_async(irq->fd);
+		if(err)
+			return(err);
+	}
+	/* If there is a signal already queued, after unblocking ignore it */
+	os_set_ioignore();
+
+	return(0);
+}
+
+void forward_interrupts(int pid)
+{
+	struct irq_fd *irq;
+	unsigned long flags;
+	int err;
+
+	flags = irq_lock();
+	for(irq=active_fds;irq != NULL;irq = irq->next){
+		err = os_set_owner(irq->fd, pid);
+		if(err < 0){
+			/* XXX Just remove the irq rather than
+			 * print out an infinite stream of these
+			 */
+			printk("Failed to forward %d to pid %d, err = %d\n",
+			       irq->fd, pid, -err);
+		}
+
+		irq->pid = pid;
+	}
+	irq_unlock(flags);
+}
+
 /*
  * do_IRQ handles all normal device IRQ's (the special
  * SMP cross-CPU interrupts have their own specific
diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
deleted file mode 100644
index 0e32f5f..0000000
--- a/arch/um/kernel/irq_user.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/* 
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/poll.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include "user_util.h"
-#include "kern_util.h"
-#include "user.h"
-#include "process.h"
-#include "sigio.h"
-#include "irq_user.h"
-#include "os.h"
-
-struct irq_fd {
-	struct irq_fd *next;
-	void *id;
-	int fd;
-	int type;
-	int irq;
-	int pid;
-	int events;
-	int current_events;
-};
-
-static struct irq_fd *active_fds = NULL;
-static struct irq_fd **last_irq_ptr = &active_fds;
-
-static struct pollfd *pollfds = NULL;
-static int pollfds_num = 0;
-static int pollfds_size = 0;
-
-extern int io_count, intr_count;
-
-extern void free_irqs(void);
-
-void sigio_handler(int sig, union uml_pt_regs *regs)
-{
-	struct irq_fd *irq_fd;
-	int i, n;
-
-	if(smp_sigio_handler()) return;
-	while(1){
-		n = poll(pollfds, pollfds_num, 0);
-		if(n < 0){
-			if(errno == EINTR) continue;
-			printk("sigio_handler : poll returned %d, "
-			       "errno = %d\n", n, errno);
-			break;
-		}
-		if(n == 0) break;
-
-		irq_fd = active_fds;
-		for(i = 0; i < pollfds_num; i++){
-			if(pollfds[i].revents != 0){
-				irq_fd->current_events = pollfds[i].revents;
-				pollfds[i].fd = -1;
-			}
-			irq_fd = irq_fd->next;
-		}
-
-		for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
-			if(irq_fd->current_events != 0){
-				irq_fd->current_events = 0;
-				do_IRQ(irq_fd->irq, regs);
-			}
-		}
-	}
-
-	free_irqs();
-}
-
-int activate_ipi(int fd, int pid)
-{
-	return(os_set_fd_async(fd, pid));
-}
-
-static void maybe_sigio_broken(int fd, int type)
-{
-	if(isatty(fd)){
-		if((type == IRQ_WRITE) && !pty_output_sigio){
-			write_sigio_workaround();
-			add_sigio_fd(fd, 0);
-		}
-		else if((type == IRQ_READ) && !pty_close_sigio){
-			write_sigio_workaround();
-			add_sigio_fd(fd, 1);			
-		}
-	}
-}
-
-int activate_fd(int irq, int fd, int type, void *dev_id)
-{
-	struct pollfd *tmp_pfd;
-	struct irq_fd *new_fd, *irq_fd;
-	unsigned long flags;
-	int pid, events, err, n, size;
-
-	pid = os_getpid();
-	err = os_set_fd_async(fd, pid);
-	if(err < 0)
-		goto out;
-
-	new_fd = um_kmalloc(sizeof(*new_fd));
-	err = -ENOMEM;
-	if(new_fd == NULL)
-		goto out;
-
-	if(type == IRQ_READ) events = POLLIN | POLLPRI;
-	else events = POLLOUT;
-	*new_fd = ((struct irq_fd) { .next  		= NULL,
-				     .id 		= dev_id,
-				     .fd 		= fd,
-				     .type 		= type,
-				     .irq 		= irq,
-				     .pid  		= pid,
-				     .events 		= events,
-				     .current_events 	= 0 } );
-
-	/* Critical section - locked by a spinlock because this stuff can
-	 * be changed from interrupt handlers.  The stuff above is done 
-	 * outside the lock because it allocates memory.
-	 */
-
-	/* Actually, it only looks like it can be called from interrupt
-	 * context.  The culprit is reactivate_fd, which calls 
-	 * maybe_sigio_broken, which calls write_sigio_workaround,
-	 * which calls activate_fd.  However, write_sigio_workaround should
-	 * only be called once, at boot time.  That would make it clear that
-	 * this is called only from process context, and can be locked with
-	 * a semaphore.
-	 */
-	flags = irq_lock();
-	for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
-		if((irq_fd->fd == fd) && (irq_fd->type == type)){
-			printk("Registering fd %d twice\n", fd);
-			printk("Irqs : %d, %d\n", irq_fd->irq, irq);
-			printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id);
-			goto out_unlock;
-		}
-	}
-
-	n = pollfds_num;
-	if(n == pollfds_size){
-		while(1){
-			/* Here we have to drop the lock in order to call 
-			 * kmalloc, which might sleep.  If something else
-			 * came in and changed the pollfds array, we free
-			 * the buffer and try again.
-			 */
-			irq_unlock(flags);
-			size = (pollfds_num + 1) * sizeof(pollfds[0]);
-			tmp_pfd = um_kmalloc(size);
-			flags = irq_lock();
-			if(tmp_pfd == NULL)
-				goto out_unlock;
-			if(n == pollfds_size)
-				break;
-			kfree(tmp_pfd);
-		}
-		if(pollfds != NULL){
-			memcpy(tmp_pfd, pollfds,
-			       sizeof(pollfds[0]) * pollfds_size);
-			kfree(pollfds);
-		}
-		pollfds = tmp_pfd;
-		pollfds_size++;
-	}
-
-	if(type == IRQ_WRITE) 
-		fd = -1;
-
-	pollfds[pollfds_num] = ((struct pollfd) { .fd 	= fd,
-						  .events 	= events,
-						  .revents 	= 0 });
-	pollfds_num++;
-
-	*last_irq_ptr = new_fd;
-	last_irq_ptr = &new_fd->next;
-
-	irq_unlock(flags);
-
-	/* This calls activate_fd, so it has to be outside the critical
-	 * section.
-	 */
-	maybe_sigio_broken(fd, type);
-
-	return(0);
-
- out_unlock:
-	irq_unlock(flags);
-	kfree(new_fd);
- out:
-	return(err);
-}
-
-static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
-{
-	struct irq_fd **prev;
-	unsigned long flags;
-	int i = 0;
-
-	flags = irq_lock();
-	prev = &active_fds;
-	while(*prev != NULL){
-		if((*test)(*prev, arg)){
-			struct irq_fd *old_fd = *prev;
-			if((pollfds[i].fd != -1) && 
-			   (pollfds[i].fd != (*prev)->fd)){
-				printk("free_irq_by_cb - mismatch between "
-				       "active_fds and pollfds, fd %d vs %d\n",
-				       (*prev)->fd, pollfds[i].fd);
-				goto out;
-			}
-
-			pollfds_num--;
-
-			/* This moves the *whole* array after pollfds[i] (though
-			 * it doesn't spot as such)! */
-
-			memmove(&pollfds[i], &pollfds[i + 1],
-			       (pollfds_num - i) * sizeof(pollfds[0]));
-
-			if(last_irq_ptr == &old_fd->next) 
-				last_irq_ptr = prev;
-			*prev = (*prev)->next;
-			if(old_fd->type == IRQ_WRITE) 
-				ignore_sigio_fd(old_fd->fd);
-			kfree(old_fd);
-			continue;
-		}
-		prev = &(*prev)->next;
-		i++;
-	}
- out:
-	irq_unlock(flags);
-}
-
-struct irq_and_dev {
-	int irq;
-	void *dev;
-};
-
-static int same_irq_and_dev(struct irq_fd *irq, void *d)
-{
-	struct irq_and_dev *data = d;
-
-	return((irq->irq == data->irq) && (irq->id == data->dev));
-}
-
-void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
-{
-	struct irq_and_dev data = ((struct irq_and_dev) { .irq  = irq,
-							  .dev  = dev });
-
-	free_irq_by_cb(same_irq_and_dev, &data);
-}
-
-static int same_fd(struct irq_fd *irq, void *fd)
-{
-	return(irq->fd == *((int *) fd));
-}
-
-void free_irq_by_fd(int fd)
-{
-	free_irq_by_cb(same_fd, &fd);
-}
-
-static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
-{
-	struct irq_fd *irq;
-	int i = 0;
-
-	for(irq=active_fds; irq != NULL; irq = irq->next){
-		if((irq->fd == fd) && (irq->irq == irqnum)) break;
-		i++;
-	}
-	if(irq == NULL){
-		printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
-		goto out;
-	}
-	if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){
-		printk("find_irq_by_fd - mismatch between active_fds and "
-		       "pollfds, fd %d vs %d, need %d\n", irq->fd, 
-		       pollfds[i].fd, fd);
-		irq = NULL;
-		goto out;
-	}
-	*index_out = i;
- out:
-	return(irq);
-}
-
-void reactivate_fd(int fd, int irqnum)
-{
-	struct irq_fd *irq;
-	unsigned long flags;
-	int i;
-
-	flags = irq_lock();
-	irq = find_irq_by_fd(fd, irqnum, &i);
-	if(irq == NULL){
-		irq_unlock(flags);
-		return;
-	}
-
-	pollfds[i].fd = irq->fd;
-
-	irq_unlock(flags);
-
-	/* This calls activate_fd, so it has to be outside the critical
-	 * section.
-	 */
-	maybe_sigio_broken(fd, irq->type);
-}
-
-void deactivate_fd(int fd, int irqnum)
-{
-	struct irq_fd *irq;
-	unsigned long flags;
-	int i;
-
-	flags = irq_lock();
-	irq = find_irq_by_fd(fd, irqnum, &i);
-	if(irq == NULL)
-		goto out;
-	pollfds[i].fd = -1;
- out:
-	irq_unlock(flags);
-}
-
-int deactivate_all_fds(void)
-{
-	struct irq_fd *irq;
-	int err;
-
-	for(irq=active_fds;irq != NULL;irq = irq->next){
-		err = os_clear_fd_async(irq->fd);
-		if(err)
-			return(err);
-	}
-	/* If there is a signal already queued, after unblocking ignore it */
-	set_handler(SIGIO, SIG_IGN, 0, -1);
-
-	return(0);
-}
-
-void forward_ipi(int fd, int pid)
-{
-	int err;
-
-	err = os_set_owner(fd, pid);
-	if(err < 0)
-		printk("forward_ipi: set_owner failed, fd = %d, me = %d, "
-		       "target = %d, err = %d\n", fd, os_getpid(), pid, -err);
-}
-
-void forward_interrupts(int pid)
-{
-	struct irq_fd *irq;
-	unsigned long flags;
-	int err;
-
-	flags = irq_lock();
-	for(irq=active_fds;irq != NULL;irq = irq->next){
-		err = os_set_owner(irq->fd, pid);
-		if(err < 0){
-			/* XXX Just remove the irq rather than
-			 * print out an infinite stream of these
-			 */
-			printk("Failed to forward %d to pid %d, err = %d\n",
-			       irq->fd, pid, -err);
-		}
-
-		irq->pid = pid;
-	}
-	irq_unlock(flags);
-}
-
-void init_irq_signals(int on_sigstack)
-{
-	__sighandler_t h;
-	int flags;
-
-	flags = on_sigstack ? SA_ONSTACK : 0;
-	if(timer_irq_inited) h = (__sighandler_t) alarm_handler;
-	else h = boot_timer_handler;
-
-	set_handler(SIGVTALRM, h, flags | SA_RESTART, 
-		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1);
-	set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
-		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
-	signal(SIGWINCH, SIG_IGN);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 92cce96..44e41a3 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -30,7 +30,7 @@
 unsigned long *empty_zero_page = NULL;
 unsigned long *empty_bad_page = NULL;
 pgd_t swapper_pg_dir[PTRS_PER_PGD];
-unsigned long highmem;
+unsigned long long highmem;
 int kmalloc_ok = 0;
 
 static unsigned long brk_end;
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index 0e65340..0500800 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -9,6 +9,7 @@
 #include "linux/vmalloc.h"
 #include "linux/bootmem.h"
 #include "linux/module.h"
+#include "linux/pfn.h"
 #include "asm/types.h"
 #include "asm/pgtable.h"
 #include "kern_util.h"
@@ -316,8 +317,6 @@
 	}
 }
 
-#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-
 extern int __syscall_stub_start, __binary_start;
 
 void setup_physmem(unsigned long start, unsigned long reserve_end,
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
index 3113cab..f6a5a50 100644
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process_kern.c
@@ -156,9 +156,25 @@
 		unsigned long stack_top, struct task_struct * p, 
 		struct pt_regs *regs)
 {
+	int ret;
+
 	p->thread = (struct thread_struct) INIT_THREAD;
-	return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, 
-				clone_flags, sp, stack_top, p, regs));
+	ret = CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr,
+				clone_flags, sp, stack_top, p, regs);
+
+	if (ret || !current->thread.forking)
+		goto out;
+
+	clear_flushed_tls(p);
+
+	/*
+	 * Set a new TLS for the child thread?
+	 */
+	if (clone_flags & CLONE_SETTLS)
+		ret = arch_copy_tls(p);
+
+out:
+	return ret;
 }
 
 void initial_thread_cb(void (*proc)(void *), void *arg)
@@ -185,10 +201,6 @@
 {
 	CHOOSE_MODE(uml_idle_timer(), (void) 0);
 
-	atomic_inc(&init_mm.mm_count);
-	current->mm = &init_mm;
-	current->active_mm = &init_mm;
-
 	while(1){
 		/* endless idle loop with no priority at all */
 
@@ -407,7 +419,7 @@
 	return strlen(buf);
 }
 
-static int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data)
+static int proc_write_sysemu(struct file *file,const char __user *buf, unsigned long count,void *data)
 {
 	char tmp[2];
 
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index 98e0939..60d2eda 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -46,6 +46,7 @@
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
 	int i, ret;
+	unsigned long __user *p = (void __user *)(unsigned long)data;
 
 	switch (request) {
 		/* when I and D space are separate, these will need to be fixed. */
@@ -58,7 +59,7 @@
 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
 		if (copied != sizeof(tmp))
 			break;
-		ret = put_user(tmp, (unsigned long __user *) data);
+		ret = put_user(tmp, p);
 		break;
 	}
 
@@ -136,15 +137,13 @@
 
 #ifdef PTRACE_GETREGS
 	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
-	  	if (!access_ok(VERIFY_WRITE, (unsigned long *)data, 
-			       MAX_REG_OFFSET)) {
+		if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) {
 			ret = -EIO;
 			break;
 		}
 		for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
-			__put_user(getreg(child, i),
-				   (unsigned long __user *) data);
-			data += sizeof(long);
+			__put_user(getreg(child, i), p);
+			p++;
 		}
 		ret = 0;
 		break;
@@ -153,15 +152,14 @@
 #ifdef PTRACE_SETREGS
 	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
 		unsigned long tmp = 0;
-	  	if (!access_ok(VERIFY_READ, (unsigned *)data, 
-			       MAX_REG_OFFSET)) {
+		if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) {
 			ret = -EIO;
 			break;
 		}
 		for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
-			__get_user(tmp, (unsigned long __user *) data);
+			__get_user(tmp, p);
 			putreg(child, i, tmp);
-			data += sizeof(long);
+			p++;
 		}
 		ret = 0;
 		break;
@@ -187,14 +185,23 @@
 		ret = set_fpxregs(data, child);
 		break;
 #endif
+	case PTRACE_GET_THREAD_AREA:
+		ret = ptrace_get_thread_area(child, addr,
+					     (struct user_desc __user *) data);
+		break;
+
+	case PTRACE_SET_THREAD_AREA:
+		ret = ptrace_set_thread_area(child, addr,
+					     (struct user_desc __user *) data);
+		break;
+
 	case PTRACE_FAULTINFO: {
-                /* Take the info from thread->arch->faultinfo,
-                 * but transfer max. sizeof(struct ptrace_faultinfo).
-                 * On i386, ptrace_faultinfo is smaller!
-                 */
-                ret = copy_to_user((unsigned long __user *) data,
-                                   &child->thread.arch.faultinfo,
-                                   sizeof(struct ptrace_faultinfo));
+		/* Take the info from thread->arch->faultinfo,
+		 * but transfer max. sizeof(struct ptrace_faultinfo).
+		 * On i386, ptrace_faultinfo is smaller!
+		 */
+		ret = copy_to_user(p, &child->thread.arch.faultinfo,
+				   sizeof(struct ptrace_faultinfo));
 		if(ret)
 			break;
 		break;
@@ -204,8 +211,7 @@
 	case PTRACE_LDT: {
 		struct ptrace_ldt ldt;
 
-		if(copy_from_user(&ldt, (unsigned long __user *) data,
-				  sizeof(ldt))){
+		if(copy_from_user(&ldt, p, sizeof(ldt))){
 			ret = -EIO;
 			break;
 		}
diff --git a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c
index 2299884..1c1300f 100644
--- a/arch/um/kernel/sigio_kern.c
+++ b/arch/um/kernel/sigio_kern.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
  * Licensed under the GPL
  */
@@ -12,13 +12,16 @@
 #include "sigio.h"
 #include "irq_user.h"
 #include "irq_kern.h"
+#include "os.h"
 
 /* Protected by sigio_lock() called from write_sigio_workaround */
 static int sigio_irq_fd = -1;
 
 static irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused)
 {
-	read_sigio_fd(sigio_irq_fd);
+	char c;
+
+	os_read_file(sigio_irq_fd, &c, sizeof(c));
 	reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ);
 	return(IRQ_HANDLED);
 }
@@ -51,6 +54,9 @@
 	spin_unlock(&sigio_spinlock);
 }
 
+extern void sigio_cleanup(void);
+__uml_exitcall(sigio_cleanup);
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c
deleted file mode 100644
index f7b18e1..0000000
--- a/arch/um/kernel/sigio_user.c
+++ /dev/null
@@ -1,466 +0,0 @@
-/* 
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <pty.h>
-#include <signal.h>
-#include <errno.h>
-#include <string.h>
-#include <sched.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-#include "init.h"
-#include "user.h"
-#include "kern_util.h"
-#include "user_util.h"
-#include "sigio.h"
-#include "os.h"
-
-/* Changed during early boot */
-int pty_output_sigio = 0;
-int pty_close_sigio = 0;
-
-/* Used as a flag during SIGIO testing early in boot */
-static volatile int got_sigio = 0;
-
-void __init handler(int sig)
-{
-	got_sigio = 1;
-}
-
-struct openpty_arg {
-	int master;
-	int slave;
-	int err;
-};
-
-static void openpty_cb(void *arg)
-{
-	struct openpty_arg *info = arg;
-
-	info->err = 0;
-	if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
-		info->err = -errno;
-}
-
-void __init check_one_sigio(void (*proc)(int, int))
-{
-	struct sigaction old, new;
-	struct openpty_arg pty = { .master = -1, .slave = -1 };
-	int master, slave, err;
-
-	initial_thread_cb(openpty_cb, &pty);
-	if(pty.err){
-		printk("openpty failed, errno = %d\n", -pty.err);
-		return;
-	}
-
-	master = pty.master;
-	slave = pty.slave;
-
-	if((master == -1) || (slave == -1)){
-		printk("openpty failed to allocate a pty\n");
-		return;
-	}
-
-	/* Not now, but complain so we now where we failed. */
-	err = raw(master);
-	if (err < 0)
-		panic("check_sigio : __raw failed, errno = %d\n", -err);
-
-	err = os_sigio_async(master, slave);
-	if(err < 0)
-		panic("tty_fds : sigio_async failed, err = %d\n", -err);
-
-	if(sigaction(SIGIO, NULL, &old) < 0)
-		panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
-	new = old;
-	new.sa_handler = handler;
-	if(sigaction(SIGIO, &new, NULL) < 0)
-		panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
-
-	got_sigio = 0;
-	(*proc)(master, slave);
-		
-	os_close_file(master);
-	os_close_file(slave);
-
-	if(sigaction(SIGIO, &old, NULL) < 0)
-		panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
-}
-
-static void tty_output(int master, int slave)
-{
-	int n;
-	char buf[512];
-
-	printk("Checking that host ptys support output SIGIO...");
-
-	memset(buf, 0, sizeof(buf));
-
-	while(os_write_file(master, buf, sizeof(buf)) > 0) ;
-	if(errno != EAGAIN)
-		panic("check_sigio : write failed, errno = %d\n", errno);
-	while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
-
-	if (got_sigio) {
-		printk("Yes\n");
-		pty_output_sigio = 1;
-	} else if (n == -EAGAIN) {
-		printk("No, enabling workaround\n");
-	} else {
-		panic("check_sigio : read failed, err = %d\n", n);
-	}
-}
-
-static void tty_close(int master, int slave)
-{
-	printk("Checking that host ptys support SIGIO on close...");
-
-	os_close_file(slave);
-	if(got_sigio){
-		printk("Yes\n");
-		pty_close_sigio = 1;
-	}
-	else printk("No, enabling workaround\n");
-}
-
-void __init check_sigio(void)
-{
-	if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
-	   (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
-		printk("No pseudo-terminals available - skipping pty SIGIO "
-		       "check\n");
-		return;
-	}
-	check_one_sigio(tty_output);
-	check_one_sigio(tty_close);
-}
-
-/* Protected by sigio_lock(), also used by sigio_cleanup, which is an 
- * exitcall.
- */
-static int write_sigio_pid = -1;
-
-/* These arrays are initialized before the sigio thread is started, and
- * the descriptors closed after it is killed.  So, it can't see them change.
- * On the UML side, they are changed under the sigio_lock.
- */
-static int write_sigio_fds[2] = { -1, -1 };
-static int sigio_private[2] = { -1, -1 };
-
-struct pollfds {
-	struct pollfd *poll;
-	int size;
-	int used;
-};
-
-/* Protected by sigio_lock().  Used by the sigio thread, but the UML thread
- * synchronizes with it.
- */
-struct pollfds current_poll = {
-	.poll  		= NULL,
-	.size 		= 0,
-	.used 		= 0
-};
-
-struct pollfds next_poll = {
-	.poll  		= NULL,
-	.size 		= 0,
-	.used 		= 0
-};
-
-static int write_sigio_thread(void *unused)
-{
-	struct pollfds *fds, tmp;
-	struct pollfd *p;
-	int i, n, respond_fd;
-	char c;
-
-        signal(SIGWINCH, SIG_IGN);
-	fds = &current_poll;
-	while(1){
-		n = poll(fds->poll, fds->used, -1);
-		if(n < 0){
-			if(errno == EINTR) continue;
-			printk("write_sigio_thread : poll returned %d, "
-			       "errno = %d\n", n, errno);
-		}
-		for(i = 0; i < fds->used; i++){
-			p = &fds->poll[i];
-			if(p->revents == 0) continue;
-			if(p->fd == sigio_private[1]){
-				n = os_read_file(sigio_private[1], &c, sizeof(c));
-				if(n != sizeof(c))
-					printk("write_sigio_thread : "
-					       "read failed, err = %d\n", -n);
-				tmp = current_poll;
-				current_poll = next_poll;
-				next_poll = tmp;
-				respond_fd = sigio_private[1];
-			}
-			else {
-				respond_fd = write_sigio_fds[1];
-				fds->used--;
-				memmove(&fds->poll[i], &fds->poll[i + 1],
-					(fds->used - i) * sizeof(*fds->poll));
-			}
-
-			n = os_write_file(respond_fd, &c, sizeof(c));
-			if(n != sizeof(c))
-				printk("write_sigio_thread : write failed, "
-				       "err = %d\n", -n);
-		}
-	}
-
-	return 0;
-}
-
-static int need_poll(int n)
-{
-	if(n <= next_poll.size){
-		next_poll.used = n;
-		return(0);
-	}
-	kfree(next_poll.poll);
-	next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
-	if(next_poll.poll == NULL){
-		printk("need_poll : failed to allocate new pollfds\n");
-		next_poll.size = 0;
-		next_poll.used = 0;
-		return(-1);
-	}
-	next_poll.size = n;
-	next_poll.used = n;
-	return(0);
-}
-
-/* Must be called with sigio_lock held, because it's needed by the marked
- * critical section. */
-static void update_thread(void)
-{
-	unsigned long flags;
-	int n;
-	char c;
-
-	flags = set_signals(0);
-	n = os_write_file(sigio_private[0], &c, sizeof(c));
-	if(n != sizeof(c)){
-		printk("update_thread : write failed, err = %d\n", -n);
-		goto fail;
-	}
-
-	n = os_read_file(sigio_private[0], &c, sizeof(c));
-	if(n != sizeof(c)){
-		printk("update_thread : read failed, err = %d\n", -n);
-		goto fail;
-	}
-
-	set_signals(flags);
-	return;
- fail:
-	/* Critical section start */
-	if(write_sigio_pid != -1) 
-		os_kill_process(write_sigio_pid, 1);
-	write_sigio_pid = -1;
-	os_close_file(sigio_private[0]);
-	os_close_file(sigio_private[1]);
-	os_close_file(write_sigio_fds[0]);
-	os_close_file(write_sigio_fds[1]);
-	/* Critical section end */
-	set_signals(flags);
-}
-
-int add_sigio_fd(int fd, int read)
-{
-	int err = 0, i, n, events;
-
-	sigio_lock();
-	for(i = 0; i < current_poll.used; i++){
-		if(current_poll.poll[i].fd == fd) 
-			goto out;
-	}
-
-	n = current_poll.used + 1;
-	err = need_poll(n);
-	if(err) 
-		goto out;
-
-	for(i = 0; i < current_poll.used; i++)
-		next_poll.poll[i] = current_poll.poll[i];
-
-	if(read) events = POLLIN;
-	else events = POLLOUT;
-
-	next_poll.poll[n - 1] = ((struct pollfd) { .fd  	= fd,
-						   .events 	= events,
-						   .revents 	= 0 });
-	update_thread();
- out:
-	sigio_unlock();
-	return(err);
-}
-
-int ignore_sigio_fd(int fd)
-{
-	struct pollfd *p;
-	int err = 0, i, n = 0;
-
-	sigio_lock();
-	for(i = 0; i < current_poll.used; i++){
-		if(current_poll.poll[i].fd == fd) break;
-	}
-	if(i == current_poll.used)
-		goto out;
-	
-	err = need_poll(current_poll.used - 1);
-	if(err)
-		goto out;
-
-	for(i = 0; i < current_poll.used; i++){
-		p = &current_poll.poll[i];
-		if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
-	}
-	if(n == i){
-		printk("ignore_sigio_fd : fd %d not found\n", fd);
-		err = -1;
-		goto out;
-	}
-
-	update_thread();
- out:
-	sigio_unlock();
-	return(err);
-}
-
-static struct pollfd* setup_initial_poll(int fd)
-{
-	struct pollfd *p;
-
-	p = um_kmalloc(sizeof(struct pollfd));
-	if (p == NULL) {
-		printk("setup_initial_poll : failed to allocate poll\n");
-		return NULL;
-	}
-	*p = ((struct pollfd) { .fd  	= fd,
-				.events 	= POLLIN,
-				.revents 	= 0 });
-	return p;
-}
-
-void write_sigio_workaround(void)
-{
-	unsigned long stack;
-	struct pollfd *p;
-	int err;
-	int l_write_sigio_fds[2];
-	int l_sigio_private[2];
-	int l_write_sigio_pid;
-
-	/* We call this *tons* of times - and most ones we must just fail. */
-	sigio_lock();
-	l_write_sigio_pid = write_sigio_pid;
-	sigio_unlock();
-
-	if (l_write_sigio_pid != -1)
-		return;
-
-	err = os_pipe(l_write_sigio_fds, 1, 1);
-	if(err < 0){
-		printk("write_sigio_workaround - os_pipe 1 failed, "
-		       "err = %d\n", -err);
-		return;
-	}
-	err = os_pipe(l_sigio_private, 1, 1);
-	if(err < 0){
-		printk("write_sigio_workaround - os_pipe 1 failed, "
-		       "err = %d\n", -err);
-		goto out_close1;
-	}
-
-	p = setup_initial_poll(l_sigio_private[1]);
-	if(!p)
-		goto out_close2;
-
-	sigio_lock();
-
-	/* Did we race? Don't try to optimize this, please, it's not so likely
-	 * to happen, and no more than once at the boot. */
-	if(write_sigio_pid != -1)
-		goto out_unlock;
-
-	write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
-					    CLONE_FILES | CLONE_VM, &stack, 0);
-
-	if (write_sigio_pid < 0)
-		goto out_clear;
-
-	if (write_sigio_irq(l_write_sigio_fds[0]))
-		goto out_kill;
-
-	/* Success, finally. */
-	memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds));
-	memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private));
-
-	current_poll = ((struct pollfds) { .poll 	= p,
-					   .used 	= 1,
-					   .size 	= 1 });
-
-	sigio_unlock();
-	return;
-
- out_kill:
-	l_write_sigio_pid = write_sigio_pid;
-	write_sigio_pid = -1;
-	sigio_unlock();
-	/* Going to call waitpid, avoid holding the lock. */
-	os_kill_process(l_write_sigio_pid, 1);
-	goto out_free;
-
- out_clear:
-	write_sigio_pid = -1;
- out_unlock:
-	sigio_unlock();
- out_free:
-	kfree(p);
- out_close2:
-	os_close_file(l_sigio_private[0]);
-	os_close_file(l_sigio_private[1]);
- out_close1:
-	os_close_file(l_write_sigio_fds[0]);
-	os_close_file(l_write_sigio_fds[1]);
-	return;
-}
-
-int read_sigio_fd(int fd)
-{
-	int n;
-	char c;
-
-	n = os_read_file(fd, &c, sizeof(c));
-	if(n != sizeof(c)){
-		if(n < 0) {
-			printk("read_sigio_fd - read failed, err = %d\n", -n);
-			return(n);
-		}
-		else {
-			printk("read_sigio_fd - short read, bytes = %d\n", n);
-			return(-EIO);
-		}
-	}
-	return(n);
-}
-
-static void sigio_cleanup(void)
-{
-	if (write_sigio_pid != -1) {
-		os_kill_process(write_sigio_pid, 1);
-		write_sigio_pid = -1;
-	}
-}
-
-__uml_exitcall(sigio_cleanup);
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
index 3f70a2e..2135eaf 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -35,6 +35,8 @@
 	switch_threads(&from->thread.mode.skas.switch_buf,
 		       to->thread.mode.skas.switch_buf);
 
+	arch_switch_to_skas(current->thread.prev_sched, current);
+
 	if(current->pid == 0)
 		switch_timers(1);
 }
@@ -89,10 +91,17 @@
 		panic("blech");
 
 	schedule_tail(current->thread.prev_sched);
+
+	/* XXX: if interrupt_end() calls schedule, this call to
+	 * arch_switch_to_skas isn't needed. We could want to apply this to
+	 * improve performance. -bb */
+	arch_switch_to_skas(current->thread.prev_sched, current);
+
 	current->thread.prev_sched = NULL;
 
 /* Handle any immediate reschedules or signals */
 	interrupt_end();
+
 	userspace(&current->thread.regs.regs);
 }
 
@@ -109,6 +118,8 @@
 		if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
 
 		handler = fork_handler;
+
+		arch_copy_thread(&current->thread.arch, &p->thread.arch);
 	}
 	else {
 		init_thread_registers(&p->thread.regs.regs);
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index 72113b0..511116a 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
  * Licensed under the GPL
  */
@@ -77,9 +77,9 @@
 	if(err < 0)
 		panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
 
-	activate_ipi(cpu_data[cpu].ipi_pipe[0], 
+	os_set_fd_async(cpu_data[cpu].ipi_pipe[0],
 		     current->thread.mode.tt.extern_pid);
- 
+
 	wmb();
 	if (cpu_test_and_set(cpu, cpu_callin_map)) {
 		printk("huh, CPU#%d already present??\n", cpu);
@@ -106,7 +106,7 @@
 		panic("copy_process failed in idle_thread, error = %ld",
 		      PTR_ERR(new_task));
 
-	cpu_tasks[cpu] = ((struct cpu_task) 
+	cpu_tasks[cpu] = ((struct cpu_task)
 		          { .pid = 	new_task->thread.mode.tt.extern_pid,
 			    .task = 	new_task } );
 	idle_threads[cpu] = new_task;
@@ -134,16 +134,15 @@
 	if(err < 0)
 		panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
 
-	activate_ipi(cpu_data[me].ipi_pipe[0],
+	os_set_fd_async(cpu_data[me].ipi_pipe[0],
 		     current->thread.mode.tt.extern_pid);
 
 	for(cpu = 1; cpu < ncpus; cpu++){
 		printk("Booting processor %d...\n", cpu);
-		
+
 		idle = idle_thread(cpu);
 
 		init_idle(idle, cpu);
-		unhash_process(idle);
 
 		waittime = 200000000;
 		while (waittime-- && !cpu_isset(cpu, cpu_callin_map))
@@ -223,7 +222,7 @@
 	atomic_inc(&scf_finished);
 }
 
-int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, 
+int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic,
 		      int wait)
 {
 	int cpus = num_online_cpus() - 1;
diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c
index 8e1a350..37d3978 100644
--- a/arch/um/kernel/syscall_kern.c
+++ b/arch/um/kernel/syscall_kern.c
@@ -104,7 +104,7 @@
 }
 
 
-long sys_uname(struct old_utsname * name)
+long sys_uname(struct old_utsname __user * name)
 {
 	long err;
 	if (!name)
@@ -115,7 +115,7 @@
 	return err?-EFAULT:0;
 }
 
-long sys_olduname(struct oldold_utsname * name)
+long sys_olduname(struct oldold_utsname __user * name)
 {
 	long error;
 
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
index d56046c..02f6d4d 100644
--- a/arch/um/kernel/trap_kern.c
+++ b/arch/um/kernel/trap_kern.c
@@ -198,7 +198,7 @@
 		si.si_signo = SIGBUS;
 		si.si_errno = 0;
 		si.si_code = BUS_ADRERR;
-		si.si_addr = (void *)address;
+		si.si_addr = (void __user *)address;
                 current->thread.arch.faultinfo = fi;
 		force_sig_info(SIGBUS, &si, current);
 	} else if (err == -ENOMEM) {
@@ -207,7 +207,7 @@
 	} else {
 		BUG_ON(err != -EFAULT);
 		si.si_signo = SIGSEGV;
-		si.si_addr = (void *) address;
+		si.si_addr = (void __user *) address;
                 current->thread.arch.faultinfo = fi;
 		force_sig_info(SIGSEGV, &si, current);
 	}
@@ -220,8 +220,8 @@
 
 	si.si_signo = SIGSEGV;
 	si.si_code = SEGV_ACCERR;
-        si.si_addr = (void *) FAULT_ADDRESS(fi);
-        current->thread.arch.faultinfo = fi;
+	si.si_addr = (void __user *) FAULT_ADDRESS(fi);
+	current->thread.arch.faultinfo = fi;
 	force_sig_info(SIGSEGV, &si, current);
 }
 
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
index 295c1ac..a9c1443 100644
--- a/arch/um/kernel/tt/process_kern.c
+++ b/arch/um/kernel/tt/process_kern.c
@@ -51,6 +51,13 @@
 
 	c = 0;
 
+	/* Notice that here we "up" the semaphore on which "to" is waiting, and
+	 * below (the read) we wait on this semaphore (which is implemented by
+	 * switch_pipe) and go sleeping. Thus, after that, we have resumed in
+	 * "to", and can't use any more the value of "from" (which is outdated),
+	 * nor the value in "to" (since it was the task which stole us the CPU,
+	 * which we don't care about). */
+
 	err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
 	if(err != sizeof(c))
 		panic("write of switch_pipe failed, err = %d", -err);
@@ -77,7 +84,7 @@
 	change_sig(SIGALRM, alrm);
 	change_sig(SIGPROF, prof);
 
-	arch_switch();
+	arch_switch_to_tt(prev_sched, current);
 
 	flush_tlb_all();
 	local_irq_restore(flags);
@@ -141,7 +148,6 @@
 	set_cmdline("(kernel thread)");
 
 	change_sig(SIGUSR1, 1);
-	change_sig(SIGVTALRM, 1);
 	change_sig(SIGPROF, 1);
 	local_irq_enable();
 	if(!run_kernel_thread(fn, arg, &current->thread.exec_buf))
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 80c9c18..7d51dd7 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -421,7 +421,7 @@
 #ifndef CONFIG_HIGHMEM
 		highmem = 0;
 		printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
-		       "to %lu bytes\n", physmem_size);
+		       "to %Lu bytes\n", physmem_size);
 #endif
 	}
 
@@ -433,8 +433,8 @@
 
 	setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
 	if(init_maps(physmem_size, iomem_size, highmem)){
-		printf("Failed to allocate mem_map for %lu bytes of physical "
-		       "memory and %lu bytes of highmem\n", physmem_size,
+		printf("Failed to allocate mem_map for %Lu bytes of physical "
+		       "memory and %Lu bytes of highmem\n", physmem_size,
 		       highmem);
 		exit(1);
 	}
@@ -477,7 +477,8 @@
 
 void __init setup_arch(char **cmdline_p)
 {
-	notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
+	atomic_notifier_chain_register(&panic_notifier_list,
+			&panic_exit_notifier);
 	paging_init();
         strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
  	*cmdline_p = command_line;
@@ -487,8 +488,7 @@
 void __init check_bugs(void)
 {
 	arch_check_bugs();
-	check_sigio();
-	check_devanon();
+ 	os_check_bugs();
 }
 
 void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index 08a4e62..f4bfc4c 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -3,17 +3,17 @@
 # Licensed under the GPL
 #
 
-obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \
-	start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o user_syms.o \
-	util.o drivers/ sys-$(SUBARCH)/
+obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \
+	signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o tls.o \
+	user_syms.o util.o drivers/ sys-$(SUBARCH)/
 
 obj-$(CONFIG_MODE_SKAS) += skas/
+obj-$(CONFIG_TTY_LOG) += tty_log.o
+user-objs-$(CONFIG_TTY_LOG) += tty_log.o
 
-USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \
-	start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o util.o
-
-elf_aux.o: $(ARCH_DIR)/kernel-offsets.h
-CFLAGS_elf_aux.o += -I$(objtree)/arch/um
+USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \
+	process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o tls.o \
+	uaccess.o umid.o util.o
 
 CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
 
diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c
index 6ae4b19..768606b 100644
--- a/arch/um/os-Linux/drivers/ethertap_kern.c
+++ b/arch/um/os-Linux/drivers/ethertap_kern.c
@@ -102,18 +102,7 @@
 static int register_ethertap(void)
 {
 	register_transport(&ethertap_transport);
-	return(1);
+	return 0;
 }
 
 __initcall(register_ethertap);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c
index 4202b9e..190009a 100644
--- a/arch/um/os-Linux/drivers/tuntap_kern.c
+++ b/arch/um/os-Linux/drivers/tuntap_kern.c
@@ -87,18 +87,7 @@
 static int register_tuntap(void)
 {
 	register_transport(&tuntap_transport);
-	return(1);
+	return 0;
 }
 
 __initcall(register_tuntap);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c
new file mode 100644
index 0000000..e599be4
--- /dev/null
+++ b/arch/um/os-Linux/irq.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "process.h"
+#include "sigio.h"
+#include "irq_user.h"
+#include "os.h"
+
+static struct pollfd *pollfds = NULL;
+static int pollfds_num = 0;
+static int pollfds_size = 0;
+
+int os_waiting_for_events(struct irq_fd *active_fds)
+{
+	struct irq_fd *irq_fd;
+	int i, n, err;
+
+	n = poll(pollfds, pollfds_num, 0);
+	if(n < 0){
+		err = -errno;
+		if(errno != EINTR)
+			printk("sigio_handler: os_waiting_for_events:"
+			       " poll returned %d, errno = %d\n", n, errno);
+		return err;
+	}
+
+	if(n == 0)
+		return 0;
+
+	irq_fd = active_fds;
+
+	for(i = 0; i < pollfds_num; i++){
+		if(pollfds[i].revents != 0){
+			irq_fd->current_events = pollfds[i].revents;
+			pollfds[i].fd = -1;
+		}
+		irq_fd = irq_fd->next;
+	}
+	return n;
+}
+
+int os_isatty(int fd)
+{
+	return(isatty(fd));
+}
+
+int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds)
+{
+	if (pollfds_num == pollfds_size) {
+		if (size_tmpfds <= pollfds_size * sizeof(pollfds[0])) {
+			/* return min size needed for new pollfds area */
+			return((pollfds_size + 1) * sizeof(pollfds[0]));
+		}
+
+		if(pollfds != NULL){
+			memcpy(tmp_pfd, pollfds,
+			       sizeof(pollfds[0]) * pollfds_size);
+			/* remove old pollfds */
+			kfree(pollfds);
+		}
+		pollfds = tmp_pfd;
+		pollfds_size++;
+	} else {
+		/* remove not used tmp_pfd */
+		if (tmp_pfd != NULL)
+			kfree(tmp_pfd);
+	}
+
+	pollfds[pollfds_num] = ((struct pollfd) { .fd 	= fd,
+						  .events 	= events,
+						  .revents 	= 0 });
+	pollfds_num++;
+
+	return(0);
+}
+
+void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg,
+		struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2)
+{
+	struct irq_fd **prev;
+	int i = 0;
+
+	prev = &active_fds;
+	while(*prev != NULL){
+		if((*test)(*prev, arg)){
+			struct irq_fd *old_fd = *prev;
+			if((pollfds[i].fd != -1) &&
+			   (pollfds[i].fd != (*prev)->fd)){
+				printk("os_free_irq_by_cb - mismatch between "
+				       "active_fds and pollfds, fd %d vs %d\n",
+				       (*prev)->fd, pollfds[i].fd);
+				goto out;
+			}
+
+			pollfds_num--;
+
+			/* This moves the *whole* array after pollfds[i]
+			 * (though it doesn't spot as such)!
+			 */
+
+			memmove(&pollfds[i], &pollfds[i + 1],
+			       (pollfds_num - i) * sizeof(pollfds[0]));
+			if(*last_irq_ptr2 == &old_fd->next)
+				*last_irq_ptr2 = prev;
+
+			*prev = (*prev)->next;
+			if(old_fd->type == IRQ_WRITE)
+				ignore_sigio_fd(old_fd->fd);
+			kfree(old_fd);
+			continue;
+		}
+		prev = &(*prev)->next;
+		i++;
+	}
+ out:
+	return;
+}
+
+
+int os_get_pollfd(int i)
+{
+	return(pollfds[i].fd);
+}
+
+void os_set_pollfd(int i, int fd)
+{
+	pollfds[i].fd = fd;
+}
+
+void os_set_ioignore(void)
+{
+	set_handler(SIGIO, SIG_IGN, 0, -1);
+}
+
+void init_irq_signals(int on_sigstack)
+{
+	__sighandler_t h;
+	int flags;
+
+	flags = on_sigstack ? SA_ONSTACK : 0;
+	if(timer_irq_inited) h = (__sighandler_t) alarm_handler;
+	else h = boot_timer_handler;
+
+	set_handler(SIGVTALRM, h, flags | SA_RESTART,
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1);
+	set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+	signal(SIGWINCH, SIG_IGN);
+}
diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c
index 9d7d69a..6ab372d 100644
--- a/arch/um/os-Linux/mem.c
+++ b/arch/um/os-Linux/mem.c
@@ -121,36 +121,11 @@
 	return(fd);
 }
 
-static int create_anon_file(unsigned long long len)
-{
-	void *addr;
-	int fd;
-
-	fd = open("/dev/anon", O_RDWR);
-	if(fd < 0) {
-		perror("opening /dev/anon");
-		exit(1);
-	}
-
-	addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
-	if(addr == MAP_FAILED){
-		perror("mapping physmem file");
-		exit(1);
-	}
-	munmap(addr, len);
-
-	return(fd);
-}
-
-extern int have_devanon;
-
 int create_mem_file(unsigned long long len)
 {
 	int err, fd;
 
-	if(have_devanon)
-		fd = create_anon_file(len);
-	else fd = create_tmp_file(len);
+	fd = create_tmp_file(len);
 
 	err = os_set_exec_close(fd, 1);
 	if(err < 0){
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index d261888..8176b0b 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -11,6 +11,7 @@
 #include <linux/unistd.h>
 #include <sys/mman.h>
 #include <sys/wait.h>
+#include <sys/mman.h>
 #include "ptrace_user.h"
 #include "os.h"
 #include "user.h"
@@ -20,6 +21,7 @@
 #include "kern_util.h"
 #include "longjmp.h"
 #include "skas_ptrace.h"
+#include "kern_constants.h"
 
 #define ARBITRARY_ADDR -1
 #define FAILURE_PID    -1
@@ -187,6 +189,48 @@
         return(0);
 }
 
+#ifndef MADV_REMOVE
+#define MADV_REMOVE	0x5		/* remove these pages & resources */
+#endif
+
+int os_drop_memory(void *addr, int length)
+{
+	int err;
+
+	err = madvise(addr, length, MADV_REMOVE);
+	if(err < 0)
+		err = -errno;
+	return err;
+}
+
+int can_drop_memory(void)
+{
+	void *addr;
+	int fd;
+
+	printk("Checking host MADV_REMOVE support...");
+	fd = create_mem_file(UM_KERN_PAGE_SIZE);
+	if(fd < 0){
+		printk("Creating test memory file failed, err = %d\n", -fd);
+		return 0;
+	}
+
+	addr = mmap64(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
+		      MAP_PRIVATE, fd, 0);
+	if(addr == MAP_FAILED){
+		printk("Mapping test memory file failed, err = %d\n", -errno);
+		return 0;
+	}
+
+	if(madvise(addr, UM_KERN_PAGE_SIZE, MADV_REMOVE) != 0){
+		printk("MADV_REMOVE failed, err = %d\n", -errno);
+		return 0;
+	}
+
+	printk("OK\n");
+	return 1;
+}
+
 void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
 {
 	int flags = 0, pages;
diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c
new file mode 100644
index 0000000..9ba9429
--- /dev/null
+++ b/arch/um/os-Linux/sigio.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <pty.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sched.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include "init.h"
+#include "user.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "sigio.h"
+#include "os.h"
+
+/* Protected by sigio_lock(), also used by sigio_cleanup, which is an
+ * exitcall.
+ */
+static int write_sigio_pid = -1;
+
+/* These arrays are initialized before the sigio thread is started, and
+ * the descriptors closed after it is killed.  So, it can't see them change.
+ * On the UML side, they are changed under the sigio_lock.
+ */
+#define SIGIO_FDS_INIT {-1, -1}
+
+static int write_sigio_fds[2] = SIGIO_FDS_INIT;
+static int sigio_private[2] = SIGIO_FDS_INIT;
+
+struct pollfds {
+	struct pollfd *poll;
+	int size;
+	int used;
+};
+
+/* Protected by sigio_lock().  Used by the sigio thread, but the UML thread
+ * synchronizes with it.
+ */
+struct pollfds current_poll = {
+	.poll  		= NULL,
+	.size 		= 0,
+	.used 		= 0
+};
+
+struct pollfds next_poll = {
+	.poll  		= NULL,
+	.size 		= 0,
+	.used 		= 0
+};
+
+static int write_sigio_thread(void *unused)
+{
+	struct pollfds *fds, tmp;
+	struct pollfd *p;
+	int i, n, respond_fd;
+	char c;
+
+        signal(SIGWINCH, SIG_IGN);
+	fds = &current_poll;
+	while(1){
+		n = poll(fds->poll, fds->used, -1);
+		if(n < 0){
+			if(errno == EINTR) continue;
+			printk("write_sigio_thread : poll returned %d, "
+			       "errno = %d\n", n, errno);
+		}
+		for(i = 0; i < fds->used; i++){
+			p = &fds->poll[i];
+			if(p->revents == 0) continue;
+			if(p->fd == sigio_private[1]){
+				n = os_read_file(sigio_private[1], &c, sizeof(c));
+				if(n != sizeof(c))
+					printk("write_sigio_thread : "
+					       "read failed, err = %d\n", -n);
+				tmp = current_poll;
+				current_poll = next_poll;
+				next_poll = tmp;
+				respond_fd = sigio_private[1];
+			}
+			else {
+				respond_fd = write_sigio_fds[1];
+				fds->used--;
+				memmove(&fds->poll[i], &fds->poll[i + 1],
+					(fds->used - i) * sizeof(*fds->poll));
+			}
+
+			n = os_write_file(respond_fd, &c, sizeof(c));
+			if(n != sizeof(c))
+				printk("write_sigio_thread : write failed, "
+				       "err = %d\n", -n);
+		}
+	}
+
+	return 0;
+}
+
+static int need_poll(int n)
+{
+	if(n <= next_poll.size){
+		next_poll.used = n;
+		return(0);
+	}
+	kfree(next_poll.poll);
+	next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
+	if(next_poll.poll == NULL){
+		printk("need_poll : failed to allocate new pollfds\n");
+		next_poll.size = 0;
+		next_poll.used = 0;
+		return(-1);
+	}
+	next_poll.size = n;
+	next_poll.used = n;
+	return(0);
+}
+
+/* Must be called with sigio_lock held, because it's needed by the marked
+ * critical section. */
+static void update_thread(void)
+{
+	unsigned long flags;
+	int n;
+	char c;
+
+	flags = set_signals(0);
+	n = os_write_file(sigio_private[0], &c, sizeof(c));
+	if(n != sizeof(c)){
+		printk("update_thread : write failed, err = %d\n", -n);
+		goto fail;
+	}
+
+	n = os_read_file(sigio_private[0], &c, sizeof(c));
+	if(n != sizeof(c)){
+		printk("update_thread : read failed, err = %d\n", -n);
+		goto fail;
+	}
+
+	set_signals(flags);
+	return;
+ fail:
+	/* Critical section start */
+	if(write_sigio_pid != -1)
+		os_kill_process(write_sigio_pid, 1);
+	write_sigio_pid = -1;
+	close(sigio_private[0]);
+	close(sigio_private[1]);
+	close(write_sigio_fds[0]);
+	close(write_sigio_fds[1]);
+	/* Critical section end */
+	set_signals(flags);
+}
+
+int add_sigio_fd(int fd, int read)
+{
+	int err = 0, i, n, events;
+
+	sigio_lock();
+	for(i = 0; i < current_poll.used; i++){
+		if(current_poll.poll[i].fd == fd)
+			goto out;
+	}
+
+	n = current_poll.used + 1;
+	err = need_poll(n);
+	if(err)
+		goto out;
+
+	for(i = 0; i < current_poll.used; i++)
+		next_poll.poll[i] = current_poll.poll[i];
+
+	if(read) events = POLLIN;
+	else events = POLLOUT;
+
+	next_poll.poll[n - 1] = ((struct pollfd) { .fd  	= fd,
+						   .events 	= events,
+						   .revents 	= 0 });
+	update_thread();
+ out:
+	sigio_unlock();
+	return(err);
+}
+
+int ignore_sigio_fd(int fd)
+{
+	struct pollfd *p;
+	int err = 0, i, n = 0;
+
+	sigio_lock();
+	for(i = 0; i < current_poll.used; i++){
+		if(current_poll.poll[i].fd == fd) break;
+	}
+	if(i == current_poll.used)
+		goto out;
+
+	err = need_poll(current_poll.used - 1);
+	if(err)
+		goto out;
+
+	for(i = 0; i < current_poll.used; i++){
+		p = &current_poll.poll[i];
+		if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
+	}
+	if(n == i){
+		printk("ignore_sigio_fd : fd %d not found\n", fd);
+		err = -1;
+		goto out;
+	}
+
+	update_thread();
+ out:
+	sigio_unlock();
+	return(err);
+}
+
+static struct pollfd *setup_initial_poll(int fd)
+{
+	struct pollfd *p;
+
+	p = um_kmalloc(sizeof(struct pollfd));
+	if (p == NULL) {
+		printk("setup_initial_poll : failed to allocate poll\n");
+		return NULL;
+	}
+	*p = ((struct pollfd) { .fd  	= fd,
+				.events 	= POLLIN,
+				.revents 	= 0 });
+	return p;
+}
+
+void write_sigio_workaround(void)
+{
+	unsigned long stack;
+	struct pollfd *p;
+	int err;
+	int l_write_sigio_fds[2];
+	int l_sigio_private[2];
+	int l_write_sigio_pid;
+
+	/* We call this *tons* of times - and most ones we must just fail. */
+	sigio_lock();
+	l_write_sigio_pid = write_sigio_pid;
+	sigio_unlock();
+
+	if (l_write_sigio_pid != -1)
+		return;
+
+	err = os_pipe(l_write_sigio_fds, 1, 1);
+	if(err < 0){
+		printk("write_sigio_workaround - os_pipe 1 failed, "
+		       "err = %d\n", -err);
+		return;
+	}
+	err = os_pipe(l_sigio_private, 1, 1);
+	if(err < 0){
+		printk("write_sigio_workaround - os_pipe 2 failed, "
+		       "err = %d\n", -err);
+		goto out_close1;
+	}
+
+	p = setup_initial_poll(l_sigio_private[1]);
+	if(!p)
+		goto out_close2;
+
+	sigio_lock();
+
+	/* Did we race? Don't try to optimize this, please, it's not so likely
+	 * to happen, and no more than once at the boot. */
+	if(write_sigio_pid != -1)
+		goto out_free;
+
+	current_poll = ((struct pollfds) { .poll 	= p,
+					   .used 	= 1,
+					   .size 	= 1 });
+
+	if (write_sigio_irq(l_write_sigio_fds[0]))
+		goto out_clear_poll;
+
+	memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds));
+	memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private));
+
+	write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
+					    CLONE_FILES | CLONE_VM, &stack, 0);
+
+	if (write_sigio_pid < 0)
+		goto out_clear;
+
+	sigio_unlock();
+	return;
+
+out_clear:
+	write_sigio_pid = -1;
+	write_sigio_fds[0] = -1;
+	write_sigio_fds[1] = -1;
+	sigio_private[0] = -1;
+	sigio_private[1] = -1;
+out_clear_poll:
+	current_poll = ((struct pollfds) { .poll	= NULL,
+					   .size	= 0,
+					   .used	= 0 });
+out_free:
+	kfree(p);
+	sigio_unlock();
+out_close2:
+	close(l_sigio_private[0]);
+	close(l_sigio_private[1]);
+out_close1:
+	close(l_write_sigio_fds[0]);
+	close(l_write_sigio_fds[1]);
+}
+
+void sigio_cleanup(void)
+{
+	if(write_sigio_pid != -1){
+		os_kill_process(write_sigio_pid, 1);
+		write_sigio_pid = -1;
+	}
+}
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index 829d6b0..387e26a 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -3,6 +3,7 @@
  * Licensed under the GPL
  */
 
+#include <pty.h>
 #include <stdio.h>
 #include <stddef.h>
 #include <stdarg.h>
@@ -469,25 +470,6 @@
 }
 #endif
 
-int have_devanon = 0;
-
-/* Runs on boot kernel stack - already safe to use printk. */
-
-void check_devanon(void)
-{
-	int fd;
-
-	printk("Checking for /dev/anon on the host...");
-	fd = open("/dev/anon", O_RDWR);
-	if(fd < 0){
-		printk("Not available (open failed with errno %d)\n", errno);
-		return;
-	}
-
-	printk("OK\n");
-	have_devanon = 1;
-}
-
 int __init parse_iomem(char *str, int *add)
 {
 	struct iomem_region *new;
@@ -539,3 +521,129 @@
 	return(1);
 }
 
+
+/* Changed during early boot */
+int pty_output_sigio = 0;
+int pty_close_sigio = 0;
+
+/* Used as a flag during SIGIO testing early in boot */
+static volatile int got_sigio = 0;
+
+static void __init handler(int sig)
+{
+	got_sigio = 1;
+}
+
+struct openpty_arg {
+	int master;
+	int slave;
+	int err;
+};
+
+static void openpty_cb(void *arg)
+{
+	struct openpty_arg *info = arg;
+
+	info->err = 0;
+	if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
+		info->err = -errno;
+}
+
+static void __init check_one_sigio(void (*proc)(int, int))
+{
+	struct sigaction old, new;
+	struct openpty_arg pty = { .master = -1, .slave = -1 };
+	int master, slave, err;
+
+	initial_thread_cb(openpty_cb, &pty);
+	if(pty.err){
+		printk("openpty failed, errno = %d\n", -pty.err);
+		return;
+	}
+
+	master = pty.master;
+	slave = pty.slave;
+
+	if((master == -1) || (slave == -1)){
+		printk("openpty failed to allocate a pty\n");
+		return;
+	}
+
+	/* Not now, but complain so we now where we failed. */
+	err = raw(master);
+	if (err < 0)
+		panic("check_sigio : __raw failed, errno = %d\n", -err);
+
+	err = os_sigio_async(master, slave);
+	if(err < 0)
+		panic("tty_fds : sigio_async failed, err = %d\n", -err);
+
+	if(sigaction(SIGIO, NULL, &old) < 0)
+		panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
+	new = old;
+	new.sa_handler = handler;
+	if(sigaction(SIGIO, &new, NULL) < 0)
+		panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
+
+	got_sigio = 0;
+	(*proc)(master, slave);
+
+	close(master);
+	close(slave);
+
+	if(sigaction(SIGIO, &old, NULL) < 0)
+		panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
+}
+
+static void tty_output(int master, int slave)
+{
+	int n;
+	char buf[512];
+
+	printk("Checking that host ptys support output SIGIO...");
+
+	memset(buf, 0, sizeof(buf));
+
+	while(os_write_file(master, buf, sizeof(buf)) > 0) ;
+	if(errno != EAGAIN)
+		panic("check_sigio : write failed, errno = %d\n", errno);
+	while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
+
+	if(got_sigio){
+		printk("Yes\n");
+		pty_output_sigio = 1;
+	}
+	else if(n == -EAGAIN) printk("No, enabling workaround\n");
+	else panic("check_sigio : read failed, err = %d\n", n);
+}
+
+static void tty_close(int master, int slave)
+{
+	printk("Checking that host ptys support SIGIO on close...");
+
+	close(slave);
+	if(got_sigio){
+		printk("Yes\n");
+		pty_close_sigio = 1;
+	}
+	else printk("No, enabling workaround\n");
+}
+
+void __init check_sigio(void)
+{
+	if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
+	   (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
+		printk("No pseudo-terminals available - skipping pty SIGIO "
+		       "check\n");
+		return;
+	}
+	check_one_sigio(tty_output);
+	check_one_sigio(tty_close);
+}
+
+void os_check_bugs(void)
+{
+	check_ptrace();
+	check_sigio();
+}
+
diff --git a/arch/um/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile
index 340ef26..b321361 100644
--- a/arch/um/os-Linux/sys-i386/Makefile
+++ b/arch/um/os-Linux/sys-i386/Makefile
@@ -3,7 +3,7 @@
 # Licensed under the GPL
 #
 
-obj-$(CONFIG_MODE_SKAS) = registers.o
+obj-$(CONFIG_MODE_SKAS) = registers.o tls.o
 
 USER_OBJS := $(obj-y)
 
diff --git a/arch/um/os-Linux/sys-i386/tls.c b/arch/um/os-Linux/sys-i386/tls.c
new file mode 100644
index 0000000..ba21f0e
--- /dev/null
+++ b/arch/um/os-Linux/sys-i386/tls.c
@@ -0,0 +1,33 @@
+#include <linux/unistd.h>
+#include "sysdep/tls.h"
+#include "user_util.h"
+
+static _syscall1(int, get_thread_area, user_desc_t *, u_info);
+
+/* Checks whether host supports TLS, and sets *tls_min according to the value
+ * valid on the host.
+ * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */
+void check_host_supports_tls(int *supports_tls, int *tls_min) {
+	/* Values for x86 and x86_64.*/
+	int val[] = {GDT_ENTRY_TLS_MIN_I386, GDT_ENTRY_TLS_MIN_X86_64};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(val); i++) {
+		user_desc_t info;
+		info.entry_number = val[i];
+
+		if (get_thread_area(&info) == 0) {
+			*tls_min = val[i];
+			*supports_tls = 1;
+			return;
+		} else {
+			if (errno == EINVAL)
+				continue;
+			else if (errno == ENOSYS)
+				*supports_tls = 0;
+				return;
+		}
+	}
+
+	*supports_tls = 0;
+}
diff --git a/arch/um/os-Linux/tls.c b/arch/um/os-Linux/tls.c
new file mode 100644
index 0000000..9cb09a4
--- /dev/null
+++ b/arch/um/os-Linux/tls.c
@@ -0,0 +1,76 @@
+#include <errno.h>
+#include <sys/ptrace.h>
+#include <asm/ldt.h>
+#include "sysdep/tls.h"
+#include "uml-config.h"
+
+/* TLS support - we basically rely on the host's one.*/
+
+/* In TT mode, this should be called only by the tracing thread, and makes sense
+ * only for PTRACE_SET_THREAD_AREA. In SKAS mode, it's used normally.
+ *
+ */
+
+#ifndef PTRACE_GET_THREAD_AREA
+#define PTRACE_GET_THREAD_AREA 25
+#endif
+
+#ifndef PTRACE_SET_THREAD_AREA
+#define PTRACE_SET_THREAD_AREA 26
+#endif
+
+int os_set_thread_area(user_desc_t *info, int pid)
+{
+	int ret;
+
+	ret = ptrace(PTRACE_SET_THREAD_AREA, pid, info->entry_number,
+		     (unsigned long) info);
+	if (ret < 0)
+		ret = -errno;
+	return ret;
+}
+
+#ifdef UML_CONFIG_MODE_SKAS
+
+int os_get_thread_area(user_desc_t *info, int pid)
+{
+	int ret;
+
+	ret = ptrace(PTRACE_GET_THREAD_AREA, pid, info->entry_number,
+		     (unsigned long) info);
+	if (ret < 0)
+		ret = -errno;
+	return ret;
+}
+
+#endif
+
+#ifdef UML_CONFIG_MODE_TT
+#include "linux/unistd.h"
+
+static _syscall1(int, get_thread_area, user_desc_t *, u_info);
+static _syscall1(int, set_thread_area, user_desc_t *, u_info);
+
+int do_set_thread_area_tt(user_desc_t *info)
+{
+	int ret;
+
+	ret = set_thread_area(info);
+	if (ret < 0) {
+		ret = -errno;
+	}
+	return ret;
+}
+
+int do_get_thread_area_tt(user_desc_t *info)
+{
+	int ret;
+
+	ret = get_thread_area(info);
+	if (ret < 0) {
+		ret = -errno;
+	}
+	return ret;
+}
+
+#endif /* UML_CONFIG_MODE_TT */
diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c
index 919d19f..5461a06 100644
--- a/arch/um/os-Linux/tt.c
+++ b/arch/um/os-Linux/tt.c
@@ -110,6 +110,16 @@
 	}
 }
 
+void forward_ipi(int fd, int pid)
+{
+	int err;
+
+	err = os_set_owner(fd, pid);
+	if(err < 0)
+		printk("forward_ipi: set_owner failed, fd = %d, me = %d, "
+		       "target = %d, err = %d\n", fd, os_getpid(), pid, -err);
+}
+
 /*
  *-------------------------
  * only for tt mode (will be deleted in future...)
diff --git a/arch/um/kernel/tty_log.c b/arch/um/os-Linux/tty_log.c
similarity index 91%
rename from arch/um/kernel/tty_log.c
rename to arch/um/os-Linux/tty_log.c
index 9ada656..c6ba56c 100644
--- a/arch/um/kernel/tty_log.c
+++ b/arch/um/os-Linux/tty_log.c
@@ -1,5 +1,5 @@
-/* 
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and 
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and
  * geoffrey hing <ghing@net.ohio-state.edu>
  * Licensed under the GPL
  */
@@ -58,7 +58,7 @@
 		return(tty_log_fd);
 	}
 
-	sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, 
+	sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec,
  		(unsigned int) tv.tv_usec);
 
 	fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))),
@@ -216,15 +216,3 @@
 "    tty data will be written.  Preconfigure the descriptor with something\n"
 "    like '10>tty_log tty_log_fd=10'.\n\n"
 );
-
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c
index ecf107a..198e591 100644
--- a/arch/um/os-Linux/umid.c
+++ b/arch/um/os-Linux/umid.c
@@ -143,8 +143,10 @@
 		goto out_close;
 	}
 
-	if((kill(p, 0) == 0) || (errno != ESRCH))
+	if((kill(p, 0) == 0) || (errno != ESRCH)){
+		printk("umid \"%s\" is already in use by pid %d\n", umid, p);
 		return 1;
+	}
 
 	err = actually_do_remove(dir);
 	if(err)
@@ -234,33 +236,44 @@
 	err = mkdir(tmp, 0777);
 	if(err < 0){
 		err = -errno;
-		if(errno != EEXIST)
+		if(err != -EEXIST)
 			goto err;
 
-		if(not_dead_yet(tmp) < 0)
+		/* 1   -> this umid is already in use
+		 * < 0 -> we couldn't remove the umid directory
+		 * In either case, we can't use this umid, so return -EEXIST.
+		 */
+		if(not_dead_yet(tmp) != 0)
 			goto err;
 
 		err = mkdir(tmp, 0777);
 	}
-	if(err < 0){
-		printk("Failed to create '%s' - err = %d\n", umid, err);
-		goto err_rmdir;
+	if(err){
+		err = -errno;
+		printk("Failed to create '%s' - err = %d\n", umid, -errno);
+		goto err;
 	}
 
 	umid_setup = 1;
 
 	create_pid_file();
 
-	return 0;
-
- err_rmdir:
-	rmdir(tmp);
+	err = 0;
  err:
 	return err;
 }
 
 static int __init make_umid_init(void)
 {
+	if(!make_umid())
+		return 0;
+
+	/* If initializing with the given umid failed, then try again with
+	 * a random one.
+	 */
+	printk("Failed to initialize umid \"%s\", trying with a random umid\n",
+	       umid);
+	*umid = '\0';
 	make_umid();
 
 	return 0;
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules
index 2e41cab..b696b45 100644
--- a/arch/um/scripts/Makefile.rules
+++ b/arch/um/scripts/Makefile.rules
@@ -20,25 +20,7 @@
 	$(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1)))
 endef
 
-
-# cmd_make_link checks to see if the $(foo-dir) variable starts with a /.  If
-# so, it's considered to be a path relative to $(srcdir) rather than
-# $(srcdir)/arch/$(SUBARCH).  This is because x86_64 wants to get ldt.c from
-# arch/um/sys-i386 rather than arch/i386 like the other borrowed files.  So,
-# it sets $(ldt.c-dir) to /arch/um/sys-i386.
-quiet_cmd_make_link = SYMLINK $@
-cmd_make_link       = rm -f $@; ln -sf $(srctree)$(if $(filter-out /%,$($(notdir $@)-dir)),/arch/$(SUBARCH))/$($(notdir $@)-dir)/$(notdir $@) $@
-
-# this needs to be before the foreach, because targets does not accept
-# complete paths like $(obj)/$(f). To make sure this works, use a := assignment
-# or we will get $(obj)/$(f) in the "targets" value.
-# Also, this forces you to use the := syntax when assigning to targets.
-# Otherwise the line below will cause an infinite loop (if you don't know why,
-# just do it).
-
-targets := $(targets) $(SYMLINKS)
-
-SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$(f))
-
-$(SYMLINKS): FORCE
-	$(call if_changed,make_link)
+ifdef subarch-obj-y
+obj-y += subarch.o
+subarch-y = $(addprefix ../../$(SUBARCH)/,$(subarch-obj-y))
+endif
diff --git a/arch/um/scripts/Makefile.unmap b/arch/um/scripts/Makefile.unmap
deleted file mode 100644
index b216518..0000000
--- a/arch/um/scripts/Makefile.unmap
+++ /dev/null
@@ -1,22 +0,0 @@
-clean-files += unmap_tmp.o unmap_fin.o unmap.o
-
-ifdef CONFIG_MODE_TT
-
-#Always build unmap_fin.o
-extra-y += unmap_fin.o
-#Do dependency tracking for unmap.o (it will be always built, but won't get the tracking unless we use this).
-targets += unmap.o
-
-#XXX: partially copied from arch/um/scripts/Makefile.rules
-$(obj)/unmap.o: _c_flags = $(call unprofile,$(CFLAGS))
-
-quiet_cmd_wrapld = LD      $@
-define cmd_wrapld
-	$(LD) $(LDFLAGS) -r -o $(obj)/unmap_tmp.o $< ; \
-	$(OBJCOPY) $(UML_OBJCOPYFLAGS) $(obj)/unmap_tmp.o $@ -G switcheroo
-endef
-
-$(obj)/unmap_fin.o : $(obj)/unmap.o FORCE
-	$(call if_changed,wrapld)
-
-endif
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index f5fd5b0..98b20b7 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -1,23 +1,18 @@
-obj-y := bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
-	ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \
-	sys_call_table.o
+obj-y = bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
+	ptrace_user.o signal.o sigcontext.o syscalls.o sysrq.o \
+	sys_call_table.o tls.o
 
 obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
 
-obj-$(CONFIG_HIGHMEM) += highmem.o
-obj-$(CONFIG_MODULES) += module.o
+subarch-obj-y = lib/bitops.o kernel/semaphore.o
+subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem.o
+subarch-obj-$(CONFIG_MODULES) += kernel/module.o
 
 USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o stub_segv.o
 
-SYMLINKS = bitops.c semaphore.c highmem.c module.c
-
 include arch/um/scripts/Makefile.rules
 
-bitops.c-dir = lib
-semaphore.c-dir = kernel
-highmem.c-dir = mm
-module.c-dir = kernel
+extra-$(CONFIG_MODE_TT) += unmap.o
 
-$(obj)/stub_segv.o : _c_flags = $(call unprofile,$(CFLAGS))
-
-include arch/um/scripts/Makefile.unmap
+$(obj)/stub_segv.o $(obj)/unmap.o: \
+	_c_flags = $(call unprofile,$(CFLAGS))
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
index e839ce6..6028bc7 100644
--- a/arch/um/sys-i386/ptrace.c
+++ b/arch/um/sys-i386/ptrace.c
@@ -6,6 +6,7 @@
 #include <linux/config.h>
 #include <linux/compiler.h>
 #include "linux/sched.h"
+#include "linux/mm.h"
 #include "asm/elf.h"
 #include "asm/ptrace.h"
 #include "asm/uaccess.h"
@@ -14,9 +15,22 @@
 #include "sysdep/sigcontext.h"
 #include "sysdep/sc.h"
 
-void arch_switch(void)
+void arch_switch_to_tt(struct task_struct *from, struct task_struct *to)
 {
-	update_debugregs(current->thread.arch.debugregs_seq);
+	update_debugregs(to->thread.arch.debugregs_seq);
+	arch_switch_tls_tt(from, to);
+}
+
+void arch_switch_to_skas(struct task_struct *from, struct task_struct *to)
+{
+	int err = arch_switch_tls_skas(from, to);
+	if (!err)
+		return;
+
+	if (err != -EINVAL)
+		printk(KERN_WARNING "arch_switch_tls_skas failed, errno %d, not EINVAL\n", -err);
+	else
+		printk(KERN_WARNING "arch_switch_tls_skas failed, errno = EINVAL\n");
 }
 
 int is_syscall(unsigned long addr)
@@ -26,9 +40,17 @@
 
 	n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
 	if(n){
-		printk("is_syscall : failed to read instruction from 0x%lx\n",
-		       addr);
-		return(0);
+		/* access_process_vm() grants access to vsyscall and stub,
+		 * while copy_from_user doesn't. Maybe access_process_vm is
+		 * slow, but that doesn't matter, since it will be called only
+		 * in case of singlestepping, if copy_from_user failed.
+		 */
+		n = access_process_vm(current, addr, &instr, sizeof(instr), 0);
+		if(n != sizeof(instr)) {
+			printk("is_syscall : failed to read instruction from "
+			       "0x%lx\n", addr);
+			return(1);
+		}
 	}
 	/* int 0x80 or sysenter */
 	return((instr == 0x80cd) || (instr == 0x340f));
@@ -115,22 +137,22 @@
 int peek_user(struct task_struct *child, long addr, long data)
 {
 /* read the word at location addr in the USER area. */
-        unsigned long tmp;
+	unsigned long tmp;
 
-        if ((addr & 3) || addr < 0)
-                return -EIO;
+	if ((addr & 3) || addr < 0)
+		return -EIO;
 
-        tmp = 0;  /* Default return condition */
-        if(addr < MAX_REG_OFFSET){
-                tmp = getreg(child, addr);
-        }
-        else if((addr >= offsetof(struct user, u_debugreg[0])) &&
-                (addr <= offsetof(struct user, u_debugreg[7]))){
-                addr -= offsetof(struct user, u_debugreg[0]);
-                addr = addr >> 2;
-                tmp = child->thread.arch.debugregs[addr];
-        }
-        return put_user(tmp, (unsigned long *) data);
+	tmp = 0;  /* Default return condition */
+	if(addr < MAX_REG_OFFSET){
+		tmp = getreg(child, addr);
+	}
+	else if((addr >= offsetof(struct user, u_debugreg[0])) &&
+		(addr <= offsetof(struct user, u_debugreg[7]))){
+		addr -= offsetof(struct user, u_debugreg[0]);
+		addr = addr >> 2;
+		tmp = child->thread.arch.debugregs[addr];
+	}
+	return put_user(tmp, (unsigned long __user *) data);
 }
 
 struct i387_fxsave_struct {
diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
index 7c376c9..9f3bd8e 100644
--- a/arch/um/sys-i386/ptrace_user.c
+++ b/arch/um/sys-i386/ptrace_user.c
@@ -14,6 +14,7 @@
 #include "sysdep/thread.h"
 #include "user.h"
 #include "os.h"
+#include "uml-config.h"
 
 int ptrace_getregs(long pid, unsigned long *regs_out)
 {
@@ -43,6 +44,7 @@
 	return 0;
 }
 
+/* All the below stuff is of interest for TT mode only */
 static void write_debugregs(int pid, unsigned long *regs)
 {
 	struct user *dummy;
@@ -75,7 +77,6 @@
 
 /* Accessed only by the tracing thread */
 static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 };
-static int debugregs_seq = 0;
 
 void arch_enter_kernel(void *task, int pid)
 {
@@ -89,6 +90,11 @@
 	write_debugregs(pid, TASK_DEBUGREGS(task));
 }
 
+#ifdef UML_CONFIG_PT_PROXY
+/* Accessed only by the tracing thread */
+static int debugregs_seq;
+
+/* Only called by the ptrace proxy */
 void ptrace_pokeuser(unsigned long addr, unsigned long data)
 {
 	if((addr < offsetof(struct user, u_debugreg[0])) ||
@@ -109,6 +115,7 @@
 	write_debugregs(pid, kernel_debugregs);
 }
 
+/* Optimized out in its header when not defined */
 void update_debugregs(int seq)
 {
 	int me;
@@ -118,6 +125,7 @@
 	me = os_getpid();
 	initial_thread_cb(update_debugregs_cb, &me);
 }
+#endif
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index 7cd1a82..f5d0e1c 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -19,7 +19,7 @@
 #include "skas.h"
 
 static int copy_sc_from_user_skas(struct pt_regs *regs,
-				  struct sigcontext *from)
+				  struct sigcontext __user *from)
 {
   	struct sigcontext sc;
 	unsigned long fpregs[HOST_FP_SIZE];
@@ -57,8 +57,8 @@
 	return(0);
 }
 
-int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
-                         struct pt_regs *regs)
+int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate __user *to_fp,
+                         struct pt_regs *regs, unsigned long sp)
 {
   	struct sigcontext sc;
 	unsigned long fpregs[HOST_FP_SIZE];
@@ -72,7 +72,7 @@
 	sc.edi = REGS_EDI(regs->regs.skas.regs);
 	sc.esi = REGS_ESI(regs->regs.skas.regs);
 	sc.ebp = REGS_EBP(regs->regs.skas.regs);
-	sc.esp = REGS_SP(regs->regs.skas.regs);
+	sc.esp = sp;
 	sc.ebx = REGS_EBX(regs->regs.skas.regs);
 	sc.edx = REGS_EDX(regs->regs.skas.regs);
 	sc.ecx = REGS_ECX(regs->regs.skas.regs);
@@ -92,7 +92,7 @@
 		       "errno = %d\n", err);
 		return(1);
 	}
-	to_fp = (to_fp ? to_fp : (struct _fpstate *) (to + 1));
+	to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1));
 	sc.fpstate = to_fp;
 
 	if(err)
@@ -113,10 +113,11 @@
  * saved pointer is in the kernel, but the sigcontext is in userspace, so we
  * copy_to_user it.
  */
-int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
+int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from,
 			 int fpsize)
 {
-	struct _fpstate *to_fp, *from_fp;
+	struct _fpstate *to_fp;
+	struct _fpstate __user *from_fp;
 	unsigned long sigs;
 	int err;
 
@@ -131,20 +132,28 @@
 	return(err);
 }
 
-int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
-		       struct sigcontext *from, int fpsize)
+int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate __user *fp,
+		       struct sigcontext *from, int fpsize, unsigned long sp)
 {
-	struct _fpstate *to_fp, *from_fp;
+	struct _fpstate __user *to_fp;
+	struct _fpstate *from_fp;
 	int err;
 
-	to_fp =	(fp ? fp : (struct _fpstate *) (to + 1));
+	to_fp =	(fp ? fp : (struct _fpstate __user *) (to + 1));
 	from_fp = from->fpstate;
 	err = copy_to_user(to, from, sizeof(*to));
+
+	/* The SP in the sigcontext is the updated one for the signal
+	 * delivery.  The sp passed in is the original, and this needs
+	 * to be restored, so we stick it in separately.
+	 */
+	err |= copy_to_user(&SC_SP(to), sp, sizeof(sp));
+
 	if(from_fp != NULL){
 		err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
 		err |= copy_to_user(to_fp, from_fp, fpsize);
 	}
-	return(err);
+	return err;
 }
 #endif
 
@@ -158,15 +167,15 @@
 	return(ret);
 }
 
-static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp,
-			   struct pt_regs *from)
+static int copy_sc_to_user(struct sigcontext *to, struct _fpstate __user *fp,
+			   struct pt_regs *from, unsigned long sp)
 {
 	return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
-					      sizeof(*fp)),
-                           copy_sc_to_user_skas(to, fp, from)));
+					      sizeof(*fp), sp),
+                           copy_sc_to_user_skas(to, fp, from, sp)));
 }
 
-static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp,
+static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __user *fp,
 				 sigset_t *set, unsigned long sp)
 {
 	int err = 0;
@@ -174,14 +183,14 @@
 	err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp);
 	err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags);
 	err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
-	err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs);
+	err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs, sp);
 	err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
 	return(err);
 }
 
 struct sigframe
 {
-	char *pretcode;
+	char __user *pretcode;
 	int sig;
 	struct sigcontext sc;
 	struct _fpstate fpstate;
@@ -191,10 +200,10 @@
 
 struct rt_sigframe
 {
-	char *pretcode;
+	char __user *pretcode;
 	int sig;
-	struct siginfo *pinfo;
-	void *puc;
+	struct siginfo __user *pinfo;
+	void __user *puc;
 	struct siginfo info;
 	struct ucontext uc;
 	struct _fpstate fpstate;
@@ -206,21 +215,32 @@
 			  sigset_t *mask)
 {
 	struct sigframe __user *frame;
-	void *restorer;
+	void __user *restorer;
+	unsigned long save_sp = PT_REGS_SP(regs);
 	int err = 0;
 
 	stack_top &= -8UL;
-	frame = (struct sigframe *) stack_top - 1;
+	frame = (struct sigframe __user *) stack_top - 1;
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		return 1;
 
-	restorer = (void *) frame->retcode;
+	restorer = frame->retcode;
 	if(ka->sa.sa_flags & SA_RESTORER)
 		restorer = ka->sa.sa_restorer;
 
+	/* Update SP now because the page fault handler refuses to extend
+	 * the stack if the faulting address is too far below the current
+	 * SP, which frame now certainly is.  If there's an error, the original
+	 * value is restored on the way out.
+	 * When writing the sigcontext to the stack, we have to write the
+	 * original value, so that's passed to copy_sc_to_user, which does
+	 * the right thing with it.
+	 */
+	PT_REGS_SP(regs) = (unsigned long) frame;
+
 	err |= __put_user(restorer, &frame->pretcode);
 	err |= __put_user(sig, &frame->sig);
-	err |= copy_sc_to_user(&frame->sc, NULL, regs);
+	err |= copy_sc_to_user(&frame->sc, NULL, regs, save_sp);
 	err |= __put_user(mask->sig[0], &frame->sc.oldmask);
 	if (_NSIG_WORDS > 1)
 		err |= __copy_to_user(&frame->extramask, &mask->sig[1],
@@ -238,7 +258,7 @@
 	err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
 
 	if(err)
-		return(err);
+		goto err;
 
 	PT_REGS_SP(regs) = (unsigned long) frame;
 	PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
@@ -248,7 +268,11 @@
 
 	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
 		ptrace_notify(SIGTRAP);
-	return(0);
+	return 0;
+
+err:
+	PT_REGS_SP(regs) = save_sp;
+	return err;
 }
 
 int setup_signal_stack_si(unsigned long stack_top, int sig,
@@ -256,25 +280,29 @@
 			  siginfo_t *info, sigset_t *mask)
 {
 	struct rt_sigframe __user *frame;
-	void *restorer;
+	void __user *restorer;
+	unsigned long save_sp = PT_REGS_SP(regs);
 	int err = 0;
 
 	stack_top &= -8UL;
-	frame = (struct rt_sigframe *) stack_top - 1;
+	frame = (struct rt_sigframe __user *) stack_top - 1;
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		return 1;
 
-	restorer = (void *) frame->retcode;
+	restorer = frame->retcode;
 	if(ka->sa.sa_flags & SA_RESTORER)
 		restorer = ka->sa.sa_restorer;
 
+	/* See comment above about why this is here */
+	PT_REGS_SP(regs) = (unsigned long) frame;
+
 	err |= __put_user(restorer, &frame->pretcode);
 	err |= __put_user(sig, &frame->sig);
 	err |= __put_user(&frame->info, &frame->pinfo);
 	err |= __put_user(&frame->uc, &frame->puc);
 	err |= copy_siginfo_to_user(&frame->info, info);
 	err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask,
-				     PT_REGS_SP(regs));
+				     save_sp);
 
 	/*
 	 * This is movl $,%eax ; int $0x80
@@ -288,9 +316,8 @@
 	err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
 
 	if(err)
-		return(err);
+		goto err;
 
-	PT_REGS_SP(regs) = (unsigned long) frame;
 	PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
 	PT_REGS_EAX(regs) = (unsigned long) sig;
 	PT_REGS_EDX(regs) = (unsigned long) &frame->info;
@@ -298,13 +325,17 @@
 
 	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
 		ptrace_notify(SIGTRAP);
-	return(0);
+	return 0;
+
+err:
+	PT_REGS_SP(regs) = save_sp;
+	return err;
 }
 
 long sys_sigreturn(struct pt_regs regs)
 {
 	unsigned long sp = PT_REGS_SP(&current->thread.regs);
-	struct sigframe __user *frame = (struct sigframe *)(sp - 8);
+	struct sigframe __user *frame = (struct sigframe __user *)(sp - 8);
 	sigset_t set;
 	struct sigcontext __user *sc = &frame->sc;
 	unsigned long __user *oldmask = &sc->oldmask;
@@ -336,8 +367,8 @@
 
 long sys_rt_sigreturn(struct pt_regs regs)
 {
-	unsigned long __user sp = PT_REGS_SP(&current->thread.regs);
-	struct rt_sigframe __user *frame = (struct rt_sigframe *) (sp - 4);
+	unsigned long sp = PT_REGS_SP(&current->thread.regs);
+	struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (sp - 4);
 	sigset_t set;
 	struct ucontext __user *uc = &frame->uc;
 	int sig_size = _NSIG_WORDS * sizeof(unsigned long);
diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S
index ad75c27..1ff6147 100644
--- a/arch/um/sys-i386/sys_call_table.S
+++ b/arch/um/sys-i386/sys_call_table.S
@@ -6,8 +6,6 @@
 
 #define sys_vm86old sys_ni_syscall
 #define sys_vm86 sys_ni_syscall
-#define sys_set_thread_area sys_ni_syscall
-#define sys_get_thread_area sys_ni_syscall
 
 #define sys_stime um_stime
 #define sys_time um_time
diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c
index 83e9be8..749dd1b 100644
--- a/arch/um/sys-i386/syscalls.c
+++ b/arch/um/sys-i386/syscalls.c
@@ -61,21 +61,27 @@
 	return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
 }
 
-/* The i386 version skips reading from %esi, the fourth argument. So we must do
- * this, too.
+/*
+ * The prototype on i386 is:
+ *
+ *     int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls, int * child_tidptr)
+ *
+ * and the "newtls" arg. on i386 is read by copy_thread directly from the
+ * register saved on the stack.
  */
 long sys_clone(unsigned long clone_flags, unsigned long newsp,
-	       int __user *parent_tid, int unused, int __user *child_tid)
+	       int __user *parent_tid, void *newtls, int __user *child_tid)
 {
 	long ret;
 
 	if (!newsp)
 		newsp = UPT_SP(&current->thread.regs.regs);
+
 	current->thread.forking = 1;
 	ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
 		      child_tid);
 	current->thread.forking = 0;
-	return(ret);
+	return ret;
 }
 
 /*
@@ -104,7 +110,7 @@
 		union semun fourth;
 		if (!ptr)
 			return -EINVAL;
-		if (get_user(fourth.__pad, (void **) ptr))
+		if (get_user(fourth.__pad, (void __user * __user *) ptr))
 			return -EFAULT;
 		return sys_semctl (first, second, third, fourth);
 	}
diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c
new file mode 100644
index 0000000..a3188e8
--- /dev/null
+++ b/arch/um/sys-i386/tls.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2005 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/kernel.h"
+#include "linux/sched.h"
+#include "linux/slab.h"
+#include "linux/types.h"
+#include "asm/uaccess.h"
+#include "asm/ptrace.h"
+#include "asm/segment.h"
+#include "asm/smp.h"
+#include "asm/desc.h"
+#include "choose-mode.h"
+#include "kern.h"
+#include "kern_util.h"
+#include "mode_kern.h"
+#include "os.h"
+#include "mode.h"
+
+#ifdef CONFIG_MODE_SKAS
+#include "skas.h"
+#endif
+
+/* If needed we can detect when it's uninitialized. */
+static int host_supports_tls = -1;
+int host_gdt_entry_tls_min = -1;
+
+#ifdef CONFIG_MODE_SKAS
+int do_set_thread_area_skas(struct user_desc *info)
+{
+	int ret;
+	u32 cpu;
+
+	cpu = get_cpu();
+	ret = os_set_thread_area(info, userspace_pid[cpu]);
+	put_cpu();
+	return ret;
+}
+
+int do_get_thread_area_skas(struct user_desc *info)
+{
+	int ret;
+	u32 cpu;
+
+	cpu = get_cpu();
+	ret = os_get_thread_area(info, userspace_pid[cpu]);
+	put_cpu();
+	return ret;
+}
+#endif
+
+/*
+ * sys_get_thread_area: get a yet unused TLS descriptor index.
+ * XXX: Consider leaving one free slot for glibc usage at first place. This must
+ * be done here (and by changing GDT_ENTRY_TLS_* macros) and nowhere else.
+ *
+ * Also, this must be tested when compiling in SKAS mode with dinamic linking
+ * and running against NPTL.
+ */
+static int get_free_idx(struct task_struct* task)
+{
+	struct thread_struct *t = &task->thread;
+	int idx;
+
+	if (!t->arch.tls_array)
+		return GDT_ENTRY_TLS_MIN;
+
+	for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++)
+		if (!t->arch.tls_array[idx].present)
+			return idx + GDT_ENTRY_TLS_MIN;
+	return -ESRCH;
+}
+
+static inline void clear_user_desc(struct user_desc* info)
+{
+	/* Postcondition: LDT_empty(info) returns true. */
+	memset(info, 0, sizeof(*info));
+
+	/* Check the LDT_empty or the i386 sys_get_thread_area code - we obtain
+	 * indeed an empty user_desc.
+	 */
+	info->read_exec_only = 1;
+	info->seg_not_present = 1;
+}
+
+#define O_FORCE 1
+
+static int load_TLS(int flags, struct task_struct *to)
+{
+	int ret = 0;
+	int idx;
+
+	for (idx = GDT_ENTRY_TLS_MIN; idx < GDT_ENTRY_TLS_MAX; idx++) {
+		struct uml_tls_struct* curr = &to->thread.arch.tls_array[idx - GDT_ENTRY_TLS_MIN];
+
+		/* Actually, now if it wasn't flushed it gets cleared and
+		 * flushed to the host, which will clear it.*/
+		if (!curr->present) {
+			if (!curr->flushed) {
+				clear_user_desc(&curr->tls);
+				curr->tls.entry_number = idx;
+			} else {
+				WARN_ON(!LDT_empty(&curr->tls));
+				continue;
+			}
+		}
+
+		if (!(flags & O_FORCE) && curr->flushed)
+			continue;
+
+		ret = do_set_thread_area(&curr->tls);
+		if (ret)
+			goto out;
+
+		curr->flushed = 1;
+	}
+out:
+	return ret;
+}
+
+/* Verify if we need to do a flush for the new process, i.e. if there are any
+ * present desc's, only if they haven't been flushed.
+ */
+static inline int needs_TLS_update(struct task_struct *task)
+{
+	int i;
+	int ret = 0;
+
+	for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) {
+		struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN];
+
+		/* Can't test curr->present, we may need to clear a descriptor
+		 * which had a value. */
+		if (curr->flushed)
+			continue;
+		ret = 1;
+		break;
+	}
+	return ret;
+}
+
+/* On a newly forked process, the TLS descriptors haven't yet been flushed. So
+ * we mark them as such and the first switch_to will do the job.
+ */
+void clear_flushed_tls(struct task_struct *task)
+{
+	int i;
+
+	for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) {
+		struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN];
+
+		/* Still correct to do this, if it wasn't present on the host it
+		 * will remain as flushed as it was. */
+		if (!curr->present)
+			continue;
+
+		curr->flushed = 0;
+	}
+}
+
+/* In SKAS0 mode, currently, multiple guest threads sharing the same ->mm have a
+ * common host process. So this is needed in SKAS0 too.
+ *
+ * However, if each thread had a different host process (and this was discussed
+ * for SMP support) this won't be needed.
+ *
+ * And this will not need be used when (and if) we'll add support to the host
+ * SKAS patch. */
+
+int arch_switch_tls_skas(struct task_struct *from, struct task_struct *to)
+{
+	if (!host_supports_tls)
+		return 0;
+
+	/* We have no need whatsoever to switch TLS for kernel threads; beyond
+	 * that, that would also result in us calling os_set_thread_area with
+	 * userspace_pid[cpu] == 0, which gives an error. */
+	if (likely(to->mm))
+		return load_TLS(O_FORCE, to);
+
+	return 0;
+}
+
+int arch_switch_tls_tt(struct task_struct *from, struct task_struct *to)
+{
+	if (!host_supports_tls)
+		return 0;
+
+	if (needs_TLS_update(to))
+		return load_TLS(0, to);
+
+	return 0;
+}
+
+static int set_tls_entry(struct task_struct* task, struct user_desc *info,
+			 int idx, int flushed)
+{
+	struct thread_struct *t = &task->thread;
+
+	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
+		return -EINVAL;
+
+	t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls = *info;
+	t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present = 1;
+	t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed = flushed;
+
+	return 0;
+}
+
+int arch_copy_tls(struct task_struct *new)
+{
+	struct user_desc info;
+	int idx, ret = -EFAULT;
+
+	if (copy_from_user(&info,
+			   (void __user *) UPT_ESI(&new->thread.regs.regs),
+			   sizeof(info)))
+		goto out;
+
+	ret = -EINVAL;
+	if (LDT_empty(&info))
+		goto out;
+
+	idx = info.entry_number;
+
+	ret = set_tls_entry(new, &info, idx, 0);
+out:
+	return ret;
+}
+
+/* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */
+static int get_tls_entry(struct task_struct* task, struct user_desc *info, int idx)
+{
+	struct thread_struct *t = &task->thread;
+
+	if (!t->arch.tls_array)
+		goto clear;
+
+	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
+		return -EINVAL;
+
+	if (!t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present)
+		goto clear;
+
+	*info = t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls;
+
+out:
+	/* Temporary debugging check, to make sure that things have been
+	 * flushed. This could be triggered if load_TLS() failed.
+	 */
+	if (unlikely(task == current && !t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed)) {
+		printk(KERN_ERR "get_tls_entry: task with pid %d got here "
+				"without flushed TLS.", current->pid);
+	}
+
+	return 0;
+clear:
+	/* When the TLS entry has not been set, the values read to user in the
+	 * tls_array are 0 (because it's cleared at boot, see
+	 * arch/i386/kernel/head.S:cpu_gdt_table). Emulate that.
+	 */
+	clear_user_desc(info);
+	info->entry_number = idx;
+	goto out;
+}
+
+asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc)
+{
+	struct user_desc info;
+	int idx, ret;
+
+	if (!host_supports_tls)
+		return -ENOSYS;
+
+	if (copy_from_user(&info, user_desc, sizeof(info)))
+		return -EFAULT;
+
+	idx = info.entry_number;
+
+	if (idx == -1) {
+		idx = get_free_idx(current);
+		if (idx < 0)
+			return idx;
+		info.entry_number = idx;
+		/* Tell the user which slot we chose for him.*/
+		if (put_user(idx, &user_desc->entry_number))
+			return -EFAULT;
+	}
+
+	ret = CHOOSE_MODE_PROC(do_set_thread_area_tt, do_set_thread_area_skas, &info);
+	if (ret)
+		return ret;
+	return set_tls_entry(current, &info, idx, 1);
+}
+
+/*
+ * Perform set_thread_area on behalf of the traced child.
+ * Note: error handling is not done on the deferred load, and this differ from
+ * i386. However the only possible error are caused by bugs.
+ */
+int ptrace_set_thread_area(struct task_struct *child, int idx,
+		struct user_desc __user *user_desc)
+{
+	struct user_desc info;
+
+	if (!host_supports_tls)
+		return -EIO;
+
+	if (copy_from_user(&info, user_desc, sizeof(info)))
+		return -EFAULT;
+
+	return set_tls_entry(child, &info, idx, 0);
+}
+
+asmlinkage int sys_get_thread_area(struct user_desc __user *user_desc)
+{
+	struct user_desc info;
+	int idx, ret;
+
+	if (!host_supports_tls)
+		return -ENOSYS;
+
+	if (get_user(idx, &user_desc->entry_number))
+		return -EFAULT;
+
+	ret = get_tls_entry(current, &info, idx);
+	if (ret < 0)
+		goto out;
+
+	if (copy_to_user(user_desc, &info, sizeof(info)))
+		ret = -EFAULT;
+
+out:
+	return ret;
+}
+
+/*
+ * Perform get_thread_area on behalf of the traced child.
+ */
+int ptrace_get_thread_area(struct task_struct *child, int idx,
+		struct user_desc __user *user_desc)
+{
+	struct user_desc info;
+	int ret;
+
+	if (!host_supports_tls)
+		return -EIO;
+
+	ret = get_tls_entry(child, &info, idx);
+	if (ret < 0)
+		goto out;
+
+	if (copy_to_user(user_desc, &info, sizeof(info)))
+		ret = -EFAULT;
+out:
+	return ret;
+}
+
+
+/* XXX: This part is probably common to i386 and x86-64. Don't create a common
+ * file for now, do that when implementing x86-64 support.*/
+static int __init __setup_host_supports_tls(void) {
+	check_host_supports_tls(&host_supports_tls, &host_gdt_entry_tls_min);
+	if (host_supports_tls) {
+		printk(KERN_INFO "Host TLS support detected\n");
+		printk(KERN_INFO "Detected host type: ");
+		switch (host_gdt_entry_tls_min) {
+			case GDT_ENTRY_TLS_MIN_I386:
+				printk("i386\n");
+				break;
+			case GDT_ENTRY_TLS_MIN_X86_64:
+				printk("x86_64\n");
+				break;
+		}
+	} else
+		printk(KERN_ERR "  Host TLS support NOT detected! "
+				"TLS support inside UML will not work\n");
+	return 1;
+}
+
+__initcall(__setup_host_supports_tls);
diff --git a/arch/um/sys-i386/user-offsets.c b/arch/um/sys-i386/user-offsets.c
index 26b6867..6f4ef2b 100644
--- a/arch/um/sys-i386/user-offsets.c
+++ b/arch/um/sys-i386/user-offsets.c
@@ -3,12 +3,13 @@
 #include <asm/ptrace.h>
 #include <asm/user.h>
 #include <linux/stddef.h>
+#include <sys/poll.h>
 
 #define DEFINE(sym, val) \
-        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+	asm volatile("\n->" #sym " %0 " #val : : "i" (val))
 
 #define DEFINE_LONGS(sym, val) \
-        asm volatile("\n->" #sym " %0 " #val : : "i" (val/sizeof(unsigned long)))
+	asm volatile("\n->" #sym " %0 " #val : : "i" (val/sizeof(unsigned long)))
 
 #define OFFSET(sym, str, mem) \
 	DEFINE(sym, offsetof(struct str, mem));
@@ -67,4 +68,9 @@
 	DEFINE(HOST_ES, ES);
 	DEFINE(HOST_GS, GS);
 	DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct));
+
+	/* XXX Duplicated between i386 and x86_64 */
+	DEFINE(UM_POLLIN, POLLIN);
+	DEFINE(UM_POLLPRI, POLLPRI);
+	DEFINE(UM_POLLOUT, POLLOUT);
 }
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index a351091..b5fc22b 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -4,31 +4,23 @@
 # Licensed under the GPL
 #
 
-#XXX: why into lib-y?
-lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o ldt.o mem.o memcpy.o \
-	ptrace.o ptrace_user.o sigcontext.o signal.o syscalls.o \
-	syscall_table.o sysrq.o thunk.o
-lib-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
+obj-y = bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
+	sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o ksyms.o \
+	tls.o
 
-obj-y := ksyms.o
-obj-$(CONFIG_MODULES) += module.o um_module.o
+obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
+obj-$(CONFIG_MODULES) += um_module.o
+
+subarch-obj-y = lib/bitops.o lib/csum-partial.o lib/memcpy.o lib/thunk.o
+subarch-obj-$(CONFIG_MODULES) += kernel/module.o
+
+ldt-y = ../sys-i386/ldt.o
 
 USER_OBJS := ptrace_user.o sigcontext.o stub_segv.o
 
-SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c ldt.c memcpy.S \
-	thunk.S module.c
-
 include arch/um/scripts/Makefile.rules
 
-bitops.c-dir = lib
-csum-copy.S-dir = lib
-csum-partial.c-dir = lib
-csum-wrappers.c-dir = lib
-ldt.c-dir = /arch/um/sys-i386
-memcpy.S-dir = lib
-thunk.S-dir = lib
-module.c-dir = kernel
+extra-$(CONFIG_MODE_TT) += unmap.o
 
-$(obj)/stub_segv.o: _c_flags = $(call unprofile,$(CFLAGS))
-
-include arch/um/scripts/Makefile.unmap
+$(obj)/stub_segv.o $(obj)/unmap.o: \
+	_c_flags = $(call unprofile,$(CFLAGS))
diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c
index 74eee5c..147bbf0 100644
--- a/arch/um/sys-x86_64/ptrace.c
+++ b/arch/um/sys-x86_64/ptrace.c
@@ -8,6 +8,7 @@
 #include <asm/ptrace.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
+#include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/elf.h>
 
@@ -136,9 +137,28 @@
 */
 }
 
+/* XXX Mostly copied from sys-i386 */
 int is_syscall(unsigned long addr)
 {
-	panic("is_syscall");
+	unsigned short instr;
+	int n;
+
+	n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
+	if(n){
+		/* access_process_vm() grants access to vsyscall and stub,
+		 * while copy_from_user doesn't. Maybe access_process_vm is
+		 * slow, but that doesn't matter, since it will be called only
+		 * in case of singlestepping, if copy_from_user failed.
+		 */
+		n = access_process_vm(current, addr, &instr, sizeof(instr), 0);
+		if(n != sizeof(instr)) {
+			printk("is_syscall : failed to read instruction from "
+			       "0x%lx\n", addr);
+			return(1);
+		}
+	}
+	/* sysenter */
+	return(instr == 0x050f);
 }
 
 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu )
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
index fe1d065..e75c4e1 100644
--- a/arch/um/sys-x86_64/signal.c
+++ b/arch/um/sys-x86_64/signal.c
@@ -55,7 +55,8 @@
 }
 
 int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
-                        struct pt_regs *regs, unsigned long mask)
+			 struct pt_regs *regs, unsigned long mask,
+			 unsigned long sp)
 {
         struct faultinfo * fi = &current->thread.arch.faultinfo;
 	int err = 0;
@@ -70,7 +71,11 @@
 	err |= PUTREG(regs, RDI, to, rdi);
 	err |= PUTREG(regs, RSI, to, rsi);
 	err |= PUTREG(regs, RBP, to, rbp);
-	err |= PUTREG(regs, RSP, to, rsp);
+        /* Must use orignal RSP, which is passed in, rather than what's in
+         * the pt_regs, because that's already been updated to point at the
+         * signal frame.
+         */
+	err |= __put_user(sp, &to->rsp);
 	err |= PUTREG(regs, RBX, to, rbx);
 	err |= PUTREG(regs, RDX, to, rdx);
 	err |= PUTREG(regs, RCX, to, rcx);
@@ -102,7 +107,7 @@
 
 #ifdef CONFIG_MODE_TT
 int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
-                        int fpsize)
+			 int fpsize)
 {
 	struct _fpstate *to_fp, *from_fp;
 	unsigned long sigs;
@@ -120,7 +125,7 @@
 }
 
 int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
-                      struct sigcontext *from, int fpsize)
+		       struct sigcontext *from, int fpsize, unsigned long sp)
 {
 	struct _fpstate *to_fp, *from_fp;
 	int err;
@@ -128,11 +133,17 @@
 	to_fp = (fp ? fp : (struct _fpstate *) (to + 1));
 	from_fp = from->fpstate;
 	err = copy_to_user(to, from, sizeof(*to));
+	/* The SP in the sigcontext is the updated one for the signal
+	 * delivery.  The sp passed in is the original, and this needs
+	 * to be restored, so we stick it in separately.
+	 */
+	err |= copy_to_user(&SC_SP(to), sp, sizeof(sp));
+
 	if(from_fp != NULL){
 		err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
 		err |= copy_to_user(to_fp, from_fp, fpsize);
 	}
-	return(err);
+	return err;
 }
 
 #endif
@@ -148,11 +159,12 @@
 }
 
 static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp,
-                          struct pt_regs *from, unsigned long mask)
+			   struct pt_regs *from, unsigned long mask,
+			   unsigned long sp)
 {
        return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
-                                             sizeof(*fp)),
-                          copy_sc_to_user_skas(to, fp, from, mask)));
+                                             sizeof(*fp), sp),
+                          copy_sc_to_user_skas(to, fp, from, mask, sp)));
 }
 
 struct rt_sigframe
@@ -170,6 +182,7 @@
 {
 	struct rt_sigframe __user *frame;
 	struct _fpstate __user *fp = NULL;
+	unsigned long save_sp = PT_REGS_RSP(regs);
 	int err = 0;
 	struct task_struct *me = current;
 
@@ -193,14 +206,25 @@
 			goto out;
 	}
 
+	/* Update SP now because the page fault handler refuses to extend
+	 * the stack if the faulting address is too far below the current
+	 * SP, which frame now certainly is.  If there's an error, the original
+	 * value is restored on the way out.
+	 * When writing the sigcontext to the stack, we have to write the
+	 * original value, so that's passed to copy_sc_to_user, which does
+	 * the right thing with it.
+	 */
+	PT_REGS_RSP(regs) = (unsigned long) frame;
+
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->uc.uc_flags);
 	err |= __put_user(0, &frame->uc.uc_link);
 	err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-	err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)),
+	err |= __put_user(sas_ss_flags(save_sp),
 			  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
-	err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
+	err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0],
+		save_sp);
 	err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate);
 	if (sizeof(*set) == 16) {
 		__put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
@@ -217,10 +241,10 @@
 		err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
 	else
 		/* could use a vstub here */
-		goto out;
+		goto restore_sp;
 
 	if (err)
-		goto out;
+		goto restore_sp;
 
 	/* Set up registers for signal handler */
 	{
@@ -238,10 +262,12 @@
 	PT_REGS_RSI(regs) = (unsigned long) &frame->info;
 	PT_REGS_RDX(regs) = (unsigned long) &frame->uc;
 	PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler;
-
-	PT_REGS_RSP(regs) = (unsigned long) frame;
  out:
-	return(err);
+	return err;
+
+restore_sp:
+	PT_REGS_RSP(regs) = save_sp;
+	return err;
 }
 
 long sys_rt_sigreturn(struct pt_regs *regs)
diff --git a/arch/um/sys-x86_64/tls.c b/arch/um/sys-x86_64/tls.c
new file mode 100644
index 0000000..ce1bf1b
--- /dev/null
+++ b/arch/um/sys-x86_64/tls.c
@@ -0,0 +1,14 @@
+#include "linux/sched.h"
+
+void debug_arch_force_load_TLS(void)
+{
+}
+
+void clear_flushed_tls(struct task_struct *task)
+{
+}
+
+int arch_copy_tls(struct task_struct *t)
+{
+        return 0;
+}
diff --git a/arch/um/sys-x86_64/user-offsets.c b/arch/um/sys-x86_64/user-offsets.c
index 7bd54a9..899cebb 100644
--- a/arch/um/sys-x86_64/user-offsets.c
+++ b/arch/um/sys-x86_64/user-offsets.c
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <stddef.h>
 #include <signal.h>
+#include <sys/poll.h>
 #define __FRAME_OFFSETS
 #include <asm/ptrace.h>
 #include <asm/types.h>
@@ -88,4 +89,9 @@
 	DEFINE_LONGS(HOST_IP, RIP);
 	DEFINE_LONGS(HOST_SP, RSP);
 	DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct));
+
+	/* XXX Duplicated between i386 and x86_64 */
+	DEFINE(UM_POLLIN, POLLIN);
+	DEFINE(UM_POLLPRI, POLLPRI);
+	DEFINE(UM_POLLOUT, POLLOUT);
 }
diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig
index e7fc3e5..37ec644 100644
--- a/arch/v850/Kconfig
+++ b/arch/v850/Kconfig
@@ -16,6 +16,12 @@
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 	default n
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+config GENERIC_HWEIGHT
+	bool
+	default y
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 6420bae..4310b4a 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -45,6 +45,10 @@
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
@@ -246,6 +250,15 @@
 	  cost of slightly increased overhead in some places. If unsure say
 	  N here.
 
+config SCHED_MC
+	bool "Multi-core scheduler support"
+	depends on SMP
+	default y
+	help
+	  Multi-core scheduler support improves the CPU scheduler's decision
+	  making when dealing with multi-core CPU chips at a cost of slightly
+	  increased overhead in some places. If unsure say N here.
+
 source "kernel/Kconfig.preempt"
 
 config NUMA
@@ -321,6 +334,10 @@
 	def_bool y
 	depends on NUMA
 
+config OUT_OF_LINE_PFN_TO_PAGE
+	def_bool y
+	depends on DISCONTIGMEM
+
 config NR_CPUS
 	int "Maximum number of CPUs (2-256)"
 	range 2 255
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index 0fbc028..585fd4a 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -70,7 +70,7 @@
 boot := arch/x86_64/boot
 
 PHONY += bzImage bzlilo install archmrproper \
-	 fdimage fdimage144 fdimage288 archclean
+	 fdimage fdimage144 fdimage288 isoimage archclean
 
 #Default target when executing "make"
 all: bzImage
@@ -87,7 +87,7 @@
 bzdisk: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) zdisk
 
-fdimage fdimage144 fdimage288: vmlinux
+fdimage fdimage144 fdimage288 isoimage: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@
 
 install:
@@ -99,11 +99,16 @@
 define archhelp
   echo  '* bzImage	- Compressed kernel image (arch/$(ARCH)/boot/bzImage)'
   echo  '  install	- Install kernel using'
-  echo  '                  (your) ~/bin/installkernel or'
-  echo  '                  (distribution) /sbin/installkernel or'
-  echo  '        	  install to $$(INSTALL_PATH) and run lilo'
+  echo  '		   (your) ~/bin/installkernel or'
+  echo  '		   (distribution) /sbin/installkernel or'
+  echo  '		   install to $$(INSTALL_PATH) and run lilo'
+  echo  '  bzdisk       - Create a boot floppy in /dev/fd0'
+  echo  '  fdimage      - Create a boot floppy image'
+  echo  '  isoimage     - Create a boot CD-ROM image'
 endef
 
-CLEAN_FILES += arch/$(ARCH)/boot/fdimage arch/$(ARCH)/boot/mtools.conf
+CLEAN_FILES += arch/$(ARCH)/boot/fdimage \
+	       arch/$(ARCH)/boot/image.iso \
+	       arch/$(ARCH)/boot/mtools.conf
 
 
diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile
index 29f8396..43ee6c5 100644
--- a/arch/x86_64/boot/Makefile
+++ b/arch/x86_64/boot/Makefile
@@ -60,8 +60,12 @@
 $(obj)/compressed/vmlinux: FORCE
 	$(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
 
-# Set this if you want to pass append arguments to the zdisk/fdimage kernel
+# Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
 FDARGS = 
+# Set this if you want an initrd included with the zdisk/fdimage/isoimage kernel
+FDINITRD =
+
+image_cmdline = default linux $(FDARGS) $(if $(FDINITRD),initrd=initrd.img,)
 
 $(obj)/mtools.conf: $(src)/mtools.conf.in
 	sed -e 's|@OBJ@|$(obj)|g' < $< > $@
@@ -70,8 +74,11 @@
 zdisk: $(BOOTIMAGE) $(obj)/mtools.conf
 	MTOOLSRC=$(obj)/mtools.conf mformat a:			; sync
 	syslinux /dev/fd0					; sync
-	echo 'default linux $(FDARGS)' | \
+	echo '$(image_cmdline)' | \
 		MTOOLSRC=$(obj)/mtools.conf mcopy - a:syslinux.cfg
+	if [ -f '$(FDINITRD)' ] ; then \
+		MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' a:initrd.img ; \
+	fi
 	MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) a:linux	; sync
 
 # These require being root or having syslinux 2.02 or higher installed
@@ -79,18 +86,39 @@
 	dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=1440
 	MTOOLSRC=$(obj)/mtools.conf mformat v:			; sync
 	syslinux $(obj)/fdimage					; sync
-	echo 'default linux $(FDARGS)' | \
+	echo '$(image_cmdline)' | \
 		MTOOLSRC=$(obj)/mtools.conf mcopy - v:syslinux.cfg
+	if [ -f '$(FDINITRD)' ] ; then \
+		MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' v:initrd.img ; \
+	fi
 	MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) v:linux	; sync
 
 fdimage288: $(BOOTIMAGE) $(obj)/mtools.conf
 	dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=2880
 	MTOOLSRC=$(obj)/mtools.conf mformat w:			; sync
 	syslinux $(obj)/fdimage					; sync
-	echo 'default linux $(FDARGS)' | \
+	echo '$(image_cmdline)' | \
 		MTOOLSRC=$(obj)/mtools.conf mcopy - w:syslinux.cfg
+	if [ -f '$(FDINITRD)' ] ; then \
+		MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' w:initrd.img ; \
+	fi
 	MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) w:linux	; sync
 
+isoimage: $(BOOTIMAGE)
+	-rm -rf $(obj)/isoimage
+	mkdir $(obj)/isoimage
+	cp `echo /usr/lib*/syslinux/isolinux.bin | awk '{ print $1; }'` \
+		$(obj)/isoimage
+	cp $(BOOTIMAGE) $(obj)/isoimage/linux
+	echo '$(image_cmdline)' > $(obj)/isoimage/isolinux.cfg
+	if [ -f '$(FDINITRD)' ] ; then \
+		cp '$(FDINITRD)' $(obj)/isoimage/initrd.img ; \
+	fi
+	mkisofs -J -r -o $(obj)/image.iso -b isolinux.bin -c boot.cat \
+		-no-emul-boot -boot-load-size 4 -boot-info-table \
+		$(obj)/isoimage
+	rm -rf $(obj)/isoimage
+
 zlilo: $(BOOTIMAGE)
 	if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
 	if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index 00dee17..35b2fac 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -501,7 +501,7 @@
 	.quad sys_setdomainname
 	.quad sys_uname
 	.quad sys_modify_ldt
-	.quad sys32_adjtimex
+	.quad compat_sys_adjtimex
 	.quad sys32_mprotect		/* 125 */
 	.quad compat_sys_sigprocmask
 	.quad quiet_ni_syscall		/* create_module */
@@ -688,6 +688,8 @@
 	.quad sys_ni_syscall		/* pselect6 for now */
 	.quad sys_ni_syscall		/* ppoll for now */
 	.quad sys_unshare		/* 310 */
+	.quad compat_sys_set_robust_list
+	.quad compat_sys_get_robust_list
 ia32_syscall_end:		
 	.rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
 		.quad ni_syscall
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
index 2b2d029..f182b20 100644
--- a/arch/x86_64/ia32/sys_ia32.c
+++ b/arch/x86_64/ia32/sys_ia32.c
@@ -30,7 +30,6 @@
 #include <linux/resource.h>
 #include <linux/times.h>
 #include <linux/utsname.h>
-#include <linux/timex.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/sem.h>
@@ -767,82 +766,6 @@
 	return ret;
 }
 
-/* Handle adjtimex compatibility. */
-
-struct timex32 {
-	u32 modes;
-	s32 offset, freq, maxerror, esterror;
-	s32 status, constant, precision, tolerance;
-	struct compat_timeval time;
-	s32 tick;
-	s32 ppsfreq, jitter, shift, stabil;
-	s32 jitcnt, calcnt, errcnt, stbcnt;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-	s32  :32; s32  :32; s32  :32; s32  :32;
-};
-
-extern int do_adjtimex(struct timex *);
-
-asmlinkage long
-sys32_adjtimex(struct timex32 __user *utp)
-{
-	struct timex txc;
-	int ret;
-
-	memset(&txc, 0, sizeof(struct timex));
-
-	if (!access_ok(VERIFY_READ, utp, sizeof(struct timex32)) ||
-	   __get_user(txc.modes, &utp->modes) ||
-	   __get_user(txc.offset, &utp->offset) ||
-	   __get_user(txc.freq, &utp->freq) ||
-	   __get_user(txc.maxerror, &utp->maxerror) ||
-	   __get_user(txc.esterror, &utp->esterror) ||
-	   __get_user(txc.status, &utp->status) ||
-	   __get_user(txc.constant, &utp->constant) ||
-	   __get_user(txc.precision, &utp->precision) ||
-	   __get_user(txc.tolerance, &utp->tolerance) ||
-	   __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	   __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	   __get_user(txc.tick, &utp->tick) ||
-	   __get_user(txc.ppsfreq, &utp->ppsfreq) ||
-	   __get_user(txc.jitter, &utp->jitter) ||
-	   __get_user(txc.shift, &utp->shift) ||
-	   __get_user(txc.stabil, &utp->stabil) ||
-	   __get_user(txc.jitcnt, &utp->jitcnt) ||
-	   __get_user(txc.calcnt, &utp->calcnt) ||
-	   __get_user(txc.errcnt, &utp->errcnt) ||
-	   __get_user(txc.stbcnt, &utp->stbcnt))
-		return -EFAULT;
-
-	ret = do_adjtimex(&txc);
-
-	if (!access_ok(VERIFY_WRITE, utp, sizeof(struct timex32)) ||
-	   __put_user(txc.modes, &utp->modes) ||
-	   __put_user(txc.offset, &utp->offset) ||
-	   __put_user(txc.freq, &utp->freq) ||
-	   __put_user(txc.maxerror, &utp->maxerror) ||
-	   __put_user(txc.esterror, &utp->esterror) ||
-	   __put_user(txc.status, &utp->status) ||
-	   __put_user(txc.constant, &utp->constant) ||
-	   __put_user(txc.precision, &utp->precision) ||
-	   __put_user(txc.tolerance, &utp->tolerance) ||
-	   __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-	   __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-	   __put_user(txc.tick, &utp->tick) ||
-	   __put_user(txc.ppsfreq, &utp->ppsfreq) ||
-	   __put_user(txc.jitter, &utp->jitter) ||
-	   __put_user(txc.shift, &utp->shift) ||
-	   __put_user(txc.stabil, &utp->stabil) ||
-	   __put_user(txc.jitcnt, &utp->jitcnt) ||
-	   __put_user(txc.calcnt, &utp->calcnt) ||
-	   __put_user(txc.errcnt, &utp->errcnt) ||
-	   __put_user(txc.stbcnt, &utp->stbcnt))
-		ret = -EFAULT;
-
-	return ret;
-}
-
 asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
 	unsigned long prot, unsigned long flags,
 	unsigned long fd, unsigned long pgoff)
diff --git a/arch/x86_64/ia32/vsyscall-sigreturn.S b/arch/x86_64/ia32/vsyscall-sigreturn.S
index d90321f..1384367 100644
--- a/arch/x86_64/ia32/vsyscall-sigreturn.S
+++ b/arch/x86_64/ia32/vsyscall-sigreturn.S
@@ -32,9 +32,28 @@
 	.size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn
 
 	.section .eh_frame,"a",@progbits
+.LSTARTFRAMES:
+        .long .LENDCIES-.LSTARTCIES
+.LSTARTCIES:
+	.long 0			/* CIE ID */
+	.byte 1			/* Version number */
+	.string "zRS"		/* NUL-terminated augmentation string */
+	.uleb128 1		/* Code alignment factor */
+	.sleb128 -4		/* Data alignment factor */
+	.byte 8			/* Return address register column */
+	.uleb128 1		/* Augmentation value length */
+	.byte 0x1b		/* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
+	.byte 0x0c		/* DW_CFA_def_cfa */
+	.uleb128 4
+	.uleb128 4
+	.byte 0x88		/* DW_CFA_offset, column 0x8 */
+	.uleb128 1
+	.align 4
+.LENDCIES:
+
 	.long .LENDFDE2-.LSTARTFDE2	/* Length FDE */
 .LSTARTFDE2:
-	.long .LSTARTFDE2-.LSTARTFRAME	/* CIE pointer */
+	.long .LSTARTFDE2-.LSTARTFRAMES	/* CIE pointer */
 	/* HACK: The dwarf2 unwind routines will subtract 1 from the
 	   return address to get an address in the middle of the
 	   presumed call instruction.  Since we didn't get here via
@@ -97,7 +116,7 @@
 
 	.long .LENDFDE3-.LSTARTFDE3	/* Length FDE */
 .LSTARTFDE3:
-	.long .LSTARTFDE3-.LSTARTFRAME	/* CIE pointer */
+	.long .LSTARTFDE3-.LSTARTFRAMES	/* CIE pointer */
 	/* HACK: See above wrt unwind library assumptions.  */
 	.long .LSTART_rt_sigreturn-1-.	/* PC-relative start address */
 	.long .LEND_rt_sigreturn-.LSTART_rt_sigreturn+1
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index d546201..100a30c 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -615,7 +615,7 @@
 		printk(KERN_WARNING "APIC Verbosity level %s not recognised"
 				" use apic=verbose or apic=debug", str);
 
-	return 0;
+	return 1;
 }
 
 __setup("apic=", apic_set_verbosity);
@@ -1137,35 +1137,35 @@
 static __init int setup_disableapic(char *str) 
 { 
 	disable_apic = 1;
-	return 0;
+	return 1;
 } 
 
 static __init int setup_nolapic(char *str) 
 { 
 	disable_apic = 1;
-	return 0;
+	return 1;
 } 
 
 static __init int setup_noapictimer(char *str) 
 { 
 	if (str[0] != ' ' && str[0] != 0)
-		return -1;
+		return 0;
 	disable_apic_timer = 1;
-	return 0;
+	return 1;
 } 
 
 static __init int setup_apicmaintimer(char *str)
 {
 	apic_runs_main_timer = 1;
 	nohpet = 1;
-	return 0;
+	return 1;
 }
 __setup("apicmaintimer", setup_apicmaintimer);
 
 static __init int setup_noapicmaintimer(char *str)
 {
 	apic_runs_main_timer = -1;
-	return 0;
+	return 1;
 }
 __setup("noapicmaintimer", setup_noapicmaintimer);
 
diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c
index 13af920..b93ef5b 100644
--- a/arch/x86_64/kernel/early_printk.c
+++ b/arch/x86_64/kernel/early_printk.c
@@ -221,7 +221,7 @@
 	char buf[256];
 
 	if (early_console_initialized)
-		return -1;
+		return 1;
 
 	strlcpy(buf,opt,sizeof(buf));
 	space = strchr(buf, ' ');
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
index 14f0ced..accbff3 100644
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -37,10 +37,12 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/preempt.h>
+#include <linux/module.h>
 
 #include <asm/cacheflush.h>
 #include <asm/pgtable.h>
 #include <asm/kdebug.h>
+#include <asm/uaccess.h>
 
 void jprobe_return_end(void);
 static void __kprobes arch_copy_kprobe(struct kprobe *p);
@@ -578,16 +580,62 @@
 {
 	struct kprobe *cur = kprobe_running();
 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	const struct exception_table_entry *fixup;
 
-	if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-		return 1;
-
-	if (kcb->kprobe_status & KPROBE_HIT_SS) {
-		resume_execution(cur, regs, kcb);
+	switch(kcb->kprobe_status) {
+	case KPROBE_HIT_SS:
+	case KPROBE_REENTER:
+		/*
+		 * We are here because the instruction being single
+		 * stepped caused a page fault. We reset the current
+		 * kprobe and the rip points back to the probe address
+		 * and allow the page fault handler to continue as a
+		 * normal page fault.
+		 */
+		regs->rip = (unsigned long)cur->addr;
 		regs->eflags |= kcb->kprobe_old_rflags;
-
-		reset_current_kprobe();
+		if (kcb->kprobe_status == KPROBE_REENTER)
+			restore_previous_kprobe(kcb);
+		else
+			reset_current_kprobe();
 		preempt_enable_no_resched();
+		break;
+	case KPROBE_HIT_ACTIVE:
+	case KPROBE_HIT_SSDONE:
+		/*
+		 * We increment the nmissed count for accounting,
+		 * we can also use npre/npostfault count for accouting
+		 * these specific fault cases.
+		 */
+		kprobes_inc_nmissed_count(cur);
+
+		/*
+		 * We come here because instructions in the pre/post
+		 * handler caused the page_fault, this could happen
+		 * if handler tries to access user space by
+		 * copy_from_user(), get_user() etc. Let the
+		 * user-specified handler try to fix it first.
+		 */
+		if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
+			return 1;
+
+		/*
+		 * In case the user-specified fault handler returned
+		 * zero, try to fix up.
+		 */
+		fixup = search_exception_tables(regs->rip);
+		if (fixup) {
+			regs->rip = fixup->fixup;
+			return 1;
+		}
+
+		/*
+		 * fixup() could not handle it,
+		 * Let do_page_fault() fix it.
+		 */
+		break;
+	default:
+		break;
 	}
 	return 0;
 }
@@ -601,6 +649,9 @@
 	struct die_args *args = (struct die_args *)data;
 	int ret = NOTIFY_DONE;
 
+	if (args->regs && user_mode(args->regs))
+		return ret;
+
 	switch (val) {
 	case DIE_INT3:
 		if (kprobe_handler(args->regs))
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index 04282ef..10b3e34 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -501,7 +501,7 @@
 static int __init mcheck_disable(char *str)
 {
 	mce_dont_init = 1;
-	return 0;
+	return 1;
 }
 
 /* mce=off disables machine check. Note you can reenable it later
@@ -521,7 +521,7 @@
 		get_option(&str, &tolerant);
 	else
 		printk("mce= argument %s ignored. Please use /sys", str); 
-	return 0;
+	return 1;
 }
 
 __setup("nomce", mcheck_disable);
diff --git a/arch/x86_64/kernel/pmtimer.c b/arch/x86_64/kernel/pmtimer.c
index ee5ee48..b0444a4 100644
--- a/arch/x86_64/kernel/pmtimer.c
+++ b/arch/x86_64/kernel/pmtimer.c
@@ -121,7 +121,7 @@
 static int __init nopmtimer_setup(char *s)
 {
 	pmtmr_ioport = 0;
-	return 0;
+	return 1;
 }
 
 __setup("nopmtimer", nopmtimer_setup);
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 8111183..70dd8e5 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -35,8 +35,8 @@
 #include <linux/ptrace.h>
 #include <linux/utsname.h>
 #include <linux/random.h>
-#include <linux/kprobes.h>
 #include <linux/notifier.h>
+#include <linux/kprobes.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -66,24 +66,17 @@
 void (*pm_idle)(void);
 static DEFINE_PER_CPU(unsigned int, cpu_idle_state);
 
-static struct notifier_block *idle_notifier;
-static DEFINE_SPINLOCK(idle_notifier_lock);
+static ATOMIC_NOTIFIER_HEAD(idle_notifier);
 
 void idle_notifier_register(struct notifier_block *n)
 {
-	unsigned long flags;
-	spin_lock_irqsave(&idle_notifier_lock, flags);
-	notifier_chain_register(&idle_notifier, n);
-	spin_unlock_irqrestore(&idle_notifier_lock, flags);
+	atomic_notifier_chain_register(&idle_notifier, n);
 }
 EXPORT_SYMBOL_GPL(idle_notifier_register);
 
 void idle_notifier_unregister(struct notifier_block *n)
 {
-	unsigned long flags;
-	spin_lock_irqsave(&idle_notifier_lock, flags);
-	notifier_chain_unregister(&idle_notifier, n);
-	spin_unlock_irqrestore(&idle_notifier_lock, flags);
+	atomic_notifier_chain_unregister(&idle_notifier, n);
 }
 EXPORT_SYMBOL(idle_notifier_unregister);
 
@@ -93,13 +86,13 @@
 void enter_idle(void)
 {
 	__get_cpu_var(idle_state) = CPU_IDLE;
-	notifier_call_chain(&idle_notifier, IDLE_START, NULL);
+	atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL);
 }
 
 static void __exit_idle(void)
 {
 	__get_cpu_var(idle_state) = CPU_NOT_IDLE;
-	notifier_call_chain(&idle_notifier, IDLE_END, NULL);
+	atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL);
 }
 
 /* Called from interrupts to signify idle end */
@@ -353,13 +346,6 @@
 	struct task_struct *me = current;
 	struct thread_struct *t = &me->thread;
 
-	/*
-	 * Remove function-return probe instances associated with this task
-	 * and put them back on the free list. Do not insert an exit probe for
-	 * this function, it will be disabled by kprobe_flush_task if you do.
-	 */
-	kprobe_flush_task(me);
-
 	if (me->thread.io_bitmap_ptr) { 
 		struct tss_struct *tss = &per_cpu(init_tss, get_cpu());
 
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index a57eec8..0856ad4 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -540,7 +540,7 @@
 static int __init noreplacement_setup(char *s)
 { 
      no_replacement = 1; 
-     return 0; 
+     return 1;
 } 
 
 __setup("noreplacement", noreplacement_setup); 
@@ -962,7 +962,6 @@
 
 	cpuid(1, &eax, &ebx, &ecx, &edx);
 
-	c->apicid = phys_pkg_id(0);
 
 	if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
 		return;
@@ -1171,6 +1170,8 @@
 			c->x86_capability[2] = cpuid_edx(0x80860001);
 	}
 
+	c->apicid = phys_pkg_id(0);
+
 	/*
 	 * Vendor-specific initialization.  In this section we
 	 * canonicalize the feature flags, meaning if there are
diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
index eabdb63f..8a691fa 100644
--- a/arch/x86_64/kernel/setup64.c
+++ b/arch/x86_64/kernel/setup64.c
@@ -55,7 +55,7 @@
 		do_not_nx = 1;
 		__supported_pte_mask &= ~_PAGE_NX;
         }
-	return 0;
+	return 1;
 } 
 __setup("noexec=", nonx_setup);	/* parsed early actually */
 
@@ -74,7 +74,7 @@
 		force_personality32 &= ~READ_IMPLIES_EXEC;
 	else if (!strcmp(str, "off"))
 		force_personality32 |= READ_IMPLIES_EXEC;
-	return 0;
+	return 1;
 }
 __setup("noexec32=", nonx32_setup);
 
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index 66e9865..71a7222 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -68,6 +68,9 @@
 /* core ID of each logical CPU */
 u8 cpu_core_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
 
+/* Last level cache ID of each logical CPU */
+u8 cpu_llc_id[NR_CPUS] __cpuinitdata  = {[0 ... NR_CPUS-1] = BAD_APICID};
+
 /* Bitmask of currently online CPUs */
 cpumask_t cpu_online_map __read_mostly;
 
@@ -350,7 +353,7 @@
 static __init int notscsync_setup(char *s)
 {
 	notscsync = 1;
-	return 0;
+	return 1;
 }
 __setup("notscsync", notscsync_setup);
 
@@ -445,6 +448,18 @@
 	cpu_set(cpuid, cpu_callin_map);
 }
 
+/* maps the cpu to the sched domain representing multi-core */
+cpumask_t cpu_coregroup_map(int cpu)
+{
+	struct cpuinfo_x86 *c = cpu_data + cpu;
+	/*
+	 * For perf, we return last level cache shared map.
+	 * TBD: when power saving sched policy is added, we will return
+	 *      cpu_core_map when power saving policy is enabled
+	 */
+	return c->llc_shared_map;
+}
+
 /* representing cpus for which sibling maps can be computed */
 static cpumask_t cpu_sibling_setup_map;
 
@@ -463,12 +478,16 @@
 				cpu_set(cpu, cpu_sibling_map[i]);
 				cpu_set(i, cpu_core_map[cpu]);
 				cpu_set(cpu, cpu_core_map[i]);
+				cpu_set(i, c[cpu].llc_shared_map);
+				cpu_set(cpu, c[i].llc_shared_map);
 			}
 		}
 	} else {
 		cpu_set(cpu, cpu_sibling_map[cpu]);
 	}
 
+	cpu_set(cpu, c[cpu].llc_shared_map);
+
 	if (current_cpu_data.x86_max_cores == 1) {
 		cpu_core_map[cpu] = cpu_sibling_map[cpu];
 		c[cpu].booted_cores = 1;
@@ -476,6 +495,11 @@
 	}
 
 	for_each_cpu_mask(i, cpu_sibling_setup_map) {
+		if (cpu_llc_id[cpu] != BAD_APICID &&
+		    cpu_llc_id[cpu] == cpu_llc_id[i]) {
+			cpu_set(i, c[cpu].llc_shared_map);
+			cpu_set(cpu, c[i].llc_shared_map);
+		}
 		if (phys_proc_id[cpu] == phys_proc_id[i]) {
 			cpu_set(i, cpu_core_map[cpu]);
 			cpu_set(cpu, cpu_core_map[i]);
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 7f58fa6..ef8bc46 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -504,42 +504,25 @@
 
 static unsigned long get_cmos_time(void)
 {
-	unsigned int timeout = 1000000, year, mon, day, hour, min, sec;
-	unsigned char uip = 0, this = 0;
+	unsigned int year, mon, day, hour, min, sec;
 	unsigned long flags;
 	unsigned extyear = 0;
 
-/*
- * The Linux interpretation of the CMOS clock register contents: When the
- * Update-In-Progress (UIP) flag goes from 1 to 0, the RTC registers show the
- * second which has precisely just started. Waiting for this can take up to 1
- * second, we timeout approximately after 2.4 seconds on a machine with
- * standard 8.3 MHz ISA bus.
- */
-
 	spin_lock_irqsave(&rtc_lock, flags);
 
-	while (timeout && (!uip || this)) {
-		uip |= this;
-		this = CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP;
-		timeout--;
-	}
-
-	/*
-	 * Here we are safe to assume the registers won't change for a whole
-	 * second, so we just go ahead and read them.
- 	 */
-	sec = CMOS_READ(RTC_SECONDS);
-	min = CMOS_READ(RTC_MINUTES);
-	hour = CMOS_READ(RTC_HOURS);
-	day = CMOS_READ(RTC_DAY_OF_MONTH);
-	mon = CMOS_READ(RTC_MONTH);
-	year = CMOS_READ(RTC_YEAR);
-
+	do {
+		sec = CMOS_READ(RTC_SECONDS);
+		min = CMOS_READ(RTC_MINUTES);
+		hour = CMOS_READ(RTC_HOURS);
+		day = CMOS_READ(RTC_DAY_OF_MONTH);
+		mon = CMOS_READ(RTC_MONTH);
+		year = CMOS_READ(RTC_YEAR);
 #ifdef CONFIG_ACPI
-	if (acpi_fadt.revision >= FADT2_REVISION_ID && acpi_fadt.century)
-		extyear = CMOS_READ(acpi_fadt.century);
+		if (acpi_fadt.revision >= FADT2_REVISION_ID &&
+					acpi_fadt.century)
+			extyear = CMOS_READ(acpi_fadt.century);
 #endif
+	} while (sec != CMOS_READ(RTC_SECONDS));
 
 	spin_unlock_irqrestore(&rtc_lock, flags);
 
@@ -1323,7 +1306,7 @@
 static int __init nohpet_setup(char *s) 
 { 
 	nohpet = 1;
-	return 0;
+	return 1;
 } 
 
 __setup("nohpet", nohpet_setup);
@@ -1331,7 +1314,7 @@
 int __init notsc_setup(char *s)
 {
 	notsc = 1;
-	return 0;
+	return 1;
 }
 
 __setup("notsc", notsc_setup);
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 7b14830..6bda322 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -69,20 +69,20 @@
 asmlinkage void machine_check(void);
 asmlinkage void spurious_interrupt_bug(void);
 
-struct notifier_block *die_chain;
-static DEFINE_SPINLOCK(die_notifier_lock);
+ATOMIC_NOTIFIER_HEAD(die_chain);
 
 int register_die_notifier(struct notifier_block *nb)
 {
-	int err = 0;
-	unsigned long flags;
-
 	vmalloc_sync_all();
-	spin_lock_irqsave(&die_notifier_lock, flags);
-	err = notifier_chain_register(&die_chain, nb);
-	spin_unlock_irqrestore(&die_notifier_lock, flags);
-	return err;
+	return atomic_notifier_chain_register(&die_chain, nb);
 }
+EXPORT_SYMBOL(register_die_notifier);
+
+int unregister_die_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&die_chain, nb);
+}
+EXPORT_SYMBOL(unregister_die_notifier);
 
 static inline void conditional_sti(struct pt_regs *regs)
 {
@@ -973,14 +973,14 @@
 static int __init oops_dummy(char *s)
 { 
 	panic_on_oops = 1;
-	return -1; 
+	return 1;
 } 
 __setup("oops=", oops_dummy); 
 
 static int __init kstack_setup(char *s)
 {
 	kstack_depth_to_print = simple_strtoul(s,NULL,0);
-	return 0;
+	return 1;
 }
 __setup("kstack=", kstack_setup);
 
diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
index d96a934..d78f460 100644
--- a/arch/x86_64/kernel/x8664_ksyms.c
+++ b/arch/x86_64/kernel/x8664_ksyms.c
@@ -102,8 +102,6 @@
 EXPORT_SYMBOL(screen_info);
 #endif
 
-EXPORT_SYMBOL(get_wchan);
-
 EXPORT_SYMBOL(rtc_lock);
 
 EXPORT_SYMBOL_GPL(set_nmi_callback);
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 316c53d..5525059 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -623,6 +623,6 @@
 static int __init enable_pagefaulttrace(char *str)
 {
 	page_fault_trace = 1;
-	return 0;
+	return 1;
 }
 __setup("pagefaulttrace", enable_pagefaulttrace);
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
index b044156..e5f7f1c 100644
--- a/arch/x86_64/mm/init.c
+++ b/arch/x86_64/mm/init.c
@@ -72,7 +72,7 @@
 	show_free_areas();
 	printk(KERN_INFO "Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
 
-	for_each_pgdat(pgdat) {
+	for_each_online_pgdat(pgdat) {
                for (i = 0; i < pgdat->node_spanned_pages; ++i) {
 			page = pfn_to_page(pgdat->node_start_pfn + i);
 			total++;
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index 63c7264..4be82d6 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -377,21 +377,6 @@
  * Should do that.
  */
 
-/* Requires pfn_valid(pfn) to be true */
-struct page *pfn_to_page(unsigned long pfn)
-{
-	int nid = phys_to_nid(((unsigned long)(pfn)) << PAGE_SHIFT);
-	return (pfn - node_start_pfn(nid)) + NODE_DATA(nid)->node_mem_map;
-}
-EXPORT_SYMBOL(pfn_to_page);
-
-unsigned long page_to_pfn(struct page *page)
-{
-	return (long)(((page) - page_zone(page)->zone_mem_map) +
-		      page_zone(page)->zone_start_pfn);
-}
-EXPORT_SYMBOL(page_to_pfn);
-
 int pfn_valid(unsigned long pfn)
 {
 	unsigned nid;
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index e90ef5d..dbeb350 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -22,6 +22,14 @@
 	bool
 	default y
 
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y
+
 config GENERIC_HARDIRQS
 	bool
 	default y
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c
index efae56a..152b937 100644
--- a/arch/xtensa/kernel/xtensa_ksyms.c
+++ b/arch/xtensa/kernel/xtensa_ksyms.c
@@ -113,8 +113,6 @@
 // FIXME EXPORT_SYMBOL(screen_info);
 #endif
 
-EXPORT_SYMBOL(get_wchan);
-
 EXPORT_SYMBOL(outsb);
 EXPORT_SYMBOL(outsw);
 EXPORT_SYMBOL(outsl);
diff --git a/arch/xtensa/platform-iss/setup.c b/arch/xtensa/platform-iss/setup.c
index 2e6dcbf..23790a5 100644
--- a/arch/xtensa/platform-iss/setup.c
+++ b/arch/xtensa/platform-iss/setup.c
@@ -108,5 +108,5 @@
 
 void __init platform_setup(char **p_cmdline)
 {
-	notifier_chain_register(&panic_notifier_list, &iss_panic_block);
+	atomic_notifier_chain_register(&panic_notifier_list, &iss_panic_block);
 }
diff --git a/block/Kconfig b/block/Kconfig
index 9678364..b6f5f0a 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -13,6 +13,7 @@
 
 config BLK_DEV_IO_TRACE
 	bool "Support for tracing block io actions"
+	depends on SYSFS
 	select RELAY
 	select DEBUG_FS
 	help
@@ -23,4 +24,13 @@
 
 	  git://brick.kernel.dk/data/git/blktrace.git
 
+config LSF
+	bool "Support for Large Single Files"
+	depends on X86 || (MIPS && 32BIT) || PPC32 || ARCH_S390_31 || SUPERH || UML
+	help
+	  Say Y here if you want to be able to handle very large files (bigger
+	  than 2TB), otherwise say N.
+
+	  If unsure, say Y.
+
 source block/Kconfig.iosched
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index c4a0d5d..67d446d 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -26,18 +26,12 @@
 static const int cfq_slice_sync = HZ / 10;
 static int cfq_slice_async = HZ / 25;
 static const int cfq_slice_async_rq = 2;
-static int cfq_slice_idle = HZ / 100;
+static int cfq_slice_idle = HZ / 70;
 
 #define CFQ_IDLE_GRACE		(HZ / 10)
 #define CFQ_SLICE_SCALE		(5)
 
 #define CFQ_KEY_ASYNC		(0)
-#define CFQ_KEY_ANY		(0xffff)
-
-/*
- * disable queueing at the driver/hardware level
- */
-static const int cfq_max_depth = 2;
 
 static DEFINE_RWLOCK(cfq_exit_lock);
 
@@ -102,6 +96,8 @@
 #define cfq_cfqq_sync(cfqq)		\
 	(cfq_cfqq_class_sync(cfqq) || (cfqq)->on_dispatch[SYNC])
 
+#define sample_valid(samples)	((samples) > 80)
+
 /*
  * Per block device queue structure
  */
@@ -170,7 +166,6 @@
 	unsigned int cfq_slice[2];
 	unsigned int cfq_slice_async_rq;
 	unsigned int cfq_slice_idle;
-	unsigned int cfq_max_depth;
 
 	struct list_head cic_list;
 };
@@ -343,17 +338,27 @@
 	return !cfqd->busy_queues;
 }
 
+static inline pid_t cfq_queue_pid(struct task_struct *task, int rw)
+{
+	if (rw == READ || process_sync(task))
+		return task->pid;
+
+	return CFQ_KEY_ASYNC;
+}
+
 /*
  * Lifted from AS - choose which of crq1 and crq2 that is best served now.
  * We choose the request that is closest to the head right now. Distance
- * behind the head are penalized and only allowed to a certain extent.
+ * behind the head is penalized and only allowed to a certain extent.
  */
 static struct cfq_rq *
 cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2)
 {
 	sector_t last, s1, s2, d1 = 0, d2 = 0;
-	int r1_wrap = 0, r2_wrap = 0;	/* requests are behind the disk head */
 	unsigned long back_max;
+#define CFQ_RQ1_WRAP	0x01 /* request 1 wraps */
+#define CFQ_RQ2_WRAP	0x02 /* request 2 wraps */
+	unsigned wrap = 0; /* bit mask: requests behind the disk head? */
 
 	if (crq1 == NULL || crq1 == crq2)
 		return crq2;
@@ -385,35 +390,47 @@
 	else if (s1 + back_max >= last)
 		d1 = (last - s1) * cfqd->cfq_back_penalty;
 	else
-		r1_wrap = 1;
+		wrap |= CFQ_RQ1_WRAP;
 
 	if (s2 >= last)
 		d2 = s2 - last;
 	else if (s2 + back_max >= last)
 		d2 = (last - s2) * cfqd->cfq_back_penalty;
 	else
-		r2_wrap = 1;
+		wrap |= CFQ_RQ2_WRAP;
 
 	/* Found required data */
-	if (!r1_wrap && r2_wrap)
-		return crq1;
-	else if (!r2_wrap && r1_wrap)
-		return crq2;
-	else if (r1_wrap && r2_wrap) {
-		/* both behind the head */
-		if (s1 <= s2)
-			return crq1;
-		else
-			return crq2;
-	}
 
-	/* Both requests in front of the head */
-	if (d1 < d2)
+	/*
+	 * By doing switch() on the bit mask "wrap" we avoid having to
+	 * check two variables for all permutations: --> faster!
+	 */
+	switch (wrap) {
+	case 0: /* common case for CFQ: crq1 and crq2 not wrapped */
+		if (d1 < d2)
+			return crq1;
+		else if (d2 < d1)
+			return crq2;
+		else {
+			if (s1 >= s2)
+				return crq1;
+			else
+				return crq2;
+		}
+
+	case CFQ_RQ2_WRAP:
 		return crq1;
-	else if (d2 < d1)
+	case CFQ_RQ1_WRAP:
 		return crq2;
-	else {
-		if (s1 >= s2)
+	case (CFQ_RQ1_WRAP|CFQ_RQ2_WRAP): /* both crqs wrapped */
+	default:
+		/*
+		 * Since both rqs are wrapped,
+		 * start with the one that's further behind head
+		 * (--> only *one* back seek required),
+		 * since back seek takes more time than forward.
+		 */
+		if (s1 <= s2)
 			return crq1;
 		else
 			return crq2;
@@ -612,15 +629,20 @@
 	cfq_add_crq_rb(crq);
 }
 
-static struct request *cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector)
-
+static struct request *
+cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
 {
-	struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, current->pid, CFQ_KEY_ANY);
+	struct task_struct *tsk = current;
+	pid_t key = cfq_queue_pid(tsk, bio_data_dir(bio));
+	struct cfq_queue *cfqq;
 	struct rb_node *n;
+	sector_t sector;
 
+	cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
 	if (!cfqq)
 		goto out;
 
+	sector = bio->bi_sector + bio_sectors(bio);
 	n = cfqq->sort_list.rb_node;
 	while (n) {
 		struct cfq_rq *crq = rb_entry_crq(n);
@@ -674,7 +696,7 @@
 		goto out;
 	}
 
-	__rq = cfq_find_rq_rb(cfqd, bio->bi_sector + bio_sectors(bio));
+	__rq = cfq_find_rq_fmerge(cfqd, bio);
 	if (__rq && elv_rq_merge_ok(__rq, bio)) {
 		ret = ELEVATOR_FRONT_MERGE;
 		goto out;
@@ -877,6 +899,7 @@
 static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 
 {
+	struct cfq_io_context *cic;
 	unsigned long sl;
 
 	WARN_ON(!RB_EMPTY(&cfqq->sort_list));
@@ -892,13 +915,23 @@
 	/*
 	 * task has exited, don't wait
 	 */
-	if (cfqd->active_cic && !cfqd->active_cic->ioc->task)
+	cic = cfqd->active_cic;
+	if (!cic || !cic->ioc->task)
 		return 0;
 
 	cfq_mark_cfqq_must_dispatch(cfqq);
 	cfq_mark_cfqq_wait_request(cfqq);
 
 	sl = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle);
+
+	/*
+	 * we don't want to idle for seeks, but we do want to allow
+	 * fair distribution of slice time for a process doing back-to-back
+	 * seeks. so allow a little bit of time for him to submit a new rq
+	 */
+	if (sample_valid(cic->seek_samples) && cic->seek_mean > 131072)
+		sl = 2;
+
 	mod_timer(&cfqd->idle_slice_timer, jiffies + sl);
 	return 1;
 }
@@ -1115,13 +1148,6 @@
 	if (cfqq) {
 		int max_dispatch;
 
-		/*
-		 * if idle window is disabled, allow queue buildup
-		 */
-		if (!cfq_cfqq_idle_window(cfqq) &&
-		    cfqd->rq_in_driver >= cfqd->cfq_max_depth)
-			return 0;
-
 		cfq_clear_cfqq_must_dispatch(cfqq);
 		cfq_clear_cfqq_wait_request(cfqq);
 		del_timer(&cfqd->idle_slice_timer);
@@ -1171,13 +1197,13 @@
 		    const int hashval)
 {
 	struct hlist_head *hash_list = &cfqd->cfq_hash[hashval];
-	struct hlist_node *entry, *next;
+	struct hlist_node *entry;
+	struct cfq_queue *__cfqq;
 
-	hlist_for_each_safe(entry, next, hash_list) {
-		struct cfq_queue *__cfqq = list_entry_qhash(entry);
+	hlist_for_each_entry(__cfqq, entry, hash_list, cfq_hash) {
 		const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->org_ioprio_class, __cfqq->org_ioprio);
 
-		if (__cfqq->key == key && (__p == prio || prio == CFQ_KEY_ANY))
+		if (__cfqq->key == key && (__p == prio || !prio))
 			return __cfqq;
 	}
 
@@ -1190,19 +1216,19 @@
 	return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));
 }
 
-static void cfq_free_io_context(struct cfq_io_context *cic)
+static void cfq_free_io_context(struct io_context *ioc)
 {
 	struct cfq_io_context *__cic;
-	struct list_head *entry, *next;
-	int freed = 1;
+	struct rb_node *n;
+	int freed = 0;
 
-	list_for_each_safe(entry, next, &cic->list) {
-		__cic = list_entry(entry, struct cfq_io_context, list);
+	while ((n = rb_first(&ioc->cic_root)) != NULL) {
+		__cic = rb_entry(n, struct cfq_io_context, rb_node);
+		rb_erase(&__cic->rb_node, &ioc->cic_root);
 		kmem_cache_free(cfq_ioc_pool, __cic);
 		freed++;
 	}
 
-	kmem_cache_free(cfq_ioc_pool, cic);
 	if (atomic_sub_and_test(freed, &ioc_count) && ioc_gone)
 		complete(ioc_gone);
 }
@@ -1210,8 +1236,7 @@
 static void cfq_trim(struct io_context *ioc)
 {
 	ioc->set_ioprio = NULL;
-	if (ioc->cic)
-		cfq_free_io_context(ioc->cic);
+	cfq_free_io_context(ioc);
 }
 
 /*
@@ -1250,26 +1275,26 @@
 	spin_unlock(q->queue_lock);
 }
 
-static void cfq_exit_io_context(struct cfq_io_context *cic)
+static void cfq_exit_io_context(struct io_context *ioc)
 {
 	struct cfq_io_context *__cic;
-	struct list_head *entry;
 	unsigned long flags;
-
-	local_irq_save(flags);
+	struct rb_node *n;
 
 	/*
 	 * put the reference this task is holding to the various queues
 	 */
-	read_lock(&cfq_exit_lock);
-	list_for_each(entry, &cic->list) {
-		__cic = list_entry(entry, struct cfq_io_context, list);
+	read_lock_irqsave(&cfq_exit_lock, flags);
+
+	n = rb_first(&ioc->cic_root);
+	while (n != NULL) {
+		__cic = rb_entry(n, struct cfq_io_context, rb_node);
+
 		cfq_exit_single_io_context(__cic);
+		n = rb_next(n);
 	}
 
-	cfq_exit_single_io_context(cic);
-	read_unlock(&cfq_exit_lock);
-	local_irq_restore(flags);
+	read_unlock_irqrestore(&cfq_exit_lock, flags);
 }
 
 static struct cfq_io_context *
@@ -1278,10 +1303,10 @@
 	struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask);
 
 	if (cic) {
-		INIT_LIST_HEAD(&cic->list);
+		RB_CLEAR(&cic->rb_node);
+		cic->key = NULL;
 		cic->cfqq[ASYNC] = NULL;
 		cic->cfqq[SYNC] = NULL;
-		cic->key = NULL;
 		cic->last_end_request = jiffies;
 		cic->ttime_total = 0;
 		cic->ttime_samples = 0;
@@ -1373,15 +1398,17 @@
 static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio)
 {
 	struct cfq_io_context *cic;
+	struct rb_node *n;
 
 	write_lock(&cfq_exit_lock);
 
-	cic = ioc->cic;
-
-	changed_ioprio(cic);
-
-	list_for_each_entry(cic, &cic->list, list)
+	n = rb_first(&ioc->cic_root);
+	while (n != NULL) {
+		cic = rb_entry(n, struct cfq_io_context, rb_node);
+ 
 		changed_ioprio(cic);
+		n = rb_next(n);
+	}
 
 	write_unlock(&cfq_exit_lock);
 
@@ -1445,14 +1472,67 @@
 	return cfqq;
 }
 
+static struct cfq_io_context *
+cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc)
+{
+	struct rb_node *n = ioc->cic_root.rb_node;
+	struct cfq_io_context *cic;
+	void *key = cfqd;
+
+	while (n) {
+		cic = rb_entry(n, struct cfq_io_context, rb_node);
+
+		if (key < cic->key)
+			n = n->rb_left;
+		else if (key > cic->key)
+			n = n->rb_right;
+		else
+			return cic;
+	}
+
+	return NULL;
+}
+
+static inline void
+cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc,
+	     struct cfq_io_context *cic)
+{
+	struct rb_node **p = &ioc->cic_root.rb_node;
+	struct rb_node *parent = NULL;
+	struct cfq_io_context *__cic;
+
+	read_lock(&cfq_exit_lock);
+
+	cic->ioc = ioc;
+	cic->key = cfqd;
+
+	ioc->set_ioprio = cfq_ioc_set_ioprio;
+
+	while (*p) {
+		parent = *p;
+		__cic = rb_entry(parent, struct cfq_io_context, rb_node);
+
+		if (cic->key < __cic->key)
+			p = &(*p)->rb_left;
+		else if (cic->key > __cic->key)
+			p = &(*p)->rb_right;
+		else
+			BUG();
+	}
+
+	rb_link_node(&cic->rb_node, parent, p);
+	rb_insert_color(&cic->rb_node, &ioc->cic_root);
+	list_add(&cic->queue_list, &cfqd->cic_list);
+	read_unlock(&cfq_exit_lock);
+}
+
 /*
  * Setup general io context and cfq io context. There can be several cfq
  * io contexts per general io context, if this process is doing io to more
- * than one device managed by cfq. Note that caller is holding a reference to
- * cfqq, so we don't need to worry about it disappearing
+ * than one device managed by cfq.
  */
 static struct cfq_io_context *
-cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask)
+cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
 {
 	struct io_context *ioc = NULL;
 	struct cfq_io_context *cic;
@@ -1463,88 +1543,15 @@
 	if (!ioc)
 		return NULL;
 
-restart:
-	if ((cic = ioc->cic) == NULL) {
-		cic = cfq_alloc_io_context(cfqd, gfp_mask);
+	cic = cfq_cic_rb_lookup(cfqd, ioc);
+	if (cic)
+		goto out;
 
-		if (cic == NULL)
-			goto err;
+	cic = cfq_alloc_io_context(cfqd, gfp_mask);
+	if (cic == NULL)
+		goto err;
 
-		/*
-		 * manually increment generic io_context usage count, it
-		 * cannot go away since we are already holding one ref to it
-		 */
-		cic->ioc = ioc;
-		cic->key = cfqd;
-		read_lock(&cfq_exit_lock);
-		ioc->set_ioprio = cfq_ioc_set_ioprio;
-		ioc->cic = cic;
-		list_add(&cic->queue_list, &cfqd->cic_list);
-		read_unlock(&cfq_exit_lock);
-	} else {
-		struct cfq_io_context *__cic;
-
-		/*
-		 * the first cic on the list is actually the head itself
-		 */
-		if (cic->key == cfqd)
-			goto out;
-
-		if (unlikely(!cic->key)) {
-			read_lock(&cfq_exit_lock);
-			if (list_empty(&cic->list))
-				ioc->cic = NULL;
-			else
-				ioc->cic = list_entry(cic->list.next,
-						      struct cfq_io_context,
-						      list);
-			read_unlock(&cfq_exit_lock);
-			kmem_cache_free(cfq_ioc_pool, cic);
-			atomic_dec(&ioc_count);
-			goto restart;
-		}
-
-		/*
-		 * cic exists, check if we already are there. linear search
-		 * should be ok here, the list will usually not be more than
-		 * 1 or a few entries long
-		 */
-		list_for_each_entry(__cic, &cic->list, list) {
-			/*
-			 * this process is already holding a reference to
-			 * this queue, so no need to get one more
-			 */
-			if (__cic->key == cfqd) {
-				cic = __cic;
-				goto out;
-			}
-			if (unlikely(!__cic->key)) {
-				read_lock(&cfq_exit_lock);
-				list_del(&__cic->list);
-				read_unlock(&cfq_exit_lock);
-				kmem_cache_free(cfq_ioc_pool, __cic);
-				atomic_dec(&ioc_count);
-				goto restart;
-			}
-		}
-
-		/*
-		 * nope, process doesn't have a cic assoicated with this
-		 * cfqq yet. get a new one and add to list
-		 */
-		__cic = cfq_alloc_io_context(cfqd, gfp_mask);
-		if (__cic == NULL)
-			goto err;
-
-		__cic->ioc = ioc;
-		__cic->key = cfqd;
-		read_lock(&cfq_exit_lock);
-		list_add(&__cic->list, &cic->list);
-		list_add(&__cic->queue_list, &cfqd->cic_list);
-		read_unlock(&cfq_exit_lock);
-		cic = __cic;
-	}
-
+	cfq_cic_link(cfqd, ioc, cic);
 out:
 	return cic;
 err:
@@ -1577,7 +1584,33 @@
 	cic->ttime_mean = (cic->ttime_total + 128) / cic->ttime_samples;
 }
 
-#define sample_valid(samples)	((samples) > 80)
+static void
+cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
+		       struct cfq_rq *crq)
+{
+	sector_t sdist;
+	u64 total;
+
+	if (cic->last_request_pos < crq->request->sector)
+		sdist = crq->request->sector - cic->last_request_pos;
+	else
+		sdist = cic->last_request_pos - crq->request->sector;
+
+	/*
+	 * Don't allow the seek distance to get too large from the
+	 * odd fragment, pagein, etc
+	 */
+	if (cic->seek_samples <= 60) /* second&third seek */
+		sdist = min(sdist, (cic->seek_mean * 4) + 2*1024*1024);
+	else
+		sdist = min(sdist, (cic->seek_mean * 4)	+ 2*1024*64);
+
+	cic->seek_samples = (7*cic->seek_samples + 256) / 8;
+	cic->seek_total = (7*cic->seek_total + (u64)256*sdist) / 8;
+	total = cic->seek_total + (cic->seek_samples/2);
+	do_div(total, cic->seek_samples);
+	cic->seek_mean = (sector_t)total;
+}
 
 /*
  * Disable idle window if the process thinks too long or seeks so much that
@@ -1690,9 +1723,11 @@
 	cic = crq->io_context;
 
 	cfq_update_io_thinktime(cfqd, cic);
+	cfq_update_io_seektime(cfqd, cic, crq);
 	cfq_update_idle_window(cfqd, cfqq, cic);
 
 	cic->last_queue = jiffies;
+	cic->last_request_pos = crq->request->sector + crq->request->nr_sectors;
 
 	if (cfqq == cfqd->active_queue) {
 		/*
@@ -1825,14 +1860,6 @@
 		cfq_resort_rr_list(cfqq, 0);
 }
 
-static inline pid_t cfq_queue_pid(struct task_struct *task, int rw)
-{
-	if (rw == READ || process_sync(task))
-		return task->pid;
-
-	return CFQ_KEY_ASYNC;
-}
-
 static inline int
 __cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
 		struct task_struct *task, int rw)
@@ -1965,7 +1992,7 @@
 
 	might_sleep_if(gfp_mask & __GFP_WAIT);
 
-	cic = cfq_get_io_context(cfqd, key, gfp_mask);
+	cic = cfq_get_io_context(cfqd, gfp_mask);
 
 	spin_lock_irqsave(q->queue_lock, flags);
 
@@ -2133,11 +2160,14 @@
 	request_queue_t *q = cfqd->queue;
 
 	cfq_shutdown_timer_wq(cfqd);
+
 	write_lock(&cfq_exit_lock);
 	spin_lock_irq(q->queue_lock);
+
 	if (cfqd->active_queue)
 		__cfq_slice_expired(cfqd, cfqd->active_queue, 0);
-	while(!list_empty(&cfqd->cic_list)) {
+
+	while (!list_empty(&cfqd->cic_list)) {
 		struct cfq_io_context *cic = list_entry(cfqd->cic_list.next,
 							struct cfq_io_context,
 							queue_list);
@@ -2152,6 +2182,7 @@
 		cic->key = NULL;
 		list_del_init(&cic->queue_list);
 	}
+
 	spin_unlock_irq(q->queue_lock);
 	write_unlock(&cfq_exit_lock);
 
@@ -2191,7 +2222,7 @@
 	if (!cfqd->cfq_hash)
 		goto out_cfqhash;
 
-	cfqd->crq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, crq_pool);
+	cfqd->crq_pool = mempool_create_slab_pool(BLKDEV_MIN_RQ, crq_pool);
 	if (!cfqd->crq_pool)
 		goto out_crqpool;
 
@@ -2227,7 +2258,6 @@
 	cfqd->cfq_slice[1] = cfq_slice_sync;
 	cfqd->cfq_slice_async_rq = cfq_slice_async_rq;
 	cfqd->cfq_slice_idle = cfq_slice_idle;
-	cfqd->cfq_max_depth = cfq_max_depth;
 
 	return 0;
 out_crqpool:
@@ -2310,7 +2340,6 @@
 SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1);
 SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1);
 SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0);
-SHOW_FUNCTION(cfq_max_depth_show, cfqd->cfq_max_depth, 0);
 #undef SHOW_FUNCTION
 
 #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV)			\
@@ -2339,7 +2368,6 @@
 STORE_FUNCTION(cfq_slice_sync_store, &cfqd->cfq_slice[1], 1, UINT_MAX, 1);
 STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1);
 STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1, UINT_MAX, 0);
-STORE_FUNCTION(cfq_max_depth_store, &cfqd->cfq_max_depth, 1, UINT_MAX, 0);
 #undef STORE_FUNCTION
 
 #define CFQ_ATTR(name) \
@@ -2356,7 +2384,6 @@
 	CFQ_ATTR(slice_async),
 	CFQ_ATTR(slice_async_rq),
 	CFQ_ATTR(slice_idle),
-	CFQ_ATTR(max_depth),
 	__ATTR_NULL
 };
 
diff --git a/block/elevator.c b/block/elevator.c
index 56c2ed0..0d6be03 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -145,7 +145,7 @@
 		strcpy(chosen_elevator, "anticipatory");
 	else
 		strncpy(chosen_elevator, str, sizeof(chosen_elevator) - 1);
-	return 0;
+	return 1;
 }
 
 __setup("elevator=", elevator_setup);
diff --git a/block/genhd.c b/block/genhd.c
index 64510fd..5a8d3bf 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -17,8 +17,6 @@
 #include <linux/buffer_head.h>
 #include <linux/mutex.h>
 
-#define MAX_PROBE_HASH 255	/* random */
-
 static struct subsystem block_subsys;
 
 static DEFINE_MUTEX(block_subsys_lock);
@@ -31,108 +29,29 @@
 	struct blk_major_name *next;
 	int major;
 	char name[16];
-} *major_names[MAX_PROBE_HASH];
+} *major_names[BLKDEV_MAJOR_HASH_SIZE];
 
 /* index in the above - for now: assume no multimajor ranges */
 static inline int major_to_index(int major)
 {
-	return major % MAX_PROBE_HASH;
+	return major % BLKDEV_MAJOR_HASH_SIZE;
 }
 
-struct blkdev_info {
-        int index;
-        struct blk_major_name *bd;
-};
+#ifdef CONFIG_PROC_FS
 
-/*
- * iterate over a list of blkdev_info structures.  allows
- * the major_names array to be iterated over from outside this file
- * must be called with the block_subsys_lock held
- */
-void *get_next_blkdev(void *dev)
+void blkdev_show(struct seq_file *f, off_t offset)
 {
-        struct blkdev_info *info;
+	struct blk_major_name *dp;
 
-        if (dev == NULL) {
-                info = kmalloc(sizeof(*info), GFP_KERNEL);
-                if (!info)
-                        goto out;
-                info->index=0;
-                info->bd = major_names[info->index];
-                if (info->bd)
-                        goto out;
-        } else {
-                info = dev;
-        }
-
-        while (info->index < ARRAY_SIZE(major_names)) {
-                if (info->bd)
-                        info->bd = info->bd->next;
-                if (info->bd)
-                        goto out;
-                /*
-                 * No devices on this chain, move to the next
-                 */
-                info->index++;
-                info->bd = (info->index < ARRAY_SIZE(major_names)) ?
-			major_names[info->index] : NULL;
-                if (info->bd)
-                        goto out;
-        }
-
-out:
-        return info;
-}
-
-void *acquire_blkdev_list(void)
-{
-        mutex_lock(&block_subsys_lock);
-        return get_next_blkdev(NULL);
-}
-
-void release_blkdev_list(void *dev)
-{
-        mutex_unlock(&block_subsys_lock);
-        kfree(dev);
-}
-
-
-/*
- * Count the number of records in the blkdev_list.
- * must be called with the block_subsys_lock held
- */
-int count_blkdev_list(void)
-{
-	struct blk_major_name *n;
-	int i, count;
-
-	count = 0;
-
-	for (i = 0; i < ARRAY_SIZE(major_names); i++) {
-		for (n = major_names[i]; n; n = n->next)
-				count++;
+	if (offset < BLKDEV_MAJOR_HASH_SIZE) {
+		mutex_lock(&block_subsys_lock);
+		for (dp = major_names[offset]; dp; dp = dp->next)
+			seq_printf(f, "%3d %s\n", dp->major, dp->name);
+		mutex_unlock(&block_subsys_lock);
 	}
-
-	return count;
 }
 
-/*
- * extract the major and name values from a blkdev_info struct
- * passed in as a void to *dev.  Must be called with
- * block_subsys_lock held
- */
-int get_blkdev_info(void *dev, int *major, char **name)
-{
-        struct blkdev_info *info = dev;
-
-        if (info->bd == NULL)
-                return 1;
-
-        *major = info->bd->major;
-        *name = info->bd->name;
-        return 0;
-}
-
+#endif /* CONFIG_PROC_FS */
 
 int register_blkdev(unsigned int major, const char *name)
 {
@@ -454,8 +373,8 @@
 	disk_round_stats(disk);
 	preempt_enable();
 	return sprintf(page,
-		"%8u %8u %8llu %8u "
-		"%8u %8u %8llu %8u "
+		"%8lu %8lu %8llu %8u "
+		"%8lu %8lu %8llu %8u "
 		"%8u %8u %8u"
 		"\n",
 		disk_stat_read(disk, ios[READ]),
@@ -649,7 +568,7 @@
 	preempt_disable();
 	disk_round_stats(gp);
 	preempt_enable();
-	seq_printf(s, "%4d %4d %s %u %u %llu %u %u %u %llu %u %u %u %u\n",
+	seq_printf(s, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n",
 		gp->major, n + gp->first_minor, disk_name(gp, n, buf),
 		disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]),
 		(unsigned long long)disk_stat_read(gp, sectors[0]),
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 062067f..5b26af8 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -785,6 +785,8 @@
 	t->max_hw_segments = min(t->max_hw_segments,b->max_hw_segments);
 	t->max_segment_size = min(t->max_segment_size,b->max_segment_size);
 	t->hardsect_size = max(t->hardsect_size,b->hardsect_size);
+	if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags))
+		clear_bit(QUEUE_FLAG_CLUSTER, &t->queue_flags);
 }
 
 EXPORT_SYMBOL(blk_queue_stack_limits);
@@ -906,17 +908,15 @@
 				__FUNCTION__, depth);
 	}
 
-	tag_index = kmalloc(depth * sizeof(struct request *), GFP_ATOMIC);
+	tag_index = kzalloc(depth * sizeof(struct request *), GFP_ATOMIC);
 	if (!tag_index)
 		goto fail;
 
 	nr_ulongs = ALIGN(depth, BITS_PER_LONG) / BITS_PER_LONG;
-	tag_map = kmalloc(nr_ulongs * sizeof(unsigned long), GFP_ATOMIC);
+	tag_map = kzalloc(nr_ulongs * sizeof(unsigned long), GFP_ATOMIC);
 	if (!tag_map)
 		goto fail;
 
-	memset(tag_index, 0, depth * sizeof(struct request *));
-	memset(tag_map, 0, nr_ulongs * sizeof(unsigned long));
 	tags->real_max_depth = depth;
 	tags->max_depth = depth;
 	tags->tag_index = tag_index;
@@ -2479,10 +2479,12 @@
 	rq->rq_disk = bd_disk;
 	rq->flags |= REQ_NOMERGE;
 	rq->end_io = done;
-	elv_add_request(q, rq, where, 1);
-	generic_unplug_device(q);
+	WARN_ON(irqs_disabled());
+	spin_lock_irq(q->queue_lock);
+	__elv_add_request(q, rq, where, 1);
+	__generic_unplug_device(q);
+	spin_unlock_irq(q->queue_lock);
 }
-
 EXPORT_SYMBOL_GPL(blk_execute_rq_nowait);
 
 /**
@@ -3512,7 +3514,7 @@
 	iocontext_cachep = kmem_cache_create("blkdev_ioc",
 			sizeof(struct io_context), 0, SLAB_PANIC, NULL, NULL);
 
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 		INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));
 
 	open_softirq(BLOCK_SOFTIRQ, blk_done_softirq, NULL);
@@ -3537,11 +3539,17 @@
 	BUG_ON(atomic_read(&ioc->refcount) == 0);
 
 	if (atomic_dec_and_test(&ioc->refcount)) {
+		struct cfq_io_context *cic;
+
 		rcu_read_lock();
 		if (ioc->aic && ioc->aic->dtor)
 			ioc->aic->dtor(ioc->aic);
-		if (ioc->cic && ioc->cic->dtor)
-			ioc->cic->dtor(ioc->cic);
+		if (ioc->cic_root.rb_node != NULL) {
+			struct rb_node *n = rb_first(&ioc->cic_root);
+
+			cic = rb_entry(n, struct cfq_io_context, rb_node);
+			cic->dtor(ioc);
+		}
 		rcu_read_unlock();
 
 		kmem_cache_free(iocontext_cachep, ioc);
@@ -3554,6 +3562,7 @@
 {
 	unsigned long flags;
 	struct io_context *ioc;
+	struct cfq_io_context *cic;
 
 	local_irq_save(flags);
 	task_lock(current);
@@ -3565,9 +3574,11 @@
 
 	if (ioc->aic && ioc->aic->exit)
 		ioc->aic->exit(ioc->aic);
-	if (ioc->cic && ioc->cic->exit)
-		ioc->cic->exit(ioc->cic);
-
+	if (ioc->cic_root.rb_node != NULL) {
+		cic = rb_entry(rb_first(&ioc->cic_root), struct cfq_io_context, rb_node);
+		cic->exit(ioc);
+	}
+ 
 	put_io_context(ioc);
 }
 
@@ -3596,7 +3607,7 @@
 		ret->last_waited = jiffies; /* doesn't matter... */
 		ret->nr_batch_requests = 0; /* because this is 0 */
 		ret->aic = NULL;
-		ret->cic = NULL;
+		ret->cic_root.rb_node = NULL;
 		tsk->io_context = ret;
 	}
 
diff --git a/drivers/Kconfig b/drivers/Kconfig
index bddf431..5c91d6a 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -64,10 +64,14 @@
 
 source "drivers/mmc/Kconfig"
 
+source "drivers/leds/Kconfig"
+
 source "drivers/infiniband/Kconfig"
 
 source "drivers/sn/Kconfig"
 
 source "drivers/edac/Kconfig"
 
+source "drivers/rtc/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 5c69b86..d6e8ffb 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -56,6 +56,7 @@
 obj-$(CONFIG_GAMEPORT)		+= input/gameport/
 obj-$(CONFIG_INPUT)		+= input/
 obj-$(CONFIG_I2O)		+= message/
+obj-$(CONFIG_RTC_LIB)		+= rtc/
 obj-$(CONFIG_I2C)		+= i2c/
 obj-$(CONFIG_W1)		+= w1/
 obj-$(CONFIG_HWMON)		+= hwmon/
@@ -68,6 +69,7 @@
 obj-$(CONFIG_EISA)		+= eisa/
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_MMC)		+= mmc/
+obj-$(CONFIG_NEW_LEDS)		+= leds/
 obj-$(CONFIG_INFINIBAND)	+= infiniband/
 obj-$(CONFIG_SGI_SN)		+= sn/
 obj-y				+= firmware/
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 79b09d7..eee0864 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1572,7 +1572,7 @@
 static int __init acpi_fake_ecdt_setup(char *str)
 {
 	acpi_fake_ecdt_enabled = 1;
-	return 0;
+	return 1;
 }
 
 __setup("acpi_fake_ecdt", acpi_fake_ecdt_setup);
@@ -1591,7 +1591,7 @@
 		acpi_ec_driver.ops.add = acpi_ec_poll_add;
 	}
 	printk(KERN_INFO PREFIX "EC %s mode.\n", intr ? "interrupt" : "polling");
-	return 0;
+	return 1;
 }
 
 __setup("ec_intr=", acpi_ec_set_intr_mode);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index ac5bbae..13b5fd5 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -156,12 +156,10 @@
 {
 	if (efi_enabled) {
 		addr->pointer_type = ACPI_PHYSICAL_POINTER;
-		if (efi.acpi20)
-			addr->pointer.physical =
-			    (acpi_physical_address) virt_to_phys(efi.acpi20);
-		else if (efi.acpi)
-			addr->pointer.physical =
-			    (acpi_physical_address) virt_to_phys(efi.acpi);
+		if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
+			addr->pointer.physical = efi.acpi20;
+		else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
+			addr->pointer.physical = efi.acpi;
 		else {
 			printk(KERN_ERR PREFIX
 			       "System description tables not found\n");
@@ -182,22 +180,14 @@
 acpi_os_map_memory(acpi_physical_address phys, acpi_size size,
 		   void __iomem ** virt)
 {
-	if (efi_enabled) {
-		if (EFI_MEMORY_WB & efi_mem_attributes(phys)) {
-			*virt = (void __iomem *)phys_to_virt(phys);
-		} else {
-			*virt = ioremap(phys, size);
-		}
-	} else {
-		if (phys > ULONG_MAX) {
-			printk(KERN_ERR PREFIX "Cannot map memory that high\n");
-			return AE_BAD_PARAMETER;
-		}
-		/*
-		 * ioremap checks to ensure this is in reserved space
-		 */
-		*virt = ioremap((unsigned long)phys, size);
+	if (phys > ULONG_MAX) {
+		printk(KERN_ERR PREFIX "Cannot map memory that high\n");
+		return AE_BAD_PARAMETER;
 	}
+	/*
+	 * ioremap checks to ensure this is in reserved space
+	 */
+	*virt = ioremap((unsigned long)phys, size);
 
 	if (!*virt)
 		return AE_NO_MEMORY;
@@ -409,18 +399,8 @@
 {
 	u32 dummy;
 	void __iomem *virt_addr;
-	int iomem = 0;
 
-	if (efi_enabled) {
-		if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
-			/* HACK ALERT! We can use readb/w/l on real memory too.. */
-			virt_addr = (void __iomem *)phys_to_virt(phys_addr);
-		} else {
-			iomem = 1;
-			virt_addr = ioremap(phys_addr, width);
-		}
-	} else
-		virt_addr = (void __iomem *)phys_to_virt(phys_addr);
+	virt_addr = ioremap(phys_addr, width);
 	if (!value)
 		value = &dummy;
 
@@ -438,10 +418,7 @@
 		BUG();
 	}
 
-	if (efi_enabled) {
-		if (iomem)
-			iounmap(virt_addr);
-	}
+	iounmap(virt_addr);
 
 	return AE_OK;
 }
@@ -450,18 +427,8 @@
 acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
 {
 	void __iomem *virt_addr;
-	int iomem = 0;
 
-	if (efi_enabled) {
-		if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
-			/* HACK ALERT! We can use writeb/w/l on real memory too */
-			virt_addr = (void __iomem *)phys_to_virt(phys_addr);
-		} else {
-			iomem = 1;
-			virt_addr = ioremap(phys_addr, width);
-		}
-	} else
-		virt_addr = (void __iomem *)phys_to_virt(phys_addr);
+	virt_addr = ioremap(phys_addr, width);
 
 	switch (width) {
 	case 8:
@@ -477,8 +444,7 @@
 		BUG();
 	}
 
-	if (iomem)
-		iounmap(virt_addr);
+	iounmap(virt_addr);
 
 	return AE_OK;
 }
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 99a3a28..713b763 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -246,7 +246,7 @@
 }
 
 /* --------------------------------------------------------------------------
-                              Common ACPI processor fucntions
+                              Common ACPI processor functions
    -------------------------------------------------------------------------- */
 
 /*
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 31d4f3f..7f37c7c 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -587,7 +587,8 @@
 		return -ENODEV;
 	}
 
-	rsdp = (struct acpi_table_rsdp *)__va(rsdp_phys);
+	rsdp = (struct acpi_table_rsdp *)__acpi_map_table(rsdp_phys,
+		sizeof(struct acpi_table_rsdp));
 	if (!rsdp) {
 		printk(KERN_WARNING PREFIX "Unable to map RSDP\n");
 		return -ENODEV;
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
index 69f4c7c..cac09e3 100644
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -1972,7 +1972,7 @@
 		    "(itf %d): No suitable DMA available.\n", lanai->number);
 		return -EBUSY;
 	}
-	if (pci_set_consistent_dma_mask(pci, 0xFFFFFFFF) != 0) {
+	if (pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) != 0) {
 		printk(KERN_WARNING DEV_LABEL
 		    "(itf %d): No suitable DMA available.\n", lanai->number);
 		return -EBUSY;
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 105a0d6..dd547af 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -47,16 +47,16 @@
 	.uevent		= memory_uevent,
 };
 
-static struct notifier_block *memory_chain;
+static BLOCKING_NOTIFIER_HEAD(memory_chain);
 
 int register_memory_notifier(struct notifier_block *nb)
 {
-        return notifier_chain_register(&memory_chain, nb);
+        return blocking_notifier_chain_register(&memory_chain, nb);
 }
 
 void unregister_memory_notifier(struct notifier_block *nb)
 {
-        notifier_chain_unregister(&memory_chain, nb);
+        blocking_notifier_chain_unregister(&memory_chain, nb);
 }
 
 /*
@@ -140,7 +140,7 @@
 
 static inline int memory_notify(unsigned long val, void *v)
 {
-	return notifier_call_chain(&memory_chain, val, v);
+	return blocking_notifier_call_chain(&memory_chain, val, v);
 }
 
 /*
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 9bdea2a..45bcda5 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -41,6 +41,7 @@
 #include <linux/timer.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/jiffies.h>
 #include <linux/random.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -311,11 +312,10 @@
 		CommandsRemaining = CommandAllocationGroupSize;
 	  CommandGroupByteCount =
 		CommandsRemaining * CommandAllocationLength;
-	  AllocationPointer = kmalloc(CommandGroupByteCount, GFP_ATOMIC);
+	  AllocationPointer = kzalloc(CommandGroupByteCount, GFP_ATOMIC);
 	  if (AllocationPointer == NULL)
 		return DAC960_Failure(Controller,
 					"AUXILIARY STRUCTURE CREATION");
-	  memset(AllocationPointer, 0, CommandGroupByteCount);
 	 }
       Command = (DAC960_Command_T *) AllocationPointer;
       AllocationPointer += CommandAllocationLength;
@@ -2709,14 +2709,12 @@
   void __iomem *BaseAddress;
   int i;
 
-  Controller = (DAC960_Controller_T *)
-	kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
+  Controller = kzalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
   if (Controller == NULL) {
 	DAC960_Error("Unable to allocate Controller structure for "
                        "Controller at\n", NULL);
 	return NULL;
   }
-  memset(Controller, 0, sizeof(DAC960_Controller_T));
   Controller->ControllerNumber = DAC960_ControllerCount;
   DAC960_Controllers[DAC960_ControllerCount++] = Controller;
   Controller->Bus = PCI_Device->bus->number;
@@ -3657,8 +3655,8 @@
 	      (NewEnquiry->EventLogSequenceNumber !=
 	       OldEnquiry->EventLogSequenceNumber) ||
 	      Controller->MonitoringTimerCount == 0 ||
-	      (jiffies - Controller->SecondaryMonitoringTime
-	       >= DAC960_SecondaryMonitoringInterval))
+	      time_after_eq(jiffies, Controller->SecondaryMonitoringTime
+	       + DAC960_SecondaryMonitoringInterval))
 	    {
 	      Controller->V1.NeedLogicalDriveInformation = true;
 	      Controller->V1.NewEventLogSequenceNumber =
@@ -5643,8 +5641,8 @@
       unsigned int StatusChangeCounter =
 	Controller->V2.HealthStatusBuffer->StatusChangeCounter;
       boolean ForceMonitoringCommand = false;
-      if (jiffies - Controller->SecondaryMonitoringTime
-	  > DAC960_SecondaryMonitoringInterval)
+      if (time_after(jiffies, Controller->SecondaryMonitoringTime
+	  + DAC960_SecondaryMonitoringInterval))
 	{
 	  int LogicalDriveNumber;
 	  for (LogicalDriveNumber = 0;
@@ -5672,8 +5670,8 @@
 	   ControllerInfo->ConsistencyChecksActive +
 	   ControllerInfo->RebuildsActive +
 	   ControllerInfo->OnlineExpansionsActive == 0 ||
-	   jiffies - Controller->PrimaryMonitoringTime
-	   < DAC960_MonitoringTimerInterval) &&
+	   time_before(jiffies, Controller->PrimaryMonitoringTime
+	   + DAC960_MonitoringTimerInterval)) &&
 	  !ForceMonitoringCommand)
 	{
 	  Controller->MonitoringTimer.expires =
@@ -5810,8 +5808,8 @@
       Controller->ProgressBufferLength = Length;
       if (Controller->EphemeralProgressMessage)
 	{
-	  if (jiffies - Controller->LastProgressReportTime
-	      >= DAC960_ProgressReportingInterval)
+	  if (time_after_eq(jiffies, Controller->LastProgressReportTime
+	      + DAC960_ProgressReportingInterval))
 	    {
 	      printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
 		     Controller->ControllerNumber, Buffer);
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index e57ac5a..ae0949b 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -383,8 +383,9 @@
 	  thus say N here.
 
 config BLK_DEV_RAM_COUNT
-	int "Default number of RAM disks" if BLK_DEV_RAM
+	int "Default number of RAM disks"
 	default "16"
+	depends on BLK_DEV_RAM
 	help
 	  The default value is 16 RAM disks. Change this if you know what
 	  are doing. If you boot from a filesystem that needs to be extracted
@@ -400,13 +401,16 @@
 	  8192.
 
 config BLK_DEV_INITRD
-	bool "Initial RAM disk (initrd) support"
+	bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
 	help
-	  The initial RAM disk is a RAM disk that is loaded by the boot loader
-	  (loadlin or lilo) and that is mounted as root before the normal boot
-	  procedure. It is typically used to load modules needed to mount the
-	  "real" root file system, etc. See <file:Documentation/initrd.txt>
-	  for details.
+	  The initial RAM filesystem is a ramfs which is loaded by the
+	  boot loader (loadlin or lilo) and that is mounted as root
+	  before the normal boot procedure. It is typically used to
+	  load modules needed to mount the "real" root file system,
+	  etc. See <file:Documentation/initrd.txt> for details.
+
+	  If RAM disk support (BLK_DEV_RAM) is also included, this
+	  also enables initial RAM disk (initrd) support.
 
 
 config CDROM_PKTCDVD
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
index a5c1c8e..4cb9c13 100644
--- a/drivers/block/acsi_slm.c
+++ b/drivers/block/acsi_slm.c
@@ -369,8 +369,6 @@
 	int length;
 	int end;
 
-	if (count < 0)
-		return( -EINVAL );
 	if (!(page = __get_free_page( GFP_KERNEL )))
 		return( -ENOMEM );
 	
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index b6e2909..2a8af68 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1850,6 +1850,7 @@
 		return 0;
 	printk (KERN_INFO "amiflop: Setting default df0 to %x\n", n);
 	fd_def_df0 = n;
+	return 1;
 }
 
 __setup("floppy=", amiga_floppy_setup);
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index 32fea55..393b86a 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -211,9 +211,7 @@
 		return;
 	}
 
-	d->bufpool = mempool_create(MIN_BUFS,
-				    mempool_alloc_slab, mempool_free_slab,
-				    buf_pool_cache);
+	d->bufpool = mempool_create_slab_pool(MIN_BUFS, buf_pool_cache);
 	if (d->bufpool == NULL) {
 		printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate bufpool "
 			"for %ld.%ld\n", d->aoemajor, d->aoeminor);
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 71ec9e6..1b0fd31 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -996,13 +996,11 @@
 			status = -EINVAL;
 			goto cleanup1;
 		}
-		buff = (unsigned char **) kmalloc(MAXSGENTRIES * 
-				sizeof(char *), GFP_KERNEL);
+		buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
 		if (!buff) {
 			status = -ENOMEM;
 			goto cleanup1;
 		}
-		memset(buff, 0, MAXSGENTRIES);
 		buff_size = (int *) kmalloc(MAXSGENTRIES * sizeof(int), 
 					GFP_KERNEL);
 		if (!buff_size) {
@@ -2729,9 +2727,9 @@
                         return;
                 }
         }
+default_int_mode:
 #endif /* CONFIG_PCI_MSI */
 	/* if we get here we're going to use the default interrupt mode */
-default_int_mode:
         c->intr[SIMPLE_MODE_INT] = pdev->irq;
 	return;
 }
@@ -2940,13 +2938,12 @@
 	int block_size;
 	int total_size; 
 
-	ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
+	ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
 	if (ld_buff == NULL)
 	{
 		printk(KERN_ERR "cciss: out of memory\n");
 		return;
 	}
-	memset(ld_buff, 0, sizeof(ReportLunData_struct));
 	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
         if (size_buff == NULL)
         {
@@ -3060,10 +3057,9 @@
 	for(i=0; i< MAX_CTLR; i++) {
 		if (!hba[i]) {
 			ctlr_info_t *p;
-			p = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+			p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL);
 			if (!p)
 				goto Enomem;
-			memset(p, 0, sizeof(ctlr_info_t));
 			for (n = 0; n < NWD; n++)
 				p->gendisk[n] = disk[n];
 			hba[i] = p;
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index 0e66e90..597c007 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -1027,12 +1027,11 @@
 	int i;
 
 	c = (ctlr_info_t *) hba[cntl_num];	
-	ld_buff = kmalloc(reportlunsize, GFP_KERNEL);
+	ld_buff = kzalloc(reportlunsize, GFP_KERNEL);
 	if (ld_buff == NULL) {
 		printk(KERN_ERR "cciss: out of memory\n");
 		return;
 	}
-	memset(ld_buff, 0, reportlunsize);
 	inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
         if (inq_buff == NULL) {
                 printk(KERN_ERR "cciss: out of memory\n");
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 840919b..bedb689 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -170,6 +170,7 @@
 #include <linux/mm.h>
 #include <linux/bio.h>
 #include <linux/string.h>
+#include <linux/jiffies.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h>	/* CMOS defines */
@@ -250,6 +251,18 @@
 #include <linux/cdrom.h>	/* for the compatibility eject ioctl */
 #include <linux/completion.h>
 
+/*
+ * Interrupt freeing also means /proc VFS work - dont do it
+ * from interrupt context. We push this work into keventd:
+ */
+static void fd_free_irq_fn(void *data)
+{
+	fd_free_irq();
+}
+
+static DECLARE_WORK(fd_free_irq_work, fd_free_irq_fn, NULL);
+
+
 static struct request *current_req;
 static struct request_queue *floppy_queue;
 static void do_fd_request(request_queue_t * q);
@@ -735,7 +748,7 @@
 {
 	int fdc = FDC(drive);
 #ifdef FLOPPY_SANITY_CHECK
-	if (jiffies - UDRS->select_date < UDP->select_delay)
+	if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
 		DPRINT("WARNING disk change called early\n");
 	if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
 	    (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
@@ -1063,7 +1076,7 @@
 		return 1;
 	}
 
-	if ((signed)(jiffies - delay) < 0) {
+	if (time_before(jiffies, delay)) {
 		del_timer(&fd_timer);
 		fd_timer.function = function;
 		fd_timer.expires = delay;
@@ -1523,7 +1536,7 @@
 		 * again just before spinup completion. Beware that
 		 * after scandrives, we must again wait for selection.
 		 */
-		if ((signed)(ready_date - jiffies) > DP->select_delay) {
+		if (time_after(ready_date, jiffies + DP->select_delay)) {
 			ready_date -= DP->select_delay;
 			function = (timeout_fn) floppy_start;
 		} else
@@ -3811,7 +3824,7 @@
 	if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
 		return 1;
 
-	if (UDP->checkfreq < (int)(jiffies - UDRS->last_checked)) {
+	if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
 		if (floppy_grab_irq_and_dma()) {
 			return 1;
 		}
@@ -4433,6 +4446,13 @@
 		return 0;
 	}
 	spin_unlock_irqrestore(&floppy_usage_lock, flags);
+
+	/*
+	 * We might have scheduled a free_irq(), wait it to
+	 * drain first:
+	 */
+	flush_scheduled_work();
+
 	if (fd_request_irq()) {
 		DPRINT("Unable to grab IRQ%d for the floppy driver\n",
 		       FLOPPY_IRQ);
@@ -4522,7 +4542,7 @@
 	if (irqdma_allocated) {
 		fd_disable_dma();
 		fd_free_dma();
-		fd_free_irq();
+		schedule_work(&fd_free_irq_work);
 		irqdma_allocated = 0;
 	}
 	set_dor(0, ~0, 8);
@@ -4633,6 +4653,8 @@
 	/* eject disk, if any */
 	fd_eject(0);
 
+	flush_scheduled_work();		/* fd_free_irq() might be pending */
+
 	wait_for_completion(&device_release);
 }
 
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 74bf025..9c3b94e 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -839,7 +839,9 @@
 
 	set_blocksize(bdev, lo_blocksize);
 
-	kernel_thread(loop_thread, lo, CLONE_KERNEL);
+	error = kernel_thread(loop_thread, lo, CLONE_KERNEL);
+	if (error < 0)
+		goto out_putf;
 	wait_for_completion(&lo->lo_done);
 	return 0;
 
diff --git a/drivers/block/paride/bpck6.c b/drivers/block/paride/bpck6.c
index 08d858a..41a237c 100644
--- a/drivers/block/paride/bpck6.c
+++ b/drivers/block/paride/bpck6.c
@@ -224,10 +224,9 @@
 
 static int bpck6_init_proto(PIA *pi)
 {
-	Interface *p = kmalloc(sizeof(Interface), GFP_KERNEL);
+	Interface *p = kzalloc(sizeof(Interface), GFP_KERNEL);
 
 	if (p) {
-		memset(p, 0, sizeof(Interface));
 		pi->private = (unsigned long)p;
 		return 0;
 	}
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 62d2464..2403721 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -151,6 +151,7 @@
 #include <linux/cdrom.h>	/* for the eject ioctl */
 #include <linux/blkdev.h>
 #include <linux/blkpg.h>
+#include <linux/kernel.h>
 #include <asm/uaccess.h>
 #include <linux/sched.h>
 #include <linux/workqueue.h>
@@ -275,7 +276,7 @@
 	int i;
 
 	printk("%s: %s: status = 0x%x =", disk->name, msg, status);
-	for (i = 0; i < 18; i++)
+	for (i = 0; i < ARRAY_SIZE(pd_errs); i++)
 		if (status & (1 << i))
 			printk(" %s", pd_errs[i]);
 	printk("\n");
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
index 6f5df0f..79b8682 100644
--- a/drivers/block/paride/pg.c
+++ b/drivers/block/paride/pg.c
@@ -643,7 +643,8 @@
 
 static int __init pg_init(void)
 {
-	int unit, err = 0;
+	int unit;
+	int err;
 
 	if (disable){
 		err = -1;
@@ -657,16 +658,17 @@
 		goto out;
 	}
 
-	if (register_chrdev(major, name, &pg_fops)) {
+	err = register_chrdev(major, name, &pg_fops);
+	if (err < 0) {
 		printk("pg_init: unable to get major number %d\n", major);
 		for (unit = 0; unit < PG_UNITS; unit++) {
 			struct pg *dev = &devices[unit];
 			if (dev->present)
 				pi_release(dev->pi);
 		}
-		err = -1;
 		goto out;
 	}
+	major = err;	/* In case the user specified `major=0' (dynamic) */
 	pg_class = class_create(THIS_MODULE, "pg");
 	if (IS_ERR(pg_class)) {
 		err = PTR_ERR(pg_class);
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index 715ae5d..d2013d3 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -943,7 +943,8 @@
 
 static int __init pt_init(void)
 {
-	int unit, err = 0;
+	int unit;
+	int err;
 
 	if (disable) {
 		err = -1;
@@ -955,14 +956,15 @@
 		goto out;
 	}
 
-	if (register_chrdev(major, name, &pt_fops)) {
+	err = register_chrdev(major, name, &pt_fops);
+	if (err < 0) {
 		printk("pt_init: unable to get major number %d\n", major);
 		for (unit = 0; unit < PT_UNITS; unit++)
 			if (pt[unit].present)
 				pi_release(pt[unit].pi);
-		err = -1;
 		goto out;
 	}
+	major = err;
 	pt_class = class_create(THIS_MODULE, "pt");
 	if (IS_ERR(pt_class)) {
 		err = PTR_ERR(pt_class);
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 1d261f9..a04f606 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -230,16 +230,6 @@
 	return 1;
 }
 
-static void *pkt_rb_alloc(gfp_t gfp_mask, void *data)
-{
-	return kmalloc(sizeof(struct pkt_rb_node), gfp_mask);
-}
-
-static void pkt_rb_free(void *ptr, void *data)
-{
-	kfree(ptr);
-}
-
 static inline struct pkt_rb_node *pkt_rbtree_next(struct pkt_rb_node *node)
 {
 	struct rb_node *n = rb_next(&node->rb_node);
@@ -2073,16 +2063,6 @@
 }
 
 
-static void *psd_pool_alloc(gfp_t gfp_mask, void *data)
-{
-	return kmalloc(sizeof(struct packet_stacked_data), gfp_mask);
-}
-
-static void psd_pool_free(void *ptr, void *data)
-{
-	kfree(ptr);
-}
-
 static int pkt_end_io_read_cloned(struct bio *bio, unsigned int bytes_done, int err)
 {
 	struct packet_stacked_data *psd = bio->bi_private;
@@ -2475,7 +2455,8 @@
 	if (!pd)
 		return ret;
 
-	pd->rb_pool = mempool_create(PKT_RB_POOL_SIZE, pkt_rb_alloc, pkt_rb_free, NULL);
+	pd->rb_pool = mempool_create_kmalloc_pool(PKT_RB_POOL_SIZE,
+						  sizeof(struct pkt_rb_node));
 	if (!pd->rb_pool)
 		goto out_mem;
 
@@ -2639,7 +2620,8 @@
 {
 	int ret;
 
-	psd_pool = mempool_create(PSD_POOL_SIZE, psd_pool_alloc, psd_pool_free, NULL);
+	psd_pool = mempool_create_kmalloc_pool(PSD_POOL_SIZE,
+					sizeof(struct packet_stacked_data));
 	if (!psd_pool)
 		return -ENOMEM;
 
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index c16e66b..f7d4c65 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -50,6 +50,7 @@
 #include <linux/timer.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/dma-mapping.h>
 
 #include <linux/fcntl.h>        /* O_ACCMODE */
 #include <linux/hdreg.h>  /* HDIO_GETGEO */
@@ -881,8 +882,8 @@
 	printk(KERN_INFO "Micro Memory(tm) controller #%d found at %02x:%02x (PCI Mem Module (Battery Backup))\n",
 	       card->card_number, dev->bus->number, dev->devfn);
 
-	if (pci_set_dma_mask(dev, 0xffffffffffffffffLL) &&
-	    pci_set_dma_mask(dev, 0xffffffffLL)) {
+	if (pci_set_dma_mask(dev, DMA_64BIT_MASK) &&
+	    pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
 		printk(KERN_WARNING "MM%d: NO suitable DMA found\n",num_cards);
 		return  -ENOMEM;
 	}
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 5980f3e..889cad0 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -187,6 +187,7 @@
 config ISI
 	tristate "Multi-Tech multiport card support (EXPERIMENTAL)"
 	depends on SERIAL_NONSTANDARD
+	select FW_LOADER
 	help
 	  This is a driver for the Multi-Tech cards which provide several
 	  serial ports.  The driver is experimental and can currently only be
@@ -560,14 +561,31 @@
 
 	  If unsure, say N.
 
+config HVC_DRIVER
+	bool
+	help
+	  Users of pSeries machines that want to utilize the hvc console front-end
+	  module for their backend console driver should select this option.
+	  It will automatically be selected if one of the back-end console drivers
+	  is selected.
+
+
 config HVC_CONSOLE
 	bool "pSeries Hypervisor Virtual Console support"
 	depends on PPC_PSERIES
+	select HVC_DRIVER
 	help
 	  pSeries machines when partitioned support a hypervisor virtual
 	  console. This driver allows each pSeries partition to have a console
 	  which is accessed via the HMC.
 
+config HVC_RTAS
+	bool "IBM RTAS Console support"
+	depends on PPC_RTAS
+	select HVC_DRIVER
+	help
+	  IBM Console device driver which makes use of RTAS
+
 config HVCS
 	tristate "IBM Hypervisor Virtual Console Server support"
 	depends on PPC_PSERIES
@@ -695,7 +713,7 @@
 
 config RTC
 	tristate "Enhanced Real Time Clock Support"
-	depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV
+	depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM
 	---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 b2a1124..a73cb49 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -41,7 +41,9 @@
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 obj-$(CONFIG_SX)		+= sx.o generic_serial.o
 obj-$(CONFIG_RIO)		+= rio/ generic_serial.o
-obj-$(CONFIG_HVC_CONSOLE)	+= hvc_console.o hvc_vio.o hvsi.o
+obj-$(CONFIG_HVC_DRIVER)	+= hvc_console.o
+obj-$(CONFIG_HVC_CONSOLE)	+= hvc_vio.o hvsi.o
+obj-$(CONFIG_HVC_RTAS)		+= hvc_rtas.o
 obj-$(CONFIG_RAW_DRIVER)	+= raw.o
 obj-$(CONFIG_SGI_SNSC)		+= snsc.o snsc_event.o
 obj-$(CONFIG_MMTIMER)		+= mmtimer.o
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 70b8ed9..4c67135 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -11,6 +11,7 @@
 #include <linux/gfp.h>
 #include <linux/page-flags.h>
 #include <linux/mm.h>
+#include <linux/jiffies.h>
 #include "agp.h"
 
 /* NVIDIA registers */
@@ -256,7 +257,7 @@
 		do {
 			pci_read_config_dword(nvidia_private.dev_1,
 					NVIDIA_1_WBC, &wbc_reg);
-			if ((signed)(end - jiffies) <= 0) {
+			if (time_before_eq(end, jiffies)) {
 				printk(KERN_ERR PFX
 				    "TLB flush took more than 3 seconds.\n");
 			}
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 107df9f..edc72a6 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -357,6 +357,12 @@
 	spinlock_t lock;
 } drm_freelist_t;
 
+typedef struct drm_dma_handle {
+	dma_addr_t busaddr;
+	void *vaddr;
+	size_t size;
+} drm_dma_handle_t;
+
 /**
  * Buffer entry.  There is one of this for each buffer size order.
  */
@@ -366,7 +372,7 @@
 	drm_buf_t *buflist;		/**< buffer list */
 	int seg_count;
 	int page_order;
-	unsigned long *seglist;
+	drm_dma_handle_t **seglist;
 
 	drm_freelist_t freelist;
 } drm_buf_entry_t;
@@ -483,12 +489,6 @@
 	drm_hw_lock_t *lock;
 } drm_sigdata_t;
 
-typedef struct drm_dma_handle {
-	dma_addr_t busaddr;
-	void *vaddr;
-	size_t size;
-} drm_dma_handle_t;
-
 /**
  * Mappings list
  */
@@ -813,8 +813,6 @@
 extern int drm_mem_info(char *buf, char **start, off_t offset,
 			int request, int *eof, void *data);
 extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
-extern unsigned long drm_alloc_pages(int order, int area);
-extern void drm_free_pages(unsigned long address, int order, int area);
 extern void *drm_ioremap(unsigned long offset, unsigned long size,
 			 drm_device_t * dev);
 extern void *drm_ioremap_nocache(unsigned long offset, unsigned long size,
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index e2637b4..8a9cf12 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -474,8 +474,7 @@
 	if (entry->seg_count) {
 		for (i = 0; i < entry->seg_count; i++) {
 			if (entry->seglist[i]) {
-				drm_free_pages(entry->seglist[i],
-					       entry->page_order, DRM_MEM_DMA);
+				drm_pci_free(dev, entry->seglist[i]);
 			}
 		}
 		drm_free(entry->seglist,
@@ -678,7 +677,7 @@
 	int total;
 	int page_order;
 	drm_buf_entry_t *entry;
-	unsigned long page;
+	drm_dma_handle_t *dmah;
 	drm_buf_t *buf;
 	int alignment;
 	unsigned long offset;
@@ -781,8 +780,10 @@
 	page_count = 0;
 
 	while (entry->buf_count < count) {
-		page = drm_alloc_pages(page_order, DRM_MEM_DMA);
-		if (!page) {
+		
+		dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000, 0xfffffffful);
+		
+		if (!dmah) {
 			/* Set count correctly so we free the proper amount. */
 			entry->buf_count = count;
 			entry->seg_count = count;
@@ -794,13 +795,13 @@
 			atomic_dec(&dev->buf_alloc);
 			return -ENOMEM;
 		}
-		entry->seglist[entry->seg_count++] = page;
+		entry->seglist[entry->seg_count++] = dmah;
 		for (i = 0; i < (1 << page_order); i++) {
 			DRM_DEBUG("page %d @ 0x%08lx\n",
 				  dma->page_count + page_count,
-				  page + PAGE_SIZE * i);
+				  (unsigned long)dmah->vaddr + PAGE_SIZE * i);
 			temp_pagelist[dma->page_count + page_count++]
-			    = page + PAGE_SIZE * i;
+				= (unsigned long)dmah->vaddr + PAGE_SIZE * i;
 		}
 		for (offset = 0;
 		     offset + size <= total && entry->buf_count < count;
@@ -811,7 +812,8 @@
 			buf->order = order;
 			buf->used = 0;
 			buf->offset = (dma->byte_count + byte_count + offset);
-			buf->address = (void *)(page + offset);
+			buf->address = (void *)(dmah->vaddr + offset);
+			buf->bus_address = dmah->busaddr + offset;
 			buf->next = NULL;
 			buf->waiting = 0;
 			buf->pending = 0;
diff --git a/drivers/char/drm/drm_dma.c b/drivers/char/drm/drm_dma.c
index 2afab95..892db70 100644
--- a/drivers/char/drm/drm_dma.c
+++ b/drivers/char/drm/drm_dma.c
@@ -85,9 +85,7 @@
 				  dma->bufs[i].seg_count);
 			for (j = 0; j < dma->bufs[i].seg_count; j++) {
 				if (dma->bufs[i].seglist[j]) {
-					drm_free_pages(dma->bufs[i].seglist[j],
-						       dma->bufs[i].page_order,
-						       DRM_MEM_DMA);
+					drm_pci_free(dev, dma->bufs[i].seglist[j]);
 				}
 			}
 			drm_free(dma->bufs[i].seglist,
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 641f763..b7f7951 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -175,7 +175,7 @@
 	drm_device_t *dev = NULL;
 	int minor = iminor(inode);
 	int err = -ENODEV;
-	struct file_operations *old_fops;
+	const struct file_operations *old_fops;
 
 	DRM_DEBUG("\n");
 
diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c
index 8074771..dddf8de 100644
--- a/drivers/char/drm/drm_memory.c
+++ b/drivers/char/drm/drm_memory.c
@@ -79,65 +79,6 @@
 	return pt;
 }
 
-/**
- * Allocate pages.
- *
- * \param order size order.
- * \param area memory area. (Not used.)
- * \return page address on success, or zero on failure.
- *
- * Allocate and reserve free pages.
- */
-unsigned long drm_alloc_pages(int order, int area)
-{
-	unsigned long address;
-	unsigned long bytes = PAGE_SIZE << order;
-	unsigned long addr;
-	unsigned int sz;
-
-	address = __get_free_pages(GFP_KERNEL|__GFP_COMP, order);
-	if (!address)
-		return 0;
-
-	/* Zero */
-	memset((void *)address, 0, bytes);
-
-	/* Reserve */
-	for (addr = address, sz = bytes;
-	     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-		SetPageReserved(virt_to_page(addr));
-	}
-
-	return address;
-}
-
-/**
- * Free pages.
- *
- * \param address address of the pages to free.
- * \param order size order.
- * \param area memory area. (Not used.)
- *
- * Unreserve and free pages allocated by alloc_pages().
- */
-void drm_free_pages(unsigned long address, int order, int area)
-{
-	unsigned long bytes = PAGE_SIZE << order;
-	unsigned long addr;
-	unsigned int sz;
-
-	if (!address)
-		return;
-
-	/* Unreserve */
-	for (addr = address, sz = bytes;
-	     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-		ClearPageReserved(virt_to_page(addr));
-	}
-
-	free_pages(address, order);
-}
-
 #if __OS_HAS_AGP
 /** Wrapper around agp_allocate_memory() */
 DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type)
diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h
index e84605f..7868341 100644
--- a/drivers/char/drm/drm_memory_debug.h
+++ b/drivers/char/drm/drm_memory_debug.h
@@ -206,76 +206,6 @@
 	}
 }
 
-unsigned long drm_alloc_pages (int order, int area) {
-	unsigned long address;
-	unsigned long bytes = PAGE_SIZE << order;
-	unsigned long addr;
-	unsigned int sz;
-
-	spin_lock(&drm_mem_lock);
-	if ((drm_ram_used >> PAGE_SHIFT)
-	    > (DRM_RAM_PERCENT * drm_ram_available) / 100) {
-		spin_unlock(&drm_mem_lock);
-		return 0;
-	}
-	spin_unlock(&drm_mem_lock);
-
-	address = __get_free_pages(GFP_KERNEL|__GFP_COMP, order);
-	if (!address) {
-		spin_lock(&drm_mem_lock);
-		++drm_mem_stats[area].fail_count;
-		spin_unlock(&drm_mem_lock);
-		return 0;
-	}
-	spin_lock(&drm_mem_lock);
-	++drm_mem_stats[area].succeed_count;
-	drm_mem_stats[area].bytes_allocated += bytes;
-	drm_ram_used += bytes;
-	spin_unlock(&drm_mem_lock);
-
-	/* Zero outside the lock */
-	memset((void *)address, 0, bytes);
-
-	/* Reserve */
-	for (addr = address, sz = bytes;
-	     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-		SetPageReserved(virt_to_page(addr));
-	}
-
-	return address;
-}
-
-void drm_free_pages (unsigned long address, int order, int area) {
-	unsigned long bytes = PAGE_SIZE << order;
-	int alloc_count;
-	int free_count;
-	unsigned long addr;
-	unsigned int sz;
-
-	if (!address) {
-		DRM_MEM_ERROR(area, "Attempt to free address 0\n");
-	} else {
-		/* Unreserve */
-		for (addr = address, sz = bytes;
-		     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-			ClearPageReserved(virt_to_page(addr));
-		}
-		free_pages(address, order);
-	}
-
-	spin_lock(&drm_mem_lock);
-	free_count = ++drm_mem_stats[area].free_count;
-	alloc_count = drm_mem_stats[area].succeed_count;
-	drm_mem_stats[area].bytes_freed += bytes;
-	drm_ram_used -= bytes;
-	spin_unlock(&drm_mem_lock);
-	if (free_count > alloc_count) {
-		DRM_MEM_ERROR(area,
-			      "Excess frees: %d frees, %d allocs\n",
-			      free_count, alloc_count);
-	}
-}
-
 void *drm_ioremap (unsigned long offset, unsigned long size,
 		    drm_device_t * dev) {
 	void *pt;
diff --git a/drivers/char/drm/drm_pci.c b/drivers/char/drm/drm_pci.c
index 1fd7ff1..b28ca9c 100644
--- a/drivers/char/drm/drm_pci.c
+++ b/drivers/char/drm/drm_pci.c
@@ -50,6 +50,10 @@
 				dma_addr_t maxaddr)
 {
 	drm_dma_handle_t *dmah;
+#if 1
+	unsigned long addr;
+	size_t sz;
+#endif
 #ifdef DRM_DEBUG_MEMORY
 	int area = DRM_MEM_DMA;
 
@@ -79,7 +83,7 @@
 		return NULL;
 
 	dmah->size = size;
-	dmah->vaddr = pci_alloc_consistent(dev->pdev, size, &dmah->busaddr);
+	dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP);
 
 #ifdef DRM_DEBUG_MEMORY
 	if (dmah->vaddr == NULL) {
@@ -104,18 +108,29 @@
 
 	memset(dmah->vaddr, 0, size);
 
+	/* XXX - Is virt_to_page() legal for consistent mem? */
+	/* Reserve */
+	for (addr = (unsigned long)dmah->vaddr, sz = size;
+	     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+		SetPageReserved(virt_to_page(addr));
+	}
+
 	return dmah;
 }
 
 EXPORT_SYMBOL(drm_pci_alloc);
 
 /**
- * \brief Free a PCI consistent memory block with freeing its descriptor.
+ * \brief Free a PCI consistent memory block without freeing its descriptor.
  *
  * This function is for internal use in the Linux-specific DRM core code.
  */
 void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah)
 {
+#if 1
+	unsigned long addr;
+	size_t sz;
+#endif
 #ifdef DRM_DEBUG_MEMORY
 	int area = DRM_MEM_DMA;
 	int alloc_count;
@@ -127,8 +142,14 @@
 		DRM_MEM_ERROR(area, "Attempt to free address 0\n");
 #endif
 	} else {
-		pci_free_consistent(dev->pdev, dmah->size, dmah->vaddr,
-				    dmah->busaddr);
+		/* XXX - Is virt_to_page() legal for consistent mem? */
+		/* Unreserve */
+		for (addr = (unsigned long)dmah->vaddr, sz = dmah->size;
+		     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+			ClearPageReserved(virt_to_page(addr));
+		}
+		dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr,
+				  dmah->busaddr);
 	}
 
 #ifdef DRM_DEBUG_MEMORY
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index 2c17e88..b1bb3c7 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -3,49 +3,69 @@
    Please contact dri-devel@lists.sf.net to add new cards to this list
 */
 #define radeon_PCI_IDS \
-	{0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350},\
+	{0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
 	{0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP}, \
 	{0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
 	{0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+	{0x1002, 0x4148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+	{0x1002, 0x4149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+	{0x1002, 0x414A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+	{0x1002, 0x414B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4153, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+	{0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
-	{0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS250|CHIP_IS_IGP}, \
+	{0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
 	{0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS250|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
-	{0x1002, 0x4965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
-	{0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
-	{0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
-	{0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \
-	{0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \
+	{0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
+	{0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
+	{0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
 	{0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
-	{0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+	{0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E47, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
-	{0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+	{0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
@@ -53,44 +73,66 @@
 	{0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
 	{0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
 	{0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x5149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x514A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x514B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x514E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x514F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \
 	{0x1002, 0x5158, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \
 	{0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
-	{0x1002, 0x5168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x5169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x516A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x516B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x516C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
-	{0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+	{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
 	{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
 	{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
-	{0x1002, 0x5837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
 	{0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
-	{0x1002, 0x5963, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
-	{0x1002, 0x5968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
+	{0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
-	{0x1002, 0x596A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
-	{0x1002, 0x596B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
+	{0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
 	{0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5c62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5c64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
-	{0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
-	{0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \
+	{0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
 	{0, 0, 0}
 
 #define r128_PCI_IDS \
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index ae0aa6d..c658dde 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -126,7 +126,7 @@
 	drm_device_t *dev = priv->head->dev;
 	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
 	drm_i810_private_t *dev_priv = dev->dev_private;
-	struct file_operations *old_fops;
+	const struct file_operations *old_fops;
 	int retcode = 0;
 
 	if (buf_priv->currently_mapped == I810_BUF_MAPPED)
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 163f2cb..b0f815d 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -128,7 +128,7 @@
 	drm_device_t *dev = priv->head->dev;
 	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
 	drm_i830_private_t *dev_priv = dev->dev_private;
-	struct file_operations *old_fops;
+	const struct file_operations *old_fops;
 	unsigned long virtual;
 	int retcode = 0;
 
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index 1ff4c7c..9f4b8ce 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -495,8 +495,6 @@
 		}
 	}
 
-	dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
-
 	i915_emit_breadcrumb(dev);
 
 	return 0;
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index d3879ac..a752afd 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -53,6 +53,8 @@
 
 	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
 
+	dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+
 	if (temp & USER_INT_FLAG)
 		DRM_WAKEUP(&dev_priv->irq_queue);
 
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c
index c08fa50..b108c7f 100644
--- a/drivers/char/drm/r300_cmdbuf.c
+++ b/drivers/char/drm/r300_cmdbuf.c
@@ -214,13 +214,13 @@
 	ADD_RANGE(0x4F54, 1);
 
 	ADD_RANGE(R300_TX_FILTER_0, 16);
-	ADD_RANGE(R300_TX_UNK1_0, 16);
+	ADD_RANGE(R300_TX_FILTER1_0, 16);
 	ADD_RANGE(R300_TX_SIZE_0, 16);
 	ADD_RANGE(R300_TX_FORMAT_0, 16);
 	ADD_RANGE(R300_TX_PITCH_0, 16);
 	/* Texture offset is dangerous and needs more checking */
 	ADD_RANGE_MARK(R300_TX_OFFSET_0, 16, MARK_CHECK_OFFSET);
-	ADD_RANGE(R300_TX_UNK4_0, 16);
+	ADD_RANGE(R300_TX_CHROMA_KEY_0, 16);
 	ADD_RANGE(R300_TX_BORDER_COLOR_0, 16);
 
 	/* Sporadic registers used as primitives are emitted */
@@ -242,8 +242,10 @@
 	return 0;
 }
 
-  /* we expect offsets passed to the framebuffer to be either within video memory or
-     within AGP space */
+/*
+ * we expect offsets passed to the framebuffer to be either within video 
+ * memory or within AGP space 
+ */
 static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv,
 					u32 offset)
 {
@@ -251,11 +253,11 @@
 	   but this value is not being kept.
 	   This code is correct for now (does the same thing as the
 	   code that sets MC_FB_LOCATION) in radeon_cp.c */
-	if ((offset >= dev_priv->fb_location) &&
-	    (offset < dev_priv->gart_vm_start))
+	if (offset >= dev_priv->fb_location &&
+	    offset < (dev_priv->fb_location + dev_priv->fb_size))
 		return 0;
-	if ((offset >= dev_priv->gart_vm_start) &&
-	    (offset < dev_priv->gart_vm_start + dev_priv->gart_size))
+	if (offset >= dev_priv->gart_vm_start &&
+	    offset < (dev_priv->gart_vm_start + dev_priv->gart_size))
 		return 0;
 	return 1;
 }
@@ -490,6 +492,7 @@
 
 	return 0;
 }
+
 static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
 					     drm_radeon_kcmd_buffer_t *cmdbuf)
 {
@@ -701,6 +704,64 @@
 	buf->used = 0;
 }
 
+static int r300_scratch(drm_radeon_private_t *dev_priv,
+			drm_radeon_kcmd_buffer_t *cmdbuf,
+			drm_r300_cmd_header_t header)
+{
+	u32 *ref_age_base;
+	u32 i, buf_idx, h_pending;
+	RING_LOCALS;
+	
+	if (cmdbuf->bufsz < 
+	    (sizeof(u64) + header.scratch.n_bufs * sizeof(buf_idx))) {
+		return DRM_ERR(EINVAL);
+	}
+	
+	if (header.scratch.reg >= 5) {
+		return DRM_ERR(EINVAL);
+	}
+	
+	dev_priv->scratch_ages[header.scratch.reg]++;
+	
+	ref_age_base = *(u32 **)cmdbuf->buf;
+	
+	cmdbuf->buf += sizeof(u64);
+	cmdbuf->bufsz -= sizeof(u64);
+	
+	for (i=0; i < header.scratch.n_bufs; i++) {
+		buf_idx = *(u32 *)cmdbuf->buf;
+		buf_idx *= 2; /* 8 bytes per buf */
+		
+		if (DRM_COPY_TO_USER(ref_age_base + buf_idx, &dev_priv->scratch_ages[header.scratch.reg], sizeof(u32))) {
+			return DRM_ERR(EINVAL);
+		}
+					
+		if (DRM_COPY_FROM_USER(&h_pending, ref_age_base + buf_idx + 1, sizeof(u32))) {
+			return DRM_ERR(EINVAL);
+		}
+					
+		if (h_pending == 0) {
+			return DRM_ERR(EINVAL);
+		}
+					
+		h_pending--;
+						
+		if (DRM_COPY_TO_USER(ref_age_base + buf_idx + 1, &h_pending, sizeof(u32))) {
+			return DRM_ERR(EINVAL);
+		}
+					
+		cmdbuf->buf += sizeof(buf_idx);
+		cmdbuf->bufsz -= sizeof(buf_idx);
+	}
+	
+	BEGIN_RING(2);
+	OUT_RING(CP_PACKET0(RADEON_SCRATCH_REG0 + header.scratch.reg * 4, 0));
+	OUT_RING(dev_priv->scratch_ages[header.scratch.reg]);
+	ADVANCE_RING();
+	
+	return 0;
+}
+
 /**
  * Parses and validates a user-supplied command buffer and emits appropriate
  * commands on the DMA ring buffer.
@@ -838,6 +899,15 @@
 			}
 			break;
 
+		case R300_CMD_SCRATCH:
+			DRM_DEBUG("R300_CMD_SCRATCH\n");
+			ret = r300_scratch(dev_priv, cmdbuf, header);
+			if (ret) {
+				DRM_ERROR("r300_scratch failed\n");
+				goto cleanup;
+			}
+			break;
+			
 		default:
 			DRM_ERROR("bad cmd_type %i at %p\n",
 				  header.header.cmd_type,
diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h
index d1e1995..a881f96 100644
--- a/drivers/char/drm/r300_reg.h
+++ b/drivers/char/drm/r300_reg.h
@@ -711,8 +711,22 @@
 #	define R300_TX_MAX_ANISO_16_TO_1 (8 << 21)
 #	define R300_TX_MAX_ANISO_MASK    (14 << 21)
 
-#define R300_TX_UNK1_0                      0x4440
+#define R300_TX_FILTER1_0                      0x4440
+#	define R300_CHROMA_KEY_MODE_DISABLE    0
+#	define R300_CHROMA_KEY_FORCE	       1
+#	define R300_CHROMA_KEY_BLEND           2
+#	define R300_MC_ROUND_NORMAL            (0<<2)
+#	define R300_MC_ROUND_MPEG4             (1<<2)
 #	define R300_LOD_BIAS_MASK	    0x1fff
+#	define R300_EDGE_ANISO_EDGE_DIAG       (0<<13)
+#	define R300_EDGE_ANISO_EDGE_ONLY       (1<<13)
+#	define R300_MC_COORD_TRUNCATE_DISABLE  (0<<14)
+#	define R300_MC_COORD_TRUNCATE_MPEG     (1<<14)
+#	define R300_TX_TRI_PERF_0_8            (0<<15)
+#	define R300_TX_TRI_PERF_1_8            (1<<15)
+#	define R300_TX_TRI_PERF_1_4            (2<<15)
+#	define R300_TX_TRI_PERF_3_8            (3<<15)
+#	define R300_ANISO_THRESHOLD_MASK       (7<<17)
 
 #define R300_TX_SIZE_0                      0x4480
 #       define R300_TX_WIDTHMASK_SHIFT           0
@@ -722,6 +736,8 @@
 #       define R300_TX_UNK23                     (1 << 23)
 #       define R300_TX_SIZE_SHIFT                26	/* largest of width, height */
 #       define R300_TX_SIZE_MASK                 (15 << 26)
+#       define R300_TX_SIZE_PROJECTED                     (1<<30)
+#       define R300_TX_SIZE_TXPITCH_EN                     (1<<31)
 #define R300_TX_FORMAT_0                    0x44C0
 	/* The interpretation of the format word by Wladimir van der Laan */
 	/* The X, Y, Z and W refer to the layout of the components.
@@ -750,7 +766,8 @@
 #	define R300_TX_FORMAT_B8G8_B8G8	    	    0x14	/* no swizzle */
 #	define R300_TX_FORMAT_G8R8_G8B8	    	    0x15	/* no swizzle */
 						  /* 0x16 - some 16 bit green format.. ?? */
-#	define R300_TX_FORMAT_UNK25		   (1 << 25)	/* no swizzle */
+#	define R300_TX_FORMAT_UNK25		   (1 << 25) /* no swizzle */
+#	define R300_TX_FORMAT_CUBIC_MAP		   (1 << 26)
 
 	/* gap */
 	/* Floating point formats */
@@ -800,18 +817,20 @@
 
 #	define R300_TX_FORMAT_YUV_MODE		0x00800000
 
-#define R300_TX_PITCH_0			    0x4500
+#define R300_TX_PITCH_0			    0x4500 /* obvious missing in gap */
 #define R300_TX_OFFSET_0                    0x4540
 /* BEGIN: Guess from R200 */
 #       define R300_TXO_ENDIAN_NO_SWAP           (0 << 0)
 #       define R300_TXO_ENDIAN_BYTE_SWAP         (1 << 0)
 #       define R300_TXO_ENDIAN_WORD_SWAP         (2 << 0)
 #       define R300_TXO_ENDIAN_HALFDW_SWAP       (3 << 0)
+#       define R300_TXO_MACRO_TILE               (1 << 2)
+#       define R300_TXO_MICRO_TILE               (1 << 3)
 #       define R300_TXO_OFFSET_MASK              0xffffffe0
 #       define R300_TXO_OFFSET_SHIFT             5
 /* END */
-#define R300_TX_UNK4_0                      0x4580
-#define R300_TX_BORDER_COLOR_0              0x45C0	//ff00ff00 == { 0, 1.0, 0, 1.0 }
+#define R300_TX_CHROMA_KEY_0                      0x4580 /* 32 bit chroma key */
+#define R300_TX_BORDER_COLOR_0              0x45C0 //ff00ff00 == { 0, 1.0, 0, 1.0 }
 
 /* END */
 
@@ -868,7 +887,9 @@
 #       define R300_PFS_NODE_TEX_OFFSET_MASK     (31 << 12)
 #       define R300_PFS_NODE_TEX_END_SHIFT       17
 #       define R300_PFS_NODE_TEX_END_MASK        (31 << 17)
-#       define R300_PFS_NODE_LAST_NODE           (1 << 22)
+/*#       define R300_PFS_NODE_LAST_NODE           (1 << 22) */
+#		define R300_PFS_NODE_OUTPUT_COLOR        (1 << 22)
+#		define R300_PFS_NODE_OUTPUT_DEPTH        (1 << 23)
 
 /* TEX
 // As far as I can tell, texture instructions cannot write into output
@@ -887,6 +908,7 @@
  */
 #		define R300_FPITX_OPCODE_SHIFT			15
 #			define R300_FPITX_OP_TEX			1
+#			define R300_FPITX_OP_KIL			2
 #			define R300_FPITX_OP_TXP			3
 #			define R300_FPITX_OP_TXB			4
 
@@ -962,9 +984,11 @@
 #       define R300_FPI1_SRC2C_CONST             (1 << 17)
 #       define R300_FPI1_DSTC_SHIFT              18
 #       define R300_FPI1_DSTC_MASK               (31 << 18)
+#		define R300_FPI1_DSTC_REG_MASK_SHIFT     23
 #       define R300_FPI1_DSTC_REG_X              (1 << 23)
 #       define R300_FPI1_DSTC_REG_Y              (1 << 24)
 #       define R300_FPI1_DSTC_REG_Z              (1 << 25)
+#		define R300_FPI1_DSTC_OUTPUT_MASK_SHIFT  26
 #       define R300_FPI1_DSTC_OUTPUT_X           (1 << 26)
 #       define R300_FPI1_DSTC_OUTPUT_Y           (1 << 27)
 #       define R300_FPI1_DSTC_OUTPUT_Z           (1 << 28)
@@ -983,6 +1007,7 @@
 #       define R300_FPI3_DSTA_MASK               (31 << 18)
 #       define R300_FPI3_DSTA_REG                (1 << 23)
 #       define R300_FPI3_DSTA_OUTPUT             (1 << 24)
+#		define R300_FPI3_DSTA_DEPTH              (1 << 27)
 
 #define R300_PFS_INSTR0_0                   0x48C0
 #       define R300_FPI0_ARGC_SRC0C_XYZ          0
@@ -1036,7 +1061,7 @@
 #       define R300_FPI0_OUTC_FRC                (9 << 23)
 #       define R300_FPI0_OUTC_REPL_ALPHA         (10 << 23)
 #       define R300_FPI0_OUTC_SAT                (1 << 30)
-#       define R300_FPI0_UNKNOWN_31              (1 << 31)
+#       define R300_FPI0_INSERT_NOP              (1 << 31)
 
 #define R300_PFS_INSTR2_0                   0x49C0
 #       define R300_FPI2_ARGA_SRC0C_X            0
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 9bb8ae0..7f949c9 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -1118,14 +1118,20 @@
 {
 	u32 ring_start, cur_read_ptr;
 	u32 tmp;
-
-	/* Initialize the memory controller */
-	RADEON_WRITE(RADEON_MC_FB_LOCATION,
-		     ((dev_priv->gart_vm_start - 1) & 0xffff0000)
-		     | (dev_priv->fb_location >> 16));
+	
+	/* Initialize the memory controller. With new memory map, the fb location
+	 * is not changed, it should have been properly initialized already. Part
+	 * of the problem is that the code below is bogus, assuming the GART is
+	 * always appended to the fb which is not necessarily the case
+	 */
+	if (!dev_priv->new_memmap)
+		RADEON_WRITE(RADEON_MC_FB_LOCATION,
+			     ((dev_priv->gart_vm_start - 1) & 0xffff0000)
+			     | (dev_priv->fb_location >> 16));
 
 #if __OS_HAS_AGP
 	if (dev_priv->flags & CHIP_IS_AGP) {
+		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
 		RADEON_WRITE(RADEON_MC_AGP_LOCATION,
 			     (((dev_priv->gart_vm_start - 1 +
 				dev_priv->gart_size) & 0xffff0000) |
@@ -1153,8 +1159,6 @@
 
 #if __OS_HAS_AGP
 	if (dev_priv->flags & CHIP_IS_AGP) {
-		/* set RADEON_AGP_BASE here instead of relying on X from user space */
-		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
 		RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
 			     dev_priv->ring_rptr->offset
 			     - dev->agp->base + dev_priv->gart_vm_start);
@@ -1174,6 +1178,17 @@
 			  entry->handle + tmp_ofs);
 	}
 
+	/* Set ring buffer size */
+#ifdef __BIG_ENDIAN
+	RADEON_WRITE(RADEON_CP_RB_CNTL,
+		     dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT);
+#else
+	RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw);
+#endif
+
+	/* Start with assuming that writeback doesn't work */
+	dev_priv->writeback_works = 0;
+
 	/* Initialize the scratch register pointer.  This will cause
 	 * the scratch register values to be written out to memory
 	 * whenever they are updated.
@@ -1190,7 +1205,38 @@
 
 	RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7);
 
-	/* Writeback doesn't seem to work everywhere, test it first */
+	/* Turn on bus mastering */
+	tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
+	RADEON_WRITE(RADEON_BUS_CNTL, tmp);
+
+	dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0;
+	RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
+
+	dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0;
+	RADEON_WRITE(RADEON_LAST_DISPATCH_REG,
+		     dev_priv->sarea_priv->last_dispatch);
+
+	dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0;
+	RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear);
+
+	radeon_do_wait_for_idle(dev_priv);
+
+	/* Sync everything up */
+	RADEON_WRITE(RADEON_ISYNC_CNTL,
+		     (RADEON_ISYNC_ANY2D_IDLE3D |
+		      RADEON_ISYNC_ANY3D_IDLE2D |
+		      RADEON_ISYNC_WAIT_IDLEGUI |
+		      RADEON_ISYNC_CPSCRATCH_IDLEGUI));
+
+}
+
+static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
+{
+	u32 tmp;
+
+	/* Writeback doesn't seem to work everywhere, test it here and possibly
+	 * enable it if it appears to work
+	 */
 	DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0);
 	RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef);
 
@@ -1203,46 +1249,15 @@
 
 	if (tmp < dev_priv->usec_timeout) {
 		dev_priv->writeback_works = 1;
-		DRM_DEBUG("writeback test succeeded, tmp=%d\n", tmp);
+		DRM_INFO("writeback test succeeded in %d usecs\n", tmp);
 	} else {
 		dev_priv->writeback_works = 0;
-		DRM_DEBUG("writeback test failed\n");
+		DRM_INFO("writeback test failed\n");
 	}
 	if (radeon_no_wb == 1) {
 		dev_priv->writeback_works = 0;
-		DRM_DEBUG("writeback forced off\n");
+		DRM_INFO("writeback forced off\n");
 	}
-
-	dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0;
-	RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
-
-	dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0;
-	RADEON_WRITE(RADEON_LAST_DISPATCH_REG,
-		     dev_priv->sarea_priv->last_dispatch);
-
-	dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0;
-	RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear);
-
-	/* Set ring buffer size */
-#ifdef __BIG_ENDIAN
-	RADEON_WRITE(RADEON_CP_RB_CNTL,
-		     dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT);
-#else
-	RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw);
-#endif
-
-	radeon_do_wait_for_idle(dev_priv);
-
-	/* Turn on bus mastering */
-	tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
-	RADEON_WRITE(RADEON_BUS_CNTL, tmp);
-
-	/* Sync everything up */
-	RADEON_WRITE(RADEON_ISYNC_CNTL,
-		     (RADEON_ISYNC_ANY2D_IDLE3D |
-		      RADEON_ISYNC_ANY3D_IDLE2D |
-		      RADEON_ISYNC_WAIT_IDLEGUI |
-		      RADEON_ISYNC_CPSCRATCH_IDLEGUI));
 }
 
 /* Enable or disable PCI-E GART on the chip */
@@ -1317,6 +1332,14 @@
 
 	DRM_DEBUG("\n");
 
+	/* if we require new memory map but we don't have it fail */
+	if ((dev_priv->flags & CHIP_NEW_MEMMAP) && !dev_priv->new_memmap)
+	{
+		DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX\n");
+		radeon_do_cleanup_cp(dev);
+		return DRM_ERR(EINVAL);
+	}
+
 	if (init->is_pci && (dev_priv->flags & CHIP_IS_AGP))
 	{
 		DRM_DEBUG("Forcing AGP card to PCI mode\n");
@@ -1496,6 +1519,9 @@
 
 	dev_priv->fb_location = (RADEON_READ(RADEON_MC_FB_LOCATION)
 				 & 0xffff) << 16;
+	dev_priv->fb_size = 
+		((RADEON_READ(RADEON_MC_FB_LOCATION) & 0xffff0000u) + 0x10000)
+		- dev_priv->fb_location;
 
 	dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) |
 					((dev_priv->front_offset
@@ -1510,8 +1536,46 @@
 					  + dev_priv->fb_location) >> 10));
 
 	dev_priv->gart_size = init->gart_size;
-	dev_priv->gart_vm_start = dev_priv->fb_location
-	    + RADEON_READ(RADEON_CONFIG_APER_SIZE);
+
+	/* New let's set the memory map ... */
+	if (dev_priv->new_memmap) {
+		u32 base = 0;
+
+		DRM_INFO("Setting GART location based on new memory map\n");
+
+		/* If using AGP, try to locate the AGP aperture at the same
+		 * location in the card and on the bus, though we have to
+		 * align it down.
+		 */
+#if __OS_HAS_AGP
+		if (dev_priv->flags & CHIP_IS_AGP) {
+			base = dev->agp->base;
+			/* Check if valid */
+			if ((base + dev_priv->gart_size) > dev_priv->fb_location &&
+			    base < (dev_priv->fb_location + dev_priv->fb_size)) {
+				DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n",
+					 dev->agp->base);
+				base = 0;
+			}
+		}
+#endif
+		/* If not or if AGP is at 0 (Macs), try to put it elsewhere */
+		if (base == 0) {
+			base = dev_priv->fb_location + dev_priv->fb_size;
+			if (((base + dev_priv->gart_size) & 0xfffffffful)
+			    < base)
+				base = dev_priv->fb_location
+					- dev_priv->gart_size;
+		}		
+		dev_priv->gart_vm_start = base & 0xffc00000u;
+		if (dev_priv->gart_vm_start != base)
+			DRM_INFO("GART aligned down from 0x%08x to 0x%08x\n",
+				 base, dev_priv->gart_vm_start);
+	} else {
+		DRM_INFO("Setting GART location based on old memory map\n");
+		dev_priv->gart_vm_start = dev_priv->fb_location +
+			RADEON_READ(RADEON_CONFIG_APER_SIZE);
+	}
 
 #if __OS_HAS_AGP
 	if (dev_priv->flags & CHIP_IS_AGP)
@@ -1596,6 +1660,7 @@
 	dev_priv->last_buf = 0;
 
 	radeon_do_engine_reset(dev);
+	radeon_test_writeback(dev_priv);
 
 	return 0;
 }
diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h
index 9c177a6..c8e279e 100644
--- a/drivers/char/drm/radeon_drm.h
+++ b/drivers/char/drm/radeon_drm.h
@@ -222,6 +222,7 @@
 #	define R300_WAIT_3D  		0x2
 #	define R300_WAIT_2D_CLEAN  	0x3
 #	define R300_WAIT_3D_CLEAN  	0x4
+#define R300_CMD_SCRATCH		8
 
 typedef union {
 	unsigned int u;
@@ -247,6 +248,9 @@
 	struct {
 		unsigned char cmd_type, flags, pad0, pad1;
 	} wait;
+	struct {
+		unsigned char cmd_type, reg, n_bufs, flags;
+	} scratch;
 } drm_r300_cmd_header_t;
 
 #define RADEON_FRONT			0x1
@@ -697,6 +701,7 @@
 #define RADEON_SETPARAM_FB_LOCATION    1	/* determined framebuffer location */
 #define RADEON_SETPARAM_SWITCH_TILING  2	/* enable/disable color tiling */
 #define RADEON_SETPARAM_PCIGART_LOCATION 3	/* PCI Gart Location */
+#define RADEON_SETPARAM_NEW_MEMMAP 4		/* Use new memory map */
 
 /* 1.14: Clients can allocate/free a surface
  */
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 1f7d2ab..78345ce 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -38,7 +38,7 @@
 
 #define DRIVER_NAME		"radeon"
 #define DRIVER_DESC		"ATI Radeon"
-#define DRIVER_DATE		"20051229"
+#define DRIVER_DATE		"20060225"
 
 /* Interface history:
  *
@@ -91,9 +91,11 @@
  * 1.20- Add support for r300 texrect
  * 1.21- Add support for card type getparam
  * 1.22- Add support for texture cache flushes (R300_TX_CNTL)
+ * 1.23- Add new radeon memory map work from benh
+ * 1.24- Add general-purpose packet for manipulating scratch registers (r300)
  */
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		22
+#define DRIVER_MINOR		24
 #define DRIVER_PATCHLEVEL	0
 
 /*
@@ -101,20 +103,21 @@
  */
 enum radeon_family {
 	CHIP_R100,
-	CHIP_RS100,
 	CHIP_RV100,
+	CHIP_RS100,
 	CHIP_RV200,
-	CHIP_R200,
 	CHIP_RS200,
-	CHIP_R250,
-	CHIP_RS250,
+	CHIP_R200,
 	CHIP_RV250,
+	CHIP_RS300,
 	CHIP_RV280,
 	CHIP_R300,
-	CHIP_RS300,
 	CHIP_R350,
 	CHIP_RV350,
+	CHIP_RV380,
 	CHIP_R420,
+	CHIP_RV410,
+	CHIP_RS400,
 	CHIP_LAST,
 };
 
@@ -136,9 +139,11 @@
 	CHIP_IS_AGP = 0x00080000UL,
 	CHIP_HAS_HIERZ = 0x00100000UL,
 	CHIP_IS_PCIE = 0x00200000UL,
+	CHIP_NEW_MEMMAP = 0x00400000UL,
 };
 
-#define GET_RING_HEAD(dev_priv)		DRM_READ32(  (dev_priv)->ring_rptr, 0 )
+#define GET_RING_HEAD(dev_priv)	(dev_priv->writeback_works ? \
+        DRM_READ32(  (dev_priv)->ring_rptr, 0 ) : RADEON_READ(RADEON_CP_RB_RPTR))
 #define SET_RING_HEAD(dev_priv,val)	DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) )
 
 typedef struct drm_radeon_freelist {
@@ -199,6 +204,8 @@
 	drm_radeon_sarea_t *sarea_priv;
 
 	u32 fb_location;
+	u32 fb_size;
+	int new_memmap;
 
 	int gart_size;
 	u32 gart_vm_start;
@@ -272,6 +279,8 @@
 	unsigned long pcigart_offset;
 	drm_ati_pcigart_info gart_info;
 
+	u32 scratch_ages[5];
+
 	/* starting from here on, data is preserved accross an open */
 	uint32_t flags;		/* see radeon_chip_flags */
 } drm_radeon_private_t;
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index 7bc2751..c5b8f77 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -45,22 +45,53 @@
 	u32 off = *offset;
 	struct drm_radeon_driver_file_fields *radeon_priv;
 
-	if (off >= dev_priv->fb_location &&
-	    off < (dev_priv->gart_vm_start + dev_priv->gart_size))
+	/* Hrm ... the story of the offset ... So this function converts
+	 * the various ideas of what userland clients might have for an
+	 * offset in the card address space into an offset into the card
+	 * address space :) So with a sane client, it should just keep
+	 * the value intact and just do some boundary checking. However,
+	 * not all clients are sane. Some older clients pass us 0 based
+	 * offsets relative to the start of the framebuffer and some may
+	 * assume the AGP aperture it appended to the framebuffer, so we
+	 * try to detect those cases and fix them up.
+	 *
+	 * Note: It might be a good idea here to make sure the offset lands
+	 * in some "allowed" area to protect things like the PCIE GART...
+	 */
+
+	/* First, the best case, the offset already lands in either the
+	 * framebuffer or the GART mapped space
+	 */
+	if ((off >= dev_priv->fb_location &&
+	     off < (dev_priv->fb_location + dev_priv->fb_size)) ||
+	    (off >= dev_priv->gart_vm_start &&
+	     off < (dev_priv->gart_vm_start + dev_priv->gart_size)))
 		return 0;
 
-	radeon_priv = filp_priv->driver_priv;
-	off += radeon_priv->radeon_fb_delta;
+	/* Ok, that didn't happen... now check if we have a zero based
+	 * offset that fits in the framebuffer + gart space, apply the
+	 * magic offset we get from SETPARAM or calculated from fb_location
+	 */
+	if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
+		radeon_priv = filp_priv->driver_priv;
+		off += radeon_priv->radeon_fb_delta;
+	}
 
-	DRM_DEBUG("offset fixed up to 0x%x\n", off);
+	/* Finally, assume we aimed at a GART offset if beyond the fb */
+	if (off > (dev_priv->fb_location + dev_priv->fb_size))
+		off = off - (dev_priv->fb_location + dev_priv->fb_size) +
+			dev_priv->gart_vm_start;
 
-	if (off < dev_priv->fb_location ||
-	    off >= (dev_priv->gart_vm_start + dev_priv->gart_size))
-		return DRM_ERR(EINVAL);
-
-	*offset = off;
-
-	return 0;
+	/* Now recheck and fail if out of bounds */
+	if ((off >= dev_priv->fb_location &&
+	     off < (dev_priv->fb_location + dev_priv->fb_size)) ||
+	    (off >= dev_priv->gart_vm_start &&
+	     off < (dev_priv->gart_vm_start + dev_priv->gart_size))) {
+		DRM_DEBUG("offset fixed up to 0x%x\n", off);
+		*offset = off;
+		return 0;
+	}
+	return DRM_ERR(EINVAL);
 }
 
 static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
@@ -1939,11 +1970,6 @@
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_surface_alloc_t alloc;
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_COPY_FROM_USER_IOCTL(alloc,
 				 (drm_radeon_surface_alloc_t __user *) data,
 				 sizeof(alloc));
@@ -1960,12 +1986,7 @@
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_surface_free_t memfree;
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
-	DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_mem_free_t __user *) data,
+	DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_surface_free_t __user *) data,
 				 sizeof(memfree));
 
 	if (free_surface(filp, dev_priv, memfree.address))
@@ -2100,11 +2121,6 @@
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 	DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data,
@@ -2189,11 +2205,6 @@
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 	DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data,
@@ -2340,11 +2351,6 @@
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_COPY_FROM_USER_IOCTL(indirect,
 				 (drm_radeon_indirect_t __user *) data,
 				 sizeof(indirect));
@@ -2417,11 +2423,6 @@
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 	DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data,
@@ -2738,11 +2739,6 @@
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 	DRM_COPY_FROM_USER_IOCTL(cmdbuf,
@@ -2897,11 +2893,6 @@
 	drm_radeon_getparam_t param;
 	int value;
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data,
 				 sizeof(param));
 
@@ -2981,11 +2972,6 @@
 	drm_radeon_setparam_t sp;
 	struct drm_radeon_driver_file_fields *radeon_priv;
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 	DRM_COPY_FROM_USER_IOCTL(sp, (drm_radeon_setparam_t __user *) data,
@@ -3012,6 +2998,9 @@
 	case RADEON_SETPARAM_PCIGART_LOCATION:
 		dev_priv->pcigart_offset = sp.value;
 		break;
+	case RADEON_SETPARAM_NEW_MEMMAP:
+		dev_priv->new_memmap = sp.value;
+		break;
 	default:
 		DRM_DEBUG("Invalid parameter %d\n", sp.param);
 		return DRM_ERR(EINVAL);
diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c
index 6774d2f..5e9936b 100644
--- a/drivers/char/drm/sis_mm.c
+++ b/drivers/char/drm/sis_mm.c
@@ -110,7 +110,7 @@
 
 	DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
 
-	DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset);
+	DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset);
 
 	return retval;
 }
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 765c5c1..9cad850 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -486,8 +486,7 @@
 		} /* End channel is open more than once */
 
 		/* Port open only once go ahead with shutdown & reset */
-		if (ch->count < 0)
-			BUG();
+		BUG_ON(ch->count < 0);
 
 		/* ---------------------------------------------------------------
 			Let the rest of the driver know the channel is being closed.
diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c
index b2e0928..093fdf9 100644
--- a/drivers/char/ftape/lowlevel/fdc-io.c
+++ b/drivers/char/ftape/lowlevel/fdc-io.c
@@ -607,7 +607,7 @@
 
 	fdc_mode = fdc_idle;
 
-	/*  maybe the cli()/sti() pair is not necessary, BUT:
+	/*  maybe the spin_lock_irq* pair is not necessary, BUT:
 	 *  the following line MUST be here. Otherwise fdc_interrupt_wait()
 	 *  won't wait. Note that fdc_reset() is called from 
 	 *  ftape_dumb_stop() when the fdc is busy transferring data. In this
diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
index 1b5e01e..43ff598 100644
--- a/drivers/char/generic_nvram.c
+++ b/drivers/char/generic_nvram.c
@@ -22,6 +22,9 @@
 #include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/nvram.h>
+#ifdef CONFIG_PPC_PMAC
+#include <asm/machdep.h>
+#endif
 
 #define NVRAM_SIZE	8192
 
@@ -92,7 +95,7 @@
 	case IOC_NVRAM_GET_OFFSET: {
 		int part, offset;
 
-		if (_machine != _MACH_Pmac)
+		if (!machine_is(powermac))
 			return -EINVAL;
 		if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0)
 			return -EFAULT;
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index f65b2e1..2b6a56b 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -39,8 +39,10 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/delay.h>
+
 #include <asm/uaccess.h>
-#include <asm/hvconsole.h>
+
+#include "hvc_console.h"
 
 #define HVC_MAJOR	229
 #define HVC_MINOR	0
@@ -54,17 +56,14 @@
 #define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */
 
 /*
- * The Linux TTY code does not support dynamic addition of tty derived devices
- * so we need to know how many tty devices we might need when space is allocated
- * for the tty device.  Since this driver supports hotplug of vty adapters we
- * need to make sure we have enough allocated.
+ * These sizes are most efficient for vio, because they are the
+ * native transfer size. We could make them selectable in the
+ * future to better deal with backends that want other buffer sizes.
  */
-#define HVC_ALLOC_TTY_ADAPTERS	8
-
 #define N_OUTBUF	16
 #define N_INBUF		16
 
-#define __ALIGNED__	__attribute__((__aligned__(8)))
+#define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
 
 static struct tty_driver *hvc_driver;
 static struct task_struct *hvc_task;
@@ -154,7 +153,7 @@
 
 void hvc_console_print(struct console *co, const char *b, unsigned count)
 {
-	char c[16] __ALIGNED__;
+	char c[N_OUTBUF] __ALIGNED__;
 	unsigned i = 0, n = 0;
 	int r, donecr = 0, index = co->index;
 
@@ -473,8 +472,10 @@
 
 	n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf);
 	if (n <= 0) {
-		if (n == 0)
+		if (n == 0) {
+			hp->do_wakeup = 1;
 			return;
+		}
 		/* throw away output on error; this happens when
 		   there is no session connected to the vterm. */
 		hp->n_outbuf = 0;
@@ -486,12 +487,19 @@
 		hp->do_wakeup = 1;
 }
 
-static inline int __hvc_write_kernel(struct hvc_struct *hp,
-				   const unsigned char *buf, int count)
+static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
+	struct hvc_struct *hp = tty->driver_data;
 	unsigned long flags;
 	int rsize, written = 0;
 
+	/* This write was probably executed during a tty close. */
+	if (!hp)
+		return -EPIPE;
+
+	if (hp->count <= 0)
+		return -EIO;
+
 	spin_lock_irqsave(&hp->lock, flags);
 
 	/* Push pending writes */
@@ -510,26 +518,8 @@
 	}
 	spin_unlock_irqrestore(&hp->lock, flags);
 
-	return written;
-}
-static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
-	struct hvc_struct *hp = tty->driver_data;
-	int written;
-
-	/* This write was probably executed during a tty close. */
-	if (!hp)
-		return -EPIPE;
-
-	if (hp->count <= 0)
-		return -EIO;
-
-	written = __hvc_write_kernel(hp, buf, count);
-
 	/*
 	 * Racy, but harmless, kick thread if there is still pending data.
-	 * There really is nothing wrong with kicking the thread, even if there
-	 * is no buffered data.
 	 */
 	if (hp->n_outbuf)
 		hvc_kick();
@@ -614,6 +604,13 @@
 				spin_unlock_irqrestore(&hp->lock, flags);
 				tty_hangup(tty);
 				spin_lock_irqsave(&hp->lock, flags);
+			} else if ( n == -EAGAIN ) {
+				/*
+				 * Some back-ends can only ensure a certain min
+				 * num of bytes read, which may be > 'count'.
+				 * Let the tty clear the flip buff to make room.
+				 */
+				poll_mask |= HVC_POLL_READ;
 			}
 			break;
 		}
@@ -635,16 +632,7 @@
 			tty_insert_flip_char(tty, buf[i], 0);
 		}
 
-		/*
-		 * Account for the total amount read in one loop, and if above
-		 * 64 bytes, we do a quick schedule loop to let the tty grok
-		 * the data and eventually throttle us.
-		 */
 		read_total += n;
-		if (read_total >= 64) {
-			poll_mask |= HVC_POLL_QUICK;
-			break;
-		}
 	}
  throttled:
 	/* Wakeup write queue if necessary */
@@ -767,7 +755,8 @@
 	 * see if this vterm id matches one registered for console.
 	 */
 	for (i=0; i < MAX_NR_HVC_CONSOLES; i++)
-		if (vtermnos[i] == hp->vtermno)
+		if (vtermnos[i] == hp->vtermno &&
+		    cons_ops[i] == hp->ops)
 			break;
 
 	/* no matching slot, just use a counter */
@@ -823,34 +812,38 @@
  * interfaces start to become available. */
 int __init hvc_init(void)
 {
+	struct tty_driver *drv;
+
 	/* We need more than hvc_count adapters due to hotplug additions. */
-	hvc_driver = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS);
-	if (!hvc_driver)
+	drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS);
+	if (!drv)
 		return -ENOMEM;
 
-	hvc_driver->owner = THIS_MODULE;
-	hvc_driver->devfs_name = "hvc/";
-	hvc_driver->driver_name = "hvc";
-	hvc_driver->name = "hvc";
-	hvc_driver->major = HVC_MAJOR;
-	hvc_driver->minor_start = HVC_MINOR;
-	hvc_driver->type = TTY_DRIVER_TYPE_SYSTEM;
-	hvc_driver->init_termios = tty_std_termios;
-	hvc_driver->flags = TTY_DRIVER_REAL_RAW;
-	tty_set_operations(hvc_driver, &hvc_ops);
+	drv->owner = THIS_MODULE;
+	drv->devfs_name = "hvc/";
+	drv->driver_name = "hvc";
+	drv->name = "hvc";
+	drv->major = HVC_MAJOR;
+	drv->minor_start = HVC_MINOR;
+	drv->type = TTY_DRIVER_TYPE_SYSTEM;
+	drv->init_termios = tty_std_termios;
+	drv->flags = TTY_DRIVER_REAL_RAW;
+	tty_set_operations(drv, &hvc_ops);
 
 	/* Always start the kthread because there can be hotplug vty adapters
 	 * added later. */
 	hvc_task = kthread_run(khvcd, NULL, "khvcd");
 	if (IS_ERR(hvc_task)) {
 		panic("Couldn't create kthread for console.\n");
-		put_tty_driver(hvc_driver);
+		put_tty_driver(drv);
 		return -EIO;
 	}
 
-	if (tty_register_driver(hvc_driver))
+	if (tty_register_driver(drv))
 		panic("Couldn't register hvc console driver\n");
 
+	mb();
+	hvc_driver = drv;
 	return 0;
 }
 module_init(hvc_init);
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h
new file mode 100644
index 0000000..96b7401
--- /dev/null
+++ b/drivers/char/hvc_console.h
@@ -0,0 +1,63 @@
+/*
+ * hvc_console.h
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author(s):
+ * 	Ryan S. Arnold <rsa@us.ibm.com>
+ *
+ * hvc_console header information:
+ *      moved here from include/asm-powerpc/hvconsole.h
+ *      and drivers/char/hvc_console.c
+ *
+ * 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 HVC_CONSOLE_H
+#define HVC_CONSOLE_H
+
+/*
+ * This is the max number of console adapters that can/will be found as
+ * console devices on first stage console init.  Any number beyond this range
+ * can't be used as a console device but is still a valid tty device.
+ */
+#define MAX_NR_HVC_CONSOLES	16
+
+/*
+ * The Linux TTY code does not support dynamic addition of tty derived devices
+ * so we need to know how many tty devices we might need when space is allocated
+ * for the tty device.  Since this driver supports hotplug of vty adapters we
+ * need to make sure we have enough allocated.
+ */
+#define HVC_ALLOC_TTY_ADAPTERS	8
+
+
+/* implemented by a low level driver */
+struct hv_ops {
+	int (*get_chars)(uint32_t vtermno, char *buf, int count);
+	int (*put_chars)(uint32_t vtermno, const char *buf, int count);
+};
+
+struct hvc_struct;
+
+/* Register a vterm and a slot index for use as a console (console_init) */
+extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops);
+
+/* register a vterm for hvc tty operation (module_init or hotplug add) */
+extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq,
+						 struct hv_ops *ops);
+/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */
+extern int __devexit hvc_remove(struct hvc_struct *hp);
+
+#endif // HVC_CONSOLE_H
diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c
new file mode 100644
index 0000000..83364ea
--- /dev/null
+++ b/drivers/char/hvc_rtas.c
@@ -0,0 +1,138 @@
+/*
+ * IBM RTAS driver interface to hvc_console.c
+ *
+ * (C) Copyright IBM Corporation 2001-2005
+ * (C) Copyright Red Hat, Inc. 2005
+ *
+ * Author(s): Maximino Augilar <IBM STI Design Center>
+ *	    : Ryan S. Arnold <rsa@us.ibm.com>
+ *	    : Utz Bacher <utz.bacher@de.ibm.com>
+ *	    : David Woodhouse <dwmw2@infradead.org>
+ *
+ *    inspired by drivers/char/hvc_console.c
+ *    written by Anton Blanchard and Paul Mackerras
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+
+#include <asm/irq.h>
+#include <asm/rtas.h>
+#include "hvc_console.h"
+
+#define hvc_rtas_cookie 0x67781e15
+struct hvc_struct *hvc_rtas_dev;
+
+#define RTASCONS_PUT_ATTEMPTS  16
+
+static int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE;
+static int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE;
+static int rtascons_put_delay = 100;
+module_param_named(put_delay, rtascons_put_delay, int, 0644);
+
+static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf, int count)
+{
+	int done;
+
+	/* if there is more than one character to be displayed, wait a bit */
+	for (done = 0; done < count; done++) {
+		int result;
+		result = rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[done]);
+		if (result)
+			break;
+	}
+	/* the calling routine expects to receive the number of bytes sent */
+	return done;
+}
+
+static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		int c, err;
+
+		err = rtas_call(rtascons_get_char_token, 0, 2, &c);
+		if (err)
+			break;
+
+		buf[i] = c;
+	}
+
+	return i;
+}
+
+static struct hv_ops hvc_rtas_get_put_ops = {
+	.get_chars = hvc_rtas_read_console,
+	.put_chars = hvc_rtas_write_console,
+};
+
+static int hvc_rtas_init(void)
+{
+	struct hvc_struct *hp;
+
+	if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
+		rtascons_put_char_token = rtas_token("put-term-char");
+	if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
+		return -EIO;
+
+	if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE)
+		rtascons_get_char_token = rtas_token("get-term-char");
+	if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE)
+		return -EIO;
+
+	BUG_ON(hvc_rtas_dev);
+
+	/* Allocate an hvc_struct for the console device we instantiated
+	 * earlier.  Save off hp so that we can return it on exit */
+	hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops);
+	if (IS_ERR(hp))
+		return PTR_ERR(hp);
+	hvc_rtas_dev = hp;
+	return 0;
+}
+module_init(hvc_rtas_init);
+
+/* This will tear down the tty portion of the driver */
+static void __exit hvc_rtas_exit(void)
+{
+	/* Really the fun isn't over until the worker thread breaks down and the
+	 * tty cleans up */
+	if (hvc_rtas_dev)
+		hvc_remove(hvc_rtas_dev);
+}
+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)
+{
+	rtascons_put_char_token = rtas_token("put-term-char");
+	if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
+		return -EIO;
+	rtascons_get_char_token = rtas_token("get-term-char");
+	if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE)
+		return -EIO;
+
+	hvc_instantiate(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops );
+	add_preferred_console("hvc", 0, NULL);
+	return 0;
+}
+console_initcall(hvc_rtas_console_init);
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index f5212eb..9add81ce 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -31,10 +31,13 @@
 
 #include <linux/types.h>
 #include <linux/init.h>
+
 #include <asm/hvconsole.h>
 #include <asm/vio.h>
 #include <asm/prom.h>
 
+#include "hvc_console.h"
+
 char hvc_driver_name[] = "hvc_console";
 
 static struct vio_device_id hvc_driver_table[] __devinitdata = {
@@ -48,6 +51,14 @@
 	unsigned long got;
 	int i;
 
+	/*
+	 * Vio firmware will read up to SIZE_VIO_GET_CHARS at its own discretion
+	 * so we play safe and avoid the situation where got > count which could
+	 * overload the flip buffer.
+	 */
+	if (count < SIZE_VIO_GET_CHARS)
+		return -EAGAIN;
+
 	got = hvc_get_chars(vtermno, buf, count);
 
 	/*
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index f7ac318..327b00c 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -439,7 +439,6 @@
 	char buf[HVCS_BUFF_LEN] __ALIGNED__;
 	unsigned long flags;
 	int got = 0;
-	int i;
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
 
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 7c0684d..e1c9537 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -42,7 +42,7 @@
 #include <linux/slab.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/ipmi.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/compat.h>
@@ -55,7 +55,7 @@
 	struct file          *file;
 	struct fasync_struct *fasync_queue;
 	wait_queue_head_t    wait;
-	struct semaphore     recv_sem;
+	struct mutex	     recv_mutex;
 	int                  default_retries;
 	unsigned int         default_retry_time_ms;
 };
@@ -90,7 +90,7 @@
 
 	spin_lock_irqsave(&priv->recv_msg_lock, flags);
 
-	if (! list_empty(&(priv->recv_msgs)))
+	if (!list_empty(&(priv->recv_msgs)))
 		mask |= (POLLIN | POLLRDNORM);
 
 	spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
@@ -141,7 +141,7 @@
 	INIT_LIST_HEAD(&(priv->recv_msgs));
 	init_waitqueue_head(&priv->wait);
 	priv->fasync_queue = NULL;
-	sema_init(&(priv->recv_sem), 1);
+	mutex_init(&priv->recv_mutex);
 
 	/* Use the low-level defaults. */
 	priv->default_retries = -1;
@@ -285,15 +285,15 @@
 			break;
 		}
 
-		/* We claim a semaphore because we don't want two
+		/* We claim a mutex because we don't want two
                    users getting something from the queue at a time.
                    Since we have to release the spinlock before we can
                    copy the data to the user, it's possible another
                    user will grab something from the queue, too.  Then
                    the messages might get out of order if something
                    fails and the message gets put back onto the
-                   queue.  This semaphore prevents that problem. */
-		down(&(priv->recv_sem));
+                   queue.  This mutex prevents that problem. */
+		mutex_lock(&priv->recv_mutex);
 
 		/* Grab the message off the list. */
 		spin_lock_irqsave(&(priv->recv_msg_lock), flags);
@@ -352,7 +352,7 @@
 			goto recv_putback_on_err;
 		}
 
-		up(&(priv->recv_sem));
+		mutex_unlock(&priv->recv_mutex);
 		ipmi_free_recv_msg(msg);
 		break;
 
@@ -362,11 +362,11 @@
 		spin_lock_irqsave(&(priv->recv_msg_lock), flags);
 		list_add(entry, &(priv->recv_msgs));
 		spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
-		up(&(priv->recv_sem));
+		mutex_unlock(&priv->recv_mutex);
 		break;
 
 	recv_err:
-		up(&(priv->recv_sem));
+		mutex_unlock(&priv->recv_mutex);
 		break;
 	}
 
@@ -789,21 +789,53 @@
 		 " interface.  Other values will set the major device number"
 		 " to that value.");
 
+/* Keep track of the devices that are registered. */
+struct ipmi_reg_list {
+	dev_t            dev;
+	struct list_head link;
+};
+static LIST_HEAD(reg_list);
+static DEFINE_MUTEX(reg_list_mutex);
+
 static struct class *ipmi_class;
 
-static void ipmi_new_smi(int if_num)
+static void ipmi_new_smi(int if_num, struct device *device)
 {
 	dev_t dev = MKDEV(ipmi_major, if_num);
+	struct ipmi_reg_list *entry;
 
 	devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
 		      "ipmidev/%d", if_num);
 
-	class_device_create(ipmi_class, NULL, dev, NULL, "ipmi%d", if_num);
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry) {
+		printk(KERN_ERR "ipmi_devintf: Unable to create the"
+		       " ipmi class device link\n");
+		return;
+	}
+	entry->dev = dev;
+
+	mutex_lock(&reg_list_mutex);
+	class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num);
+	list_add(&entry->link, &reg_list);
+	mutex_unlock(&reg_list_mutex);
 }
 
 static void ipmi_smi_gone(int if_num)
 {
-	class_device_destroy(ipmi_class, MKDEV(ipmi_major, if_num));
+	dev_t dev = MKDEV(ipmi_major, if_num);
+	struct ipmi_reg_list *entry;
+
+	mutex_lock(&reg_list_mutex);
+	list_for_each_entry(entry, &reg_list, link) {
+		if (entry->dev == dev) {
+			list_del(&entry->link);
+			kfree(entry);
+			break;
+		}
+	}
+	class_device_destroy(ipmi_class, dev);
+	mutex_unlock(&reg_list_mutex);
 	devfs_remove("ipmidev/%d", if_num);
 }
 
@@ -856,6 +888,14 @@
 
 static __exit void cleanup_ipmi(void)
 {
+	struct ipmi_reg_list *entry, *entry2;
+	mutex_lock(&reg_list_mutex);
+	list_for_each_entry_safe(entry, entry2, &reg_list, link) {
+		list_del(&entry->link);
+		class_device_destroy(ipmi_class, entry->dev);
+		kfree(entry);
+	}
+	mutex_unlock(&reg_list_mutex);
 	class_destroy(ipmi_class);
 	ipmi_smi_watcher_unregister(&smi_watcher);
 	devfs_remove(DEVICE_NAME);
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
index da15541..2062675 100644
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -227,7 +227,7 @@
 static inline int check_obf(struct si_sm_data *kcs, unsigned char status,
 			    long time)
 {
-	if (! GET_STATUS_OBF(status)) {
+	if (!GET_STATUS_OBF(status)) {
 		kcs->obf_timeout -= time;
 		if (kcs->obf_timeout < 0) {
 		    start_error_recovery(kcs, "OBF not ready in time");
@@ -407,7 +407,7 @@
 		}
 
 		if (state == KCS_READ_STATE) {
-			if (! check_obf(kcs, status, time))
+			if (!check_obf(kcs, status, time))
 				return SI_SM_CALL_WITH_DELAY;
 			read_next_byte(kcs);
 		} else {
@@ -447,7 +447,7 @@
 					     "Not in read state for error2");
 			break;
 		}
-		if (! check_obf(kcs, status, time))
+		if (!check_obf(kcs, status, time))
 			return SI_SM_CALL_WITH_DELAY;
 
 		clear_obf(kcs, status);
@@ -462,7 +462,7 @@
 			break;
 		}
 
-		if (! check_obf(kcs, status, time))
+		if (!check_obf(kcs, status, time))
 			return SI_SM_CALL_WITH_DELAY;
 
 		clear_obf(kcs, status);
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index abd4c51..0ded046 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -38,6 +38,7 @@
 #include <linux/sched.h>
 #include <linux/poll.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/ipmi.h>
 #include <linux/ipmi_smi.h>
@@ -48,7 +49,7 @@
 
 #define PFX "IPMI message handler: "
 
-#define IPMI_DRIVER_VERSION "38.0"
+#define IPMI_DRIVER_VERSION "39.0"
 
 static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
 static int ipmi_init_msghandler(void);
@@ -162,6 +163,28 @@
 };
 #endif
 
+struct bmc_device
+{
+	struct platform_device *dev;
+	struct ipmi_device_id  id;
+	unsigned char          guid[16];
+	int                    guid_set;
+
+	struct kref	       refcount;
+
+	/* bmc device attributes */
+	struct device_attribute device_id_attr;
+	struct device_attribute provides_dev_sdrs_attr;
+	struct device_attribute revision_attr;
+	struct device_attribute firmware_rev_attr;
+	struct device_attribute version_attr;
+	struct device_attribute add_dev_support_attr;
+	struct device_attribute manufacturer_id_attr;
+	struct device_attribute product_id_attr;
+	struct device_attribute guid_attr;
+	struct device_attribute aux_firmware_rev_attr;
+};
+
 #define IPMI_IPMB_NUM_SEQ	64
 #define IPMI_MAX_CHANNELS       16
 struct ipmi_smi
@@ -178,9 +201,8 @@
 	/* Used for wake ups at startup. */
 	wait_queue_head_t waitq;
 
-	/* The IPMI version of the BMC on the other end. */
-	unsigned char       version_major;
-	unsigned char       version_minor;
+	struct bmc_device *bmc;
+	char *my_dev_name;
 
 	/* This is the lower-layer's sender routine. */
 	struct ipmi_smi_handlers *handlers;
@@ -194,6 +216,9 @@
 	struct ipmi_proc_entry *proc_entries;
 #endif
 
+	/* Driver-model device for the system interface. */
+	struct device          *si_dev;
+
 	/* A table of sequence numbers for this interface.  We use the
            sequence numbers for IPMB messages that go out of the
            interface to match them up with their responses.  A routine
@@ -210,7 +235,7 @@
 
 	/* The list of command receivers that are registered for commands
 	   on this interface. */
-	struct semaphore cmd_rcvrs_lock;
+	struct mutex     cmd_rcvrs_mutex;
 	struct list_head cmd_rcvrs;
 
 	/* Events that were queues because no one was there to receive
@@ -312,6 +337,7 @@
 	/* Events that were received with the proper format. */
 	unsigned int events;
 };
+#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
 
 /* Used to mark an interface entry that cannot be used but is not a
  * free entry, either, primarily used at creation and deletion time so
@@ -320,6 +346,15 @@
 #define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \
 				   || (i == IPMI_INVALID_INTERFACE_ENTRY))
 
+/**
+ * The driver model view of the IPMI messaging driver.
+ */
+static struct device_driver ipmidriver = {
+	.name = "ipmi",
+	.bus = &platform_bus_type
+};
+static DEFINE_MUTEX(ipmidriver_mutex);
+
 #define MAX_IPMI_INTERFACES 4
 static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];
 
@@ -353,10 +388,10 @@
 
 	/* Wholesale remove all the entries from the list in the
 	 * interface and wait for RCU to know that none are in use. */
-	down(&intf->cmd_rcvrs_lock);
+	mutex_lock(&intf->cmd_rcvrs_mutex);
 	list_add_rcu(&list, &intf->cmd_rcvrs);
 	list_del_rcu(&intf->cmd_rcvrs);
-	up(&intf->cmd_rcvrs_lock);
+	mutex_unlock(&intf->cmd_rcvrs_mutex);
 	synchronize_rcu();
 
 	list_for_each_entry_safe(rcvr, rcvr2, &list, link)
@@ -393,7 +428,7 @@
 		if (IPMI_INVALID_INTERFACE(intf))
 			continue;
 		spin_unlock_irqrestore(&interfaces_lock, flags);
-		watcher->new_smi(i);
+		watcher->new_smi(i, intf->si_dev);
 		spin_lock_irqsave(&interfaces_lock, flags);
 	}
 	spin_unlock_irqrestore(&interfaces_lock, flags);
@@ -409,14 +444,14 @@
 }
 
 static void
-call_smi_watchers(int i)
+call_smi_watchers(int i, struct device *dev)
 {
 	struct ipmi_smi_watcher *w;
 
 	down_read(&smi_watchers_sem);
 	list_for_each_entry(w, &smi_watchers, link) {
 		if (try_module_get(w->owner)) {
-			w->new_smi(i);
+			w->new_smi(i, dev);
 			module_put(w->owner);
 		}
 	}
@@ -523,7 +558,7 @@
 
 static void deliver_response(struct ipmi_recv_msg *msg)
 {
-	if (! msg->user) {
+	if (!msg->user) {
 		ipmi_smi_t    intf = msg->user_msg_data;
 		unsigned long flags;
 
@@ -564,11 +599,11 @@
 	     (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
 	     i = (i+1)%IPMI_IPMB_NUM_SEQ)
 	{
-		if (! intf->seq_table[i].inuse)
+		if (!intf->seq_table[i].inuse)
 			break;
 	}
 
-	if (! intf->seq_table[i].inuse) {
+	if (!intf->seq_table[i].inuse) {
 		intf->seq_table[i].recv_msg = recv_msg;
 
 		/* Start with the maximum timeout, when the send response
@@ -729,7 +764,7 @@
 	}
 
 	new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
-	if (! new_user)
+	if (!new_user)
 		return -ENOMEM;
 
 	spin_lock_irqsave(&interfaces_lock, flags);
@@ -785,14 +820,13 @@
 
 int ipmi_destroy_user(ipmi_user_t user)
 {
-	int              rv = -ENODEV;
 	ipmi_smi_t       intf = user->intf;
 	int              i;
 	unsigned long    flags;
 	struct cmd_rcvr  *rcvr;
 	struct cmd_rcvr  *rcvrs = NULL;
 
-	user->valid = 1;
+	user->valid = 0;
 
 	/* Remove the user from the interface's sequence table. */
 	spin_lock_irqsave(&intf->seq_lock, flags);
@@ -813,7 +847,7 @@
 	 * since other things may be using it till we do
 	 * synchronize_rcu()) then free everything in that list.
 	 */
-	down(&intf->cmd_rcvrs_lock);
+	mutex_lock(&intf->cmd_rcvrs_mutex);
 	list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
 		if (rcvr->user == user) {
 			list_del_rcu(&rcvr->link);
@@ -821,7 +855,7 @@
 			rcvrs = rcvr;
 		}
 	}
-	up(&intf->cmd_rcvrs_lock);
+	mutex_unlock(&intf->cmd_rcvrs_mutex);
 	synchronize_rcu();
 	while (rcvrs) {
 		rcvr = rcvrs;
@@ -837,15 +871,15 @@
 
 	kref_put(&user->refcount, free_user);
 
-	return rv;
+	return 0;
 }
 
 void ipmi_get_version(ipmi_user_t   user,
 		      unsigned char *major,
 		      unsigned char *minor)
 {
-	*major = user->intf->version_major;
-	*minor = user->intf->version_minor;
+	*major = ipmi_version_major(&user->intf->bmc->id);
+	*minor = ipmi_version_minor(&user->intf->bmc->id);
 }
 
 int ipmi_set_my_address(ipmi_user_t   user,
@@ -902,7 +936,8 @@
 
 	if (val) {
 		/* Deliver any queued events. */
-		list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) {
+		list_for_each_entry_safe(msg, msg2, &intf->waiting_events,
+					 link) {
 			list_del(&msg->link);
 			list_add_tail(&msg->link, &msgs);
 		}
@@ -944,13 +979,13 @@
 
 
 	rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
-	if (! rcvr)
+	if (!rcvr)
 		return -ENOMEM;
 	rcvr->cmd = cmd;
 	rcvr->netfn = netfn;
 	rcvr->user = user;
 
-	down(&intf->cmd_rcvrs_lock);
+	mutex_lock(&intf->cmd_rcvrs_mutex);
 	/* Make sure the command/netfn is not already registered. */
 	entry = find_cmd_rcvr(intf, netfn, cmd);
 	if (entry) {
@@ -961,7 +996,7 @@
 	list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
 
  out_unlock:
-	up(&intf->cmd_rcvrs_lock);
+	mutex_unlock(&intf->cmd_rcvrs_mutex);
 	if (rv)
 		kfree(rcvr);
 
@@ -975,17 +1010,17 @@
 	ipmi_smi_t      intf = user->intf;
 	struct cmd_rcvr *rcvr;
 
-	down(&intf->cmd_rcvrs_lock);
+	mutex_lock(&intf->cmd_rcvrs_mutex);
 	/* Make sure the command/netfn is not already registered. */
 	rcvr = find_cmd_rcvr(intf, netfn, cmd);
 	if ((rcvr) && (rcvr->user == user)) {
 		list_del_rcu(&rcvr->link);
-		up(&intf->cmd_rcvrs_lock);
+		mutex_unlock(&intf->cmd_rcvrs_mutex);
 		synchronize_rcu();
 		kfree(rcvr);
 		return 0;
 	} else {
-		up(&intf->cmd_rcvrs_lock);
+		mutex_unlock(&intf->cmd_rcvrs_mutex);
 		return -ENOENT;
 	}
 }
@@ -1480,7 +1515,7 @@
 	unsigned char saddr, lun;
 	int           rv;
 
-	if (! user)
+	if (!user)
 		return -EINVAL;
 	rv = check_addr(user->intf, addr, &saddr, &lun);
 	if (rv)
@@ -1511,7 +1546,7 @@
 	unsigned char saddr, lun;
 	int           rv;
 
-	if (! user)
+	if (!user)
 		return -EINVAL;
 	rv = check_addr(user->intf, addr, &saddr, &lun);
 	if (rv)
@@ -1536,7 +1571,7 @@
 	char       *out = (char *) page;
 	ipmi_smi_t intf = data;
 	int        i;
-	int        rv= 0;
+	int        rv = 0;
 
 	for (i = 0; i < IPMI_MAX_CHANNELS; i++)
 		rv += sprintf(out+rv, "%x ", intf->channels[i].address);
@@ -1553,7 +1588,8 @@
 	ipmi_smi_t intf = data;
 
 	return sprintf(out, "%d.%d\n",
-		       intf->version_major, intf->version_minor);
+		       ipmi_version_major(&intf->bmc->id),
+		       ipmi_version_minor(&intf->bmc->id));
 }
 
 static int stat_file_read_proc(char *page, char **start, off_t off,
@@ -1712,6 +1748,470 @@
 #endif /* CONFIG_PROC_FS */
 }
 
+static int __find_bmc_guid(struct device *dev, void *data)
+{
+	unsigned char *id = data;
+	struct bmc_device *bmc = dev_get_drvdata(dev);
+	return memcmp(bmc->guid, id, 16) == 0;
+}
+
+static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
+					     unsigned char *guid)
+{
+	struct device *dev;
+
+	dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
+	if (dev)
+		return dev_get_drvdata(dev);
+	else
+		return NULL;
+}
+
+struct prod_dev_id {
+	unsigned int  product_id;
+	unsigned char device_id;
+};
+
+static int __find_bmc_prod_dev_id(struct device *dev, void *data)
+{
+	struct prod_dev_id *id = data;
+	struct bmc_device *bmc = dev_get_drvdata(dev);
+
+	return (bmc->id.product_id == id->product_id
+		&& bmc->id.product_id == id->product_id
+		&& bmc->id.device_id == id->device_id);
+}
+
+static struct bmc_device *ipmi_find_bmc_prod_dev_id(
+	struct device_driver *drv,
+	unsigned char product_id, unsigned char device_id)
+{
+	struct prod_dev_id id = {
+		.product_id = product_id,
+		.device_id = device_id,
+	};
+	struct device *dev;
+
+	dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
+	if (dev)
+		return dev_get_drvdata(dev);
+	else
+		return NULL;
+}
+
+static ssize_t device_id_show(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct bmc_device *bmc = dev_get_drvdata(dev);
+
+	return snprintf(buf, 10, "%u\n", bmc->id.device_id);
+}
+
+static ssize_t provides_dev_sdrs_show(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	struct bmc_device *bmc = dev_get_drvdata(dev);
+
+	return snprintf(buf, 10, "%u\n",
+			bmc->id.device_revision && 0x80 >> 7);
+}
+
+static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct bmc_device *bmc = dev_get_drvdata(dev);
+
+	return snprintf(buf, 20, "%u\n",
+			bmc->id.device_revision && 0x0F);
+}
+
+static ssize_t firmware_rev_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct bmc_device *bmc = dev_get_drvdata(dev);
+
+	return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
+			bmc->id.firmware_revision_2);
+}
+
+static ssize_t ipmi_version_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct bmc_device *bmc = dev_get_drvdata(dev);
+
+	return snprintf(buf, 20, "%u.%u\n",
+			ipmi_version_major(&bmc->id),
+			ipmi_version_minor(&bmc->id));
+}
+
+static ssize_t add_dev_support_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct bmc_device *bmc = dev_get_drvdata(dev);
+
+	return snprintf(buf, 10, "0x%02x\n",
+			bmc->id.additional_device_support);
+}
+
+static ssize_t manufacturer_id_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct bmc_device *bmc = dev_get_drvdata(dev);
+
+	return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
+}
+
+static ssize_t product_id_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	struct bmc_device *bmc = dev_get_drvdata(dev);
+
+	return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
+}
+
+static ssize_t aux_firmware_rev_show(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct bmc_device *bmc = dev_get_drvdata(dev);
+
+	return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
+			bmc->id.aux_firmware_revision[3],
+			bmc->id.aux_firmware_revision[2],
+			bmc->id.aux_firmware_revision[1],
+			bmc->id.aux_firmware_revision[0]);
+}
+
+static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct bmc_device *bmc = dev_get_drvdata(dev);
+
+	return snprintf(buf, 100, "%Lx%Lx\n",
+			(long long) bmc->guid[0],
+			(long long) bmc->guid[8]);
+}
+
+static void
+cleanup_bmc_device(struct kref *ref)
+{
+	struct bmc_device *bmc;
+
+	bmc = container_of(ref, struct bmc_device, refcount);
+
+	device_remove_file(&bmc->dev->dev,
+			   &bmc->device_id_attr);
+	device_remove_file(&bmc->dev->dev,
+			   &bmc->provides_dev_sdrs_attr);
+	device_remove_file(&bmc->dev->dev,
+			   &bmc->revision_attr);
+	device_remove_file(&bmc->dev->dev,
+			   &bmc->firmware_rev_attr);
+	device_remove_file(&bmc->dev->dev,
+			   &bmc->version_attr);
+	device_remove_file(&bmc->dev->dev,
+			   &bmc->add_dev_support_attr);
+	device_remove_file(&bmc->dev->dev,
+			   &bmc->manufacturer_id_attr);
+	device_remove_file(&bmc->dev->dev,
+			   &bmc->product_id_attr);
+	if (bmc->id.aux_firmware_revision_set)
+		device_remove_file(&bmc->dev->dev,
+				   &bmc->aux_firmware_rev_attr);
+	if (bmc->guid_set)
+		device_remove_file(&bmc->dev->dev,
+				   &bmc->guid_attr);
+	platform_device_unregister(bmc->dev);
+	kfree(bmc);
+}
+
+static void ipmi_bmc_unregister(ipmi_smi_t intf)
+{
+	struct bmc_device *bmc = intf->bmc;
+
+	sysfs_remove_link(&intf->si_dev->kobj, "bmc");
+	if (intf->my_dev_name) {
+		sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name);
+		kfree(intf->my_dev_name);
+		intf->my_dev_name = NULL;
+	}
+
+	mutex_lock(&ipmidriver_mutex);
+	kref_put(&bmc->refcount, cleanup_bmc_device);
+	mutex_unlock(&ipmidriver_mutex);
+}
+
+static int ipmi_bmc_register(ipmi_smi_t intf)
+{
+	int               rv;
+	struct bmc_device *bmc = intf->bmc;
+	struct bmc_device *old_bmc;
+	int               size;
+	char              dummy[1];
+
+	mutex_lock(&ipmidriver_mutex);
+
+	/*
+	 * Try to find if there is an bmc_device struct
+	 * representing the interfaced BMC already
+	 */
+	if (bmc->guid_set)
+		old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
+	else
+		old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
+						    bmc->id.product_id,
+						    bmc->id.device_id);
+
+	/*
+	 * If there is already an bmc_device, free the new one,
+	 * otherwise register the new BMC device
+	 */
+	if (old_bmc) {
+		kfree(bmc);
+		intf->bmc = old_bmc;
+		bmc = old_bmc;
+
+		kref_get(&bmc->refcount);
+		mutex_unlock(&ipmidriver_mutex);
+
+		printk(KERN_INFO
+		       "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
+		       " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
+		       bmc->id.manufacturer_id,
+		       bmc->id.product_id,
+		       bmc->id.device_id);
+	} else {
+		bmc->dev = platform_device_alloc("ipmi_bmc",
+						 bmc->id.device_id);
+		if (!bmc->dev) {
+			printk(KERN_ERR
+			       "ipmi_msghandler:"
+			       " Unable to allocate platform device\n");
+			return -ENOMEM;
+		}
+		bmc->dev->dev.driver = &ipmidriver;
+		dev_set_drvdata(&bmc->dev->dev, bmc);
+		kref_init(&bmc->refcount);
+
+		rv = platform_device_register(bmc->dev);
+		mutex_unlock(&ipmidriver_mutex);
+		if (rv) {
+			printk(KERN_ERR
+			       "ipmi_msghandler:"
+			       " Unable to register bmc device: %d\n",
+			       rv);
+			/* Don't go to out_err, you can only do that if
+			   the device is registered already. */
+			return rv;
+		}
+
+		bmc->device_id_attr.attr.name = "device_id";
+		bmc->device_id_attr.attr.owner = THIS_MODULE;
+		bmc->device_id_attr.attr.mode = S_IRUGO;
+		bmc->device_id_attr.show = device_id_show;
+
+		bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
+		bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE;
+		bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
+		bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
+
+
+		bmc->revision_attr.attr.name = "revision";
+		bmc->revision_attr.attr.owner = THIS_MODULE;
+		bmc->revision_attr.attr.mode = S_IRUGO;
+		bmc->revision_attr.show = revision_show;
+
+		bmc->firmware_rev_attr.attr.name = "firmware_revision";
+		bmc->firmware_rev_attr.attr.owner = THIS_MODULE;
+		bmc->firmware_rev_attr.attr.mode = S_IRUGO;
+		bmc->firmware_rev_attr.show = firmware_rev_show;
+
+		bmc->version_attr.attr.name = "ipmi_version";
+		bmc->version_attr.attr.owner = THIS_MODULE;
+		bmc->version_attr.attr.mode = S_IRUGO;
+		bmc->version_attr.show = ipmi_version_show;
+
+		bmc->add_dev_support_attr.attr.name
+			= "additional_device_support";
+		bmc->add_dev_support_attr.attr.owner = THIS_MODULE;
+		bmc->add_dev_support_attr.attr.mode = S_IRUGO;
+		bmc->add_dev_support_attr.show = add_dev_support_show;
+
+		bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
+		bmc->manufacturer_id_attr.attr.owner = THIS_MODULE;
+		bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
+		bmc->manufacturer_id_attr.show = manufacturer_id_show;
+
+		bmc->product_id_attr.attr.name = "product_id";
+		bmc->product_id_attr.attr.owner = THIS_MODULE;
+		bmc->product_id_attr.attr.mode = S_IRUGO;
+		bmc->product_id_attr.show = product_id_show;
+
+		bmc->guid_attr.attr.name = "guid";
+		bmc->guid_attr.attr.owner = THIS_MODULE;
+		bmc->guid_attr.attr.mode = S_IRUGO;
+		bmc->guid_attr.show = guid_show;
+
+		bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
+		bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE;
+		bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
+		bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
+
+		device_create_file(&bmc->dev->dev,
+				   &bmc->device_id_attr);
+		device_create_file(&bmc->dev->dev,
+				   &bmc->provides_dev_sdrs_attr);
+		device_create_file(&bmc->dev->dev,
+				   &bmc->revision_attr);
+		device_create_file(&bmc->dev->dev,
+				   &bmc->firmware_rev_attr);
+		device_create_file(&bmc->dev->dev,
+				   &bmc->version_attr);
+		device_create_file(&bmc->dev->dev,
+				   &bmc->add_dev_support_attr);
+		device_create_file(&bmc->dev->dev,
+				   &bmc->manufacturer_id_attr);
+		device_create_file(&bmc->dev->dev,
+				   &bmc->product_id_attr);
+		if (bmc->id.aux_firmware_revision_set)
+			device_create_file(&bmc->dev->dev,
+					   &bmc->aux_firmware_rev_attr);
+		if (bmc->guid_set)
+			device_create_file(&bmc->dev->dev,
+					   &bmc->guid_attr);
+
+		printk(KERN_INFO
+		       "ipmi: Found new BMC (man_id: 0x%6.6x, "
+		       " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
+		       bmc->id.manufacturer_id,
+		       bmc->id.product_id,
+		       bmc->id.device_id);
+	}
+
+	/*
+	 * create symlink from system interface device to bmc device
+	 * and back.
+	 */
+	rv = sysfs_create_link(&intf->si_dev->kobj,
+			       &bmc->dev->dev.kobj, "bmc");
+	if (rv) {
+		printk(KERN_ERR
+		       "ipmi_msghandler: Unable to create bmc symlink: %d\n",
+		       rv);
+		goto out_err;
+	}
+
+	size = snprintf(dummy, 0, "ipmi%d", intf->intf_num);
+	intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
+	if (!intf->my_dev_name) {
+		rv = -ENOMEM;
+		printk(KERN_ERR
+		       "ipmi_msghandler: allocate link from BMC: %d\n",
+		       rv);
+		goto out_err;
+	}
+	snprintf(intf->my_dev_name, size+1, "ipmi%d", intf->intf_num);
+
+	rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
+			       intf->my_dev_name);
+	if (rv) {
+		kfree(intf->my_dev_name);
+		intf->my_dev_name = NULL;
+		printk(KERN_ERR
+		       "ipmi_msghandler:"
+		       " Unable to create symlink to bmc: %d\n",
+		       rv);
+		goto out_err;
+	}
+
+	return 0;
+
+out_err:
+	ipmi_bmc_unregister(intf);
+	return rv;
+}
+
+static int
+send_guid_cmd(ipmi_smi_t intf, int chan)
+{
+	struct kernel_ipmi_msg            msg;
+	struct ipmi_system_interface_addr si;
+
+	si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	si.channel = IPMI_BMC_CHANNEL;
+	si.lun = 0;
+
+	msg.netfn = IPMI_NETFN_APP_REQUEST;
+	msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
+	msg.data = NULL;
+	msg.data_len = 0;
+	return i_ipmi_request(NULL,
+			      intf,
+			      (struct ipmi_addr *) &si,
+			      0,
+			      &msg,
+			      intf,
+			      NULL,
+			      NULL,
+			      0,
+			      intf->channels[0].address,
+			      intf->channels[0].lun,
+			      -1, 0);
+}
+
+static void
+guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
+{
+	if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+	    || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
+	    || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
+		/* Not for me */
+		return;
+
+	if (msg->msg.data[0] != 0) {
+		/* Error from getting the GUID, the BMC doesn't have one. */
+		intf->bmc->guid_set = 0;
+		goto out;
+	}
+
+	if (msg->msg.data_len < 17) {
+		intf->bmc->guid_set = 0;
+		printk(KERN_WARNING PFX
+		       "guid_handler: The GUID response from the BMC was too"
+		       " short, it was %d but should have been 17.  Assuming"
+		       " GUID is not available.\n",
+		       msg->msg.data_len);
+		goto out;
+	}
+
+	memcpy(intf->bmc->guid, msg->msg.data, 16);
+	intf->bmc->guid_set = 1;
+ out:
+	wake_up(&intf->waitq);
+}
+
+static void
+get_guid(ipmi_smi_t intf)
+{
+	int rv;
+
+	intf->bmc->guid_set = 0x2;
+	intf->null_user_handler = guid_handler;
+	rv = send_guid_cmd(intf, 0);
+	if (rv)
+		/* Send failed, no GUID available. */
+		intf->bmc->guid_set = 0;
+	wait_event(intf->waitq, intf->bmc->guid_set != 2);
+	intf->null_user_handler = NULL;
+}
+
 static int
 send_channel_info_cmd(ipmi_smi_t intf, int chan)
 {
@@ -1804,16 +2304,19 @@
 
 int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
 		      void		       *send_info,
-		      unsigned char            version_major,
-		      unsigned char            version_minor,
-		      unsigned char            slave_addr,
-		      ipmi_smi_t               *new_intf)
+		      struct ipmi_device_id    *device_id,
+		      struct device            *si_dev,
+		      unsigned char            slave_addr)
 {
 	int              i, j;
 	int              rv;
 	ipmi_smi_t       intf;
 	unsigned long    flags;
+	int              version_major;
+	int              version_minor;
 
+	version_major = ipmi_version_major(device_id);
+	version_minor = ipmi_version_minor(device_id);
 
 	/* Make sure the driver is actually initialized, this handles
 	   problems with initialization order. */
@@ -1831,10 +2334,15 @@
 	if (!intf)
 		return -ENOMEM;
 	memset(intf, 0, sizeof(*intf));
+	intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL);
+	if (!intf->bmc) {
+		kfree(intf);
+		return -ENOMEM;
+	}
 	intf->intf_num = -1;
 	kref_init(&intf->refcount);
-	intf->version_major = version_major;
-	intf->version_minor = version_minor;
+	intf->bmc->id = *device_id;
+	intf->si_dev = si_dev;
 	for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
 		intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
 		intf->channels[j].lun = 2;
@@ -1858,7 +2366,7 @@
 	spin_lock_init(&intf->events_lock);
 	INIT_LIST_HEAD(&intf->waiting_events);
 	intf->waiting_events_count = 0;
-	init_MUTEX(&intf->cmd_rcvrs_lock);
+	mutex_init(&intf->cmd_rcvrs_mutex);
 	INIT_LIST_HEAD(&intf->cmd_rcvrs);
 	init_waitqueue_head(&intf->waitq);
 
@@ -1880,9 +2388,11 @@
 	if (rv)
 		goto out;
 
-	/* FIXME - this is an ugly kludge, this sets the intf for the
-	   caller before sending any messages with it. */
-	*new_intf = intf;
+	rv = handlers->start_processing(send_info, intf);
+	if (rv)
+		goto out;
+
+	get_guid(intf);
 
 	if ((version_major > 1)
 	    || ((version_major == 1) && (version_minor >= 5)))
@@ -1898,6 +2408,7 @@
 		/* Wait for the channel info to be read. */
 		wait_event(intf->waitq,
 			   intf->curr_channel >= IPMI_MAX_CHANNELS);
+		intf->null_user_handler = NULL;
 	} else {
 		/* Assume a single IPMB channel at zero. */
 		intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
@@ -1907,6 +2418,8 @@
 	if (rv == 0)
 		rv = add_proc_entries(intf, i);
 
+	rv = ipmi_bmc_register(intf);
+
  out:
 	if (rv) {
 		if (intf->proc_dir)
@@ -1921,7 +2434,7 @@
 		spin_lock_irqsave(&interfaces_lock, flags);
 		ipmi_interfaces[i] = intf;
 		spin_unlock_irqrestore(&interfaces_lock, flags);
-		call_smi_watchers(i);
+		call_smi_watchers(i, intf->si_dev);
 	}
 
 	return rv;
@@ -1933,6 +2446,8 @@
 	struct ipmi_smi_watcher *w;
 	unsigned long           flags;
 
+	ipmi_bmc_unregister(intf);
+
 	spin_lock_irqsave(&interfaces_lock, flags);
 	for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
 		if (ipmi_interfaces[i] == intf) {
@@ -2107,7 +2622,7 @@
 		spin_unlock_irqrestore(&intf->counter_lock, flags);
 
 		recv_msg = ipmi_alloc_recv_msg();
-		if (! recv_msg) {
+		if (!recv_msg) {
 			/* We couldn't allocate memory for the
                            message, so requeue it for handling
                            later. */
@@ -2262,7 +2777,7 @@
 		spin_unlock_irqrestore(&intf->counter_lock, flags);
 
 		recv_msg = ipmi_alloc_recv_msg();
-		if (! recv_msg) {
+		if (!recv_msg) {
 			/* We couldn't allocate memory for the
                            message, so requeue it for handling
                            later. */
@@ -2354,13 +2869,14 @@
 	   events. */
 	rcu_read_lock();
 	list_for_each_entry_rcu(user, &intf->users, link) {
-		if (! user->gets_events)
+		if (!user->gets_events)
 			continue;
 
 		recv_msg = ipmi_alloc_recv_msg();
-		if (! recv_msg) {
+		if (!recv_msg) {
 			rcu_read_unlock();
-			list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
+			list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
+						 link) {
 				list_del(&recv_msg->link);
 				ipmi_free_recv_msg(recv_msg);
 			}
@@ -2390,7 +2906,7 @@
 		/* No one to receive the message, put it in queue if there's
 		   not already too many things in the queue. */
 		recv_msg = ipmi_alloc_recv_msg();
-		if (! recv_msg) {
+		if (!recv_msg) {
 			/* We couldn't allocate memory for the
                            message, so requeue it for handling
                            later. */
@@ -2675,7 +3191,7 @@
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(user, &intf->users, link) {
-		if (! user->handler->ipmi_watchdog_pretimeout)
+		if (!user->handler->ipmi_watchdog_pretimeout)
 			continue;
 
 		user->handler->ipmi_watchdog_pretimeout(user->handler_data);
@@ -2763,7 +3279,7 @@
 
 		smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
 					    ent->seqid);
-		if (! smi_msg)
+		if (!smi_msg)
 			return;
 
 		spin_unlock_irqrestore(&intf->seq_lock, *flags);
@@ -2799,8 +3315,9 @@
 
 		/* See if any waiting messages need to be processed. */
 		spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
-		list_for_each_entry_safe(smi_msg, smi_msg2, &intf->waiting_msgs, link) {
-			if (! handle_new_recv_msg(intf, smi_msg)) {
+		list_for_each_entry_safe(smi_msg, smi_msg2,
+					 &intf->waiting_msgs, link) {
+			if (!handle_new_recv_msg(intf, smi_msg)) {
 				list_del(&smi_msg->link);
 				ipmi_free_smi_msg(smi_msg);
 			} else {
@@ -3196,10 +3713,17 @@
 static int ipmi_init_msghandler(void)
 {
 	int i;
+	int rv;
 
 	if (initialized)
 		return 0;
 
+	rv = driver_register(&ipmidriver);
+	if (rv) {
+		printk(KERN_ERR PFX "Could not register IPMI driver\n");
+		return rv;
+	}
+
 	printk(KERN_INFO "ipmi message handler version "
 	       IPMI_DRIVER_VERSION "\n");
 
@@ -3222,7 +3746,7 @@
 	ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
 	add_timer(&ipmi_timer);
 
-	notifier_chain_register(&panic_notifier_list, &panic_block);
+	atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
 
 	initialized = 1;
 
@@ -3242,7 +3766,7 @@
 	if (!initialized)
 		return;
 
-	notifier_chain_unregister(&panic_notifier_list, &panic_block);
+	atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
 
 	/* This can't be called if any interfaces exist, so no worry about
 	   shutting down the interfaces. */
@@ -3256,6 +3780,8 @@
 	remove_proc_entry(proc_ipmi_root->name, &proc_root);
 #endif /* CONFIG_PROC_FS */
 
+	driver_unregister(&ipmidriver);
+
 	initialized = 0;
 
 	/* Check for buffer leaks. */
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index e8ed26b..d0b5c08 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -346,7 +346,7 @@
 {
 	const char ipmi_version_major = ipmi_version & 0xF;
 	const char ipmi_version_minor = (ipmi_version >> 4) & 0xF;
-	const char mfr[3]=DELL_IANA_MFR_ID;
+	const char mfr[3] = DELL_IANA_MFR_ID;
 	if (!memcmp(mfr, &mfg_id, sizeof(mfr)) &&
 	    ipmi_version_major <= 1 &&
 	    ipmi_version_minor < 5)
@@ -464,7 +464,7 @@
 
 /* Wait for an IPMI interface to be installed, the first one installed
    will be grabbed by this code and used to perform the powerdown. */
-static void ipmi_po_new_smi(int if_num)
+static void ipmi_po_new_smi(int if_num, struct device *device)
 {
 	struct ipmi_system_interface_addr smi_addr;
 	struct kernel_ipmi_msg            send_msg;
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index e59b638..a86c0f2 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -52,6 +52,7 @@
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/notifier.h>
+#include <linux/mutex.h>
 #include <linux/kthread.h>
 #include <asm/irq.h>
 #ifdef CONFIG_HIGH_RES_TIMERS
@@ -109,21 +110,15 @@
 enum si_type {
     SI_KCS, SI_SMIC, SI_BT
 };
+static char *si_to_str[] = { "KCS", "SMIC", "BT" };
 
-struct ipmi_device_id {
-	unsigned char device_id;
-	unsigned char device_revision;
-	unsigned char firmware_revision_1;
-	unsigned char firmware_revision_2;
-	unsigned char ipmi_version;
-	unsigned char additional_device_support;
-	unsigned char manufacturer_id[3];
-	unsigned char product_id[2];
-	unsigned char aux_firmware_revision[4];
-} __attribute__((packed));
+#define DEVICE_NAME "ipmi_si"
 
-#define ipmi_version_major(v) ((v)->ipmi_version & 0xf)
-#define ipmi_version_minor(v) ((v)->ipmi_version >> 4)
+static struct device_driver ipmi_driver =
+{
+	.name = DEVICE_NAME,
+	.bus = &platform_bus_type
+};
 
 struct smi_info
 {
@@ -147,6 +142,9 @@
 	int (*irq_setup)(struct smi_info *info);
 	void (*irq_cleanup)(struct smi_info *info);
 	unsigned int io_size;
+	char *addr_source; /* ACPI, PCI, SMBIOS, hardcode, default. */
+	void (*addr_source_cleanup)(struct smi_info *info);
+	void *addr_source_data;
 
 	/* Per-OEM handler, called from handle_flags().
 	   Returns 1 when handle_flags() needs to be re-run
@@ -203,8 +201,17 @@
 	   interrupts. */
 	int interrupt_disabled;
 
+	/* From the get device id response... */
 	struct ipmi_device_id device_id;
 
+	/* Driver model stuff. */
+	struct device *dev;
+	struct platform_device *pdev;
+
+	 /* True if we allocated the device, false if it came from
+	  * someplace else (like PCI). */
+	int dev_registered;
+
 	/* Slave address, could be reported from DMI. */
 	unsigned char slave_addr;
 
@@ -224,12 +231,16 @@
 	unsigned long incoming_messages;
 
         struct task_struct *thread;
+
+	struct list_head link;
 };
 
-static struct notifier_block *xaction_notifier_list;
+static int try_smi_init(struct smi_info *smi);
+
+static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
 static int register_xaction_notifier(struct notifier_block * nb)
 {
-	return notifier_chain_register(&xaction_notifier_list, nb);
+	return atomic_notifier_chain_register(&xaction_notifier_list, nb);
 }
 
 static void si_restart_short_timer(struct smi_info *smi_info);
@@ -271,13 +282,13 @@
 	spin_lock(&(smi_info->msg_lock));
 
 	/* Pick the high priority queue first. */
-	if (! list_empty(&(smi_info->hp_xmit_msgs))) {
+	if (!list_empty(&(smi_info->hp_xmit_msgs))) {
 		entry = smi_info->hp_xmit_msgs.next;
-	} else if (! list_empty(&(smi_info->xmit_msgs))) {
+	} else if (!list_empty(&(smi_info->xmit_msgs))) {
 		entry = smi_info->xmit_msgs.next;
 	}
 
-	if (! entry) {
+	if (!entry) {
 		smi_info->curr_msg = NULL;
 		rv = SI_SM_IDLE;
 	} else {
@@ -291,7 +302,8 @@
 		do_gettimeofday(&t);
 		printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
 #endif
-		err = notifier_call_chain(&xaction_notifier_list, 0, smi_info);
+		err = atomic_notifier_call_chain(&xaction_notifier_list,
+				0, smi_info);
 		if (err & NOTIFY_STOP_MASK) {
 			rv = SI_SM_CALL_WITHOUT_DELAY;
 			goto out;
@@ -344,7 +356,7 @@
    memory, we will re-enable the interrupt. */
 static inline void disable_si_irq(struct smi_info *smi_info)
 {
-	if ((smi_info->irq) && (! smi_info->interrupt_disabled)) {
+	if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
 		disable_irq_nosync(smi_info->irq);
 		smi_info->interrupt_disabled = 1;
 	}
@@ -375,7 +387,7 @@
 	} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
 		/* Messages available. */
 		smi_info->curr_msg = ipmi_alloc_smi_msg();
-		if (! smi_info->curr_msg) {
+		if (!smi_info->curr_msg) {
 			disable_si_irq(smi_info);
 			smi_info->si_state = SI_NORMAL;
 			return;
@@ -394,7 +406,7 @@
 	} else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
 		/* Events available. */
 		smi_info->curr_msg = ipmi_alloc_smi_msg();
-		if (! smi_info->curr_msg) {
+		if (!smi_info->curr_msg) {
 			disable_si_irq(smi_info);
 			smi_info->si_state = SI_NORMAL;
 			return;
@@ -430,7 +442,7 @@
 #endif
 	switch (smi_info->si_state) {
 	case SI_NORMAL:
-		if (! smi_info->curr_msg)
+		if (!smi_info->curr_msg)
 			break;
 
 		smi_info->curr_msg->rsp_size
@@ -791,7 +803,7 @@
 	set_user_nice(current, 19);
 	while (!kthread_should_stop()) {
 		spin_lock_irqsave(&(smi_info->si_lock), flags);
-		smi_result=smi_event_handler(smi_info, 0);
+		smi_result = smi_event_handler(smi_info, 0);
 		spin_unlock_irqrestore(&(smi_info->si_lock), flags);
 		if (smi_result == SI_SM_CALL_WITHOUT_DELAY) {
 			/* do nothing */
@@ -880,7 +892,7 @@
 
 	smi_info->last_timeout_jiffies = jiffies_now;
 
-	if ((smi_info->irq) && (! smi_info->interrupt_disabled)) {
+	if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
 		/* Running with interrupts, only do long timeouts. */
 		smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
 		spin_lock_irqsave(&smi_info->count_lock, flags);
@@ -960,10 +972,37 @@
 	return si_irq_handler(irq, data, regs);
 }
 
+static int smi_start_processing(void       *send_info,
+				ipmi_smi_t intf)
+{
+	struct smi_info *new_smi = send_info;
+
+	new_smi->intf = intf;
+
+	/* Set up the timer that drives the interface. */
+	setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi);
+	new_smi->last_timeout_jiffies = jiffies;
+	mod_timer(&new_smi->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
+
+ 	if (new_smi->si_type != SI_BT) {
+		new_smi->thread = kthread_run(ipmi_thread, new_smi,
+					      "kipmi%d", new_smi->intf_num);
+		if (IS_ERR(new_smi->thread)) {
+			printk(KERN_NOTICE "ipmi_si_intf: Could not start"
+			       " kernel thread due to error %ld, only using"
+			       " timers to drive the interface\n",
+			       PTR_ERR(new_smi->thread));
+			new_smi->thread = NULL;
+		}
+	}
+
+	return 0;
+}
 
 static struct ipmi_smi_handlers handlers =
 {
 	.owner                  = THIS_MODULE,
+	.start_processing       = smi_start_processing,
 	.sender			= sender,
 	.request_events		= request_events,
 	.set_run_to_completion  = set_run_to_completion,
@@ -974,15 +1013,10 @@
    a default IO port, and 1 ACPI/SPMI address.  That sets SI_MAX_DRIVERS */
 
 #define SI_MAX_PARMS 4
-#define SI_MAX_DRIVERS ((SI_MAX_PARMS * 2) + 2)
-static struct smi_info *smi_infos[SI_MAX_DRIVERS] =
-{ NULL, NULL, NULL, NULL };
+static LIST_HEAD(smi_infos);
+static DEFINE_MUTEX(smi_infos_lock);
+static int smi_num; /* Used to sequence the SMIs */
 
-#define DEVICE_NAME "ipmi_si"
-
-#define DEFAULT_KCS_IO_PORT	0xca2
-#define DEFAULT_SMIC_IO_PORT	0xca9
-#define DEFAULT_BT_IO_PORT	0xe4
 #define DEFAULT_REGSPACING	1
 
 static int           si_trydefaults = 1;
@@ -1053,38 +1087,23 @@
 		 " by interface number.");
 
 
+#define IPMI_IO_ADDR_SPACE  0
 #define IPMI_MEM_ADDR_SPACE 1
-#define IPMI_IO_ADDR_SPACE  2
+static char *addr_space_to_str[] = { "I/O", "memory" };
 
-#if defined(CONFIG_ACPI) || defined(CONFIG_DMI) || defined(CONFIG_PCI)
-static int is_new_interface(int intf, u8 addr_space, unsigned long base_addr)
+static void std_irq_cleanup(struct smi_info *info)
 {
-	int i;
-
-	for (i = 0; i < SI_MAX_PARMS; ++i) {
-		/* Don't check our address. */
-		if (i == intf)
-			continue;
-		if (si_type[i] != NULL) {
-			if ((addr_space == IPMI_MEM_ADDR_SPACE &&
-			     base_addr == addrs[i]) ||
-			    (addr_space == IPMI_IO_ADDR_SPACE &&
-			     base_addr == ports[i]))
-				return 0;
-		}
-		else
-			break;
-	}
-
-	return 1;
+	if (info->si_type == SI_BT)
+		/* Disable the interrupt in the BT interface. */
+		info->io.outputb(&info->io, IPMI_BT_INTMASK_REG, 0);
+	free_irq(info->irq, info);
 }
-#endif
 
 static int std_irq_setup(struct smi_info *info)
 {
 	int rv;
 
-	if (! info->irq)
+	if (!info->irq)
 		return 0;
 
 	if (info->si_type == SI_BT) {
@@ -1093,7 +1112,7 @@
 				 SA_INTERRUPT,
 				 DEVICE_NAME,
 				 info);
-		if (! rv)
+		if (!rv)
 			/* Enable the interrupt in the BT interface. */
 			info->io.outputb(&info->io, IPMI_BT_INTMASK_REG,
 					 IPMI_BT_INTMASK_ENABLE_IRQ_BIT);
@@ -1110,88 +1129,77 @@
 		       DEVICE_NAME, info->irq);
 		info->irq = 0;
 	} else {
+		info->irq_cleanup = std_irq_cleanup;
 		printk("  Using irq %d\n", info->irq);
 	}
 
 	return rv;
 }
 
-static void std_irq_cleanup(struct smi_info *info)
-{
-	if (! info->irq)
-		return;
-
-	if (info->si_type == SI_BT)
-		/* Disable the interrupt in the BT interface. */
-		info->io.outputb(&info->io, IPMI_BT_INTMASK_REG, 0);
-	free_irq(info->irq, info);
-}
-
 static unsigned char port_inb(struct si_sm_io *io, unsigned int offset)
 {
-	unsigned int *addr = io->info;
+	unsigned int addr = io->addr_data;
 
-	return inb((*addr)+(offset*io->regspacing));
+	return inb(addr + (offset * io->regspacing));
 }
 
 static void port_outb(struct si_sm_io *io, unsigned int offset,
 		      unsigned char b)
 {
-	unsigned int *addr = io->info;
+	unsigned int addr = io->addr_data;
 
-	outb(b, (*addr)+(offset * io->regspacing));
+	outb(b, addr + (offset * io->regspacing));
 }
 
 static unsigned char port_inw(struct si_sm_io *io, unsigned int offset)
 {
-	unsigned int *addr = io->info;
+	unsigned int addr = io->addr_data;
 
-	return (inw((*addr)+(offset * io->regspacing)) >> io->regshift) & 0xff;
+	return (inw(addr + (offset * io->regspacing)) >> io->regshift) & 0xff;
 }
 
 static void port_outw(struct si_sm_io *io, unsigned int offset,
 		      unsigned char b)
 {
-	unsigned int *addr = io->info;
+	unsigned int addr = io->addr_data;
 
-	outw(b << io->regshift, (*addr)+(offset * io->regspacing));
+	outw(b << io->regshift, addr + (offset * io->regspacing));
 }
 
 static unsigned char port_inl(struct si_sm_io *io, unsigned int offset)
 {
-	unsigned int *addr = io->info;
+	unsigned int addr = io->addr_data;
 
-	return (inl((*addr)+(offset * io->regspacing)) >> io->regshift) & 0xff;
+	return (inl(addr + (offset * io->regspacing)) >> io->regshift) & 0xff;
 }
 
 static void port_outl(struct si_sm_io *io, unsigned int offset,
 		      unsigned char b)
 {
-	unsigned int *addr = io->info;
+	unsigned int addr = io->addr_data;
 
-	outl(b << io->regshift, (*addr)+(offset * io->regspacing));
+	outl(b << io->regshift, addr+(offset * io->regspacing));
 }
 
 static void port_cleanup(struct smi_info *info)
 {
-	unsigned int *addr = info->io.info;
-	int           mapsize;
+	unsigned int addr = info->io.addr_data;
+	int          mapsize;
 
-	if (addr && (*addr)) {
+	if (addr) {
 		mapsize = ((info->io_size * info->io.regspacing)
 			   - (info->io.regspacing - info->io.regsize));
 
-		release_region (*addr, mapsize);
+		release_region (addr, mapsize);
 	}
-	kfree(info);
 }
 
 static int port_setup(struct smi_info *info)
 {
-	unsigned int *addr = info->io.info;
-	int           mapsize;
+	unsigned int addr = info->io.addr_data;
+	int          mapsize;
 
-	if (! addr || (! *addr))
+	if (!addr)
 		return -ENODEV;
 
 	info->io_cleanup = port_cleanup;
@@ -1225,51 +1233,11 @@
 	mapsize = ((info->io_size * info->io.regspacing)
 		   - (info->io.regspacing - info->io.regsize));
 
-	if (request_region(*addr, mapsize, DEVICE_NAME) == NULL)
+	if (request_region(addr, mapsize, DEVICE_NAME) == NULL)
 		return -EIO;
 	return 0;
 }
 
-static int try_init_port(int intf_num, struct smi_info **new_info)
-{
-	struct smi_info *info;
-
-	if (! ports[intf_num])
-		return -ENODEV;
-
-	if (! is_new_interface(intf_num, IPMI_IO_ADDR_SPACE,
-			      ports[intf_num]))
-		return -ENODEV;
-
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
-	if (! info) {
-		printk(KERN_ERR "ipmi_si: Could not allocate SI data (1)\n");
-		return -ENOMEM;
-	}
-	memset(info, 0, sizeof(*info));
-
-	info->io_setup = port_setup;
-	info->io.info = &(ports[intf_num]);
-	info->io.addr = NULL;
-	info->io.regspacing = regspacings[intf_num];
-	if (! info->io.regspacing)
-		info->io.regspacing = DEFAULT_REGSPACING;
-	info->io.regsize = regsizes[intf_num];
-	if (! info->io.regsize)
-		info->io.regsize = DEFAULT_REGSPACING;
-	info->io.regshift = regshifts[intf_num];
-	info->irq = 0;
-	info->irq_setup = NULL;
-	*new_info = info;
-
-	if (si_type[intf_num] == NULL)
-		si_type[intf_num] = "kcs";
-
-	printk("ipmi_si: Trying \"%s\" at I/O port 0x%x\n",
-	       si_type[intf_num], ports[intf_num]);
-	return 0;
-}
-
 static unsigned char intf_mem_inb(struct si_sm_io *io, unsigned int offset)
 {
 	return readb((io->addr)+(offset * io->regspacing));
@@ -1321,7 +1289,7 @@
 
 static void mem_cleanup(struct smi_info *info)
 {
-	unsigned long *addr = info->io.info;
+	unsigned long addr = info->io.addr_data;
 	int           mapsize;
 
 	if (info->io.addr) {
@@ -1330,17 +1298,16 @@
 		mapsize = ((info->io_size * info->io.regspacing)
 			   - (info->io.regspacing - info->io.regsize));
 
-		release_mem_region(*addr, mapsize);
+		release_mem_region(addr, mapsize);
 	}
-	kfree(info);
 }
 
 static int mem_setup(struct smi_info *info)
 {
-	unsigned long *addr = info->io.info;
+	unsigned long addr = info->io.addr_data;
 	int           mapsize;
 
-	if (! addr || (! *addr))
+	if (!addr)
 		return -ENODEV;
 
 	info->io_cleanup = mem_cleanup;
@@ -1380,58 +1347,84 @@
 	mapsize = ((info->io_size * info->io.regspacing)
 		   - (info->io.regspacing - info->io.regsize));
 
-	if (request_mem_region(*addr, mapsize, DEVICE_NAME) == NULL)
+	if (request_mem_region(addr, mapsize, DEVICE_NAME) == NULL)
 		return -EIO;
 
-	info->io.addr = ioremap(*addr, mapsize);
+	info->io.addr = ioremap(addr, mapsize);
 	if (info->io.addr == NULL) {
-		release_mem_region(*addr, mapsize);
+		release_mem_region(addr, mapsize);
 		return -EIO;
 	}
 	return 0;
 }
 
-static int try_init_mem(int intf_num, struct smi_info **new_info)
+
+static __devinit void hardcode_find_bmc(void)
 {
+	int             i;
 	struct smi_info *info;
 
-	if (! addrs[intf_num])
-		return -ENODEV;
+	for (i = 0; i < SI_MAX_PARMS; i++) {
+		if (!ports[i] && !addrs[i])
+			continue;
 
-	if (! is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE,
-			      addrs[intf_num]))
-		return -ENODEV;
+		info = kzalloc(sizeof(*info), GFP_KERNEL);
+		if (!info)
+			return;
 
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
-	if (! info) {
-		printk(KERN_ERR "ipmi_si: Could not allocate SI data (2)\n");
-		return -ENOMEM;
+		info->addr_source = "hardcoded";
+
+		if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) {
+			info->si_type = SI_KCS;
+		} else if (strcmp(si_type[i], "smic") == 0) {
+			info->si_type = SI_SMIC;
+		} else if (strcmp(si_type[i], "bt") == 0) {
+			info->si_type = SI_BT;
+		} else {
+			printk(KERN_WARNING
+			       "ipmi_si: Interface type specified "
+			       "for interface %d, was invalid: %s\n",
+			       i, si_type[i]);
+			kfree(info);
+			continue;
+		}
+
+		if (ports[i]) {
+			/* An I/O port */
+			info->io_setup = port_setup;
+			info->io.addr_data = ports[i];
+			info->io.addr_type = IPMI_IO_ADDR_SPACE;
+		} else if (addrs[i]) {
+			/* A memory port */
+			info->io_setup = mem_setup;
+			info->io.addr_data = addrs[i];
+			info->io.addr_type = IPMI_MEM_ADDR_SPACE;
+		} else {
+			printk(KERN_WARNING
+			       "ipmi_si: Interface type specified "
+			       "for interface %d, "
+			       "but port and address were not set or "
+			       "set to zero.\n", i);
+			kfree(info);
+			continue;
+		}
+
+		info->io.addr = NULL;
+		info->io.regspacing = regspacings[i];
+		if (!info->io.regspacing)
+			info->io.regspacing = DEFAULT_REGSPACING;
+		info->io.regsize = regsizes[i];
+		if (!info->io.regsize)
+			info->io.regsize = DEFAULT_REGSPACING;
+		info->io.regshift = regshifts[i];
+		info->irq = irqs[i];
+		if (info->irq)
+			info->irq_setup = std_irq_setup;
+
+		try_smi_init(info);
 	}
-	memset(info, 0, sizeof(*info));
-
-	info->io_setup = mem_setup;
-	info->io.info = &addrs[intf_num];
-	info->io.addr = NULL;
-	info->io.regspacing = regspacings[intf_num];
-	if (! info->io.regspacing)
-		info->io.regspacing = DEFAULT_REGSPACING;
-	info->io.regsize = regsizes[intf_num];
-	if (! info->io.regsize)
-		info->io.regsize = DEFAULT_REGSPACING;
-	info->io.regshift = regshifts[intf_num];
-	info->irq = 0;
-	info->irq_setup = NULL;
-	*new_info = info;
-
-	if (si_type[intf_num] == NULL)
-		si_type[intf_num] = "kcs";
-
-	printk("ipmi_si: Trying \"%s\" at memory address 0x%lx\n",
-	       si_type[intf_num], addrs[intf_num]);
-	return 0;
 }
 
-
 #ifdef CONFIG_ACPI
 
 #include <linux/acpi.h>
@@ -1470,11 +1463,19 @@
 	return ACPI_INTERRUPT_HANDLED;
 }
 
+static void acpi_gpe_irq_cleanup(struct smi_info *info)
+{
+	if (!info->irq)
+		return;
+
+	acpi_remove_gpe_handler(NULL, info->irq, &ipmi_acpi_gpe);
+}
+
 static int acpi_gpe_irq_setup(struct smi_info *info)
 {
 	acpi_status status;
 
-	if (! info->irq)
+	if (!info->irq)
 		return 0;
 
 	/* FIXME - is level triggered right? */
@@ -1491,19 +1492,12 @@
 		info->irq = 0;
 		return -EINVAL;
 	} else {
+		info->irq_cleanup = acpi_gpe_irq_cleanup;
 		printk("  Using ACPI GPE %d\n", info->irq);
 		return 0;
 	}
 }
 
-static void acpi_gpe_irq_cleanup(struct smi_info *info)
-{
-	if (! info->irq)
-		return;
-
-	acpi_remove_gpe_handler(NULL, info->irq, &ipmi_acpi_gpe);
-}
-
 /*
  * Defined at
  * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/Docs/TechPapers/IA64/hpspmi.pdf
@@ -1546,28 +1540,12 @@
 	s8      spmi_id[1]; /* A '\0' terminated array starts here. */
 };
 
-static int try_init_acpi(int intf_num, struct smi_info **new_info)
+static __devinit int try_init_acpi(struct SPMITable *spmi)
 {
 	struct smi_info  *info;
-	acpi_status      status;
-	struct SPMITable *spmi;
 	char             *io_type;
 	u8 		 addr_space;
 
-	if (acpi_disabled)
-		return -ENODEV;
-
-	if (acpi_failure)
-		return -ENODEV;
-
-	status = acpi_get_firmware_table("SPMI", intf_num+1,
-					 ACPI_LOGICAL_ADDRESSING,
-					 (struct acpi_table_header **) &spmi);
-	if (status != AE_OK) {
-		acpi_failure = 1;
-		return -ENODEV;
-	}
-
 	if (spmi->IPMIlegacy != 1) {
 	    printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy);
   	    return -ENODEV;
@@ -1577,47 +1555,42 @@
 		addr_space = IPMI_MEM_ADDR_SPACE;
 	else
 		addr_space = IPMI_IO_ADDR_SPACE;
-	if (! is_new_interface(-1, addr_space, spmi->addr.address))
-		return -ENODEV;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n");
+		return -ENOMEM;
+	}
+
+	info->addr_source = "ACPI";
 
 	/* Figure out the interface type. */
 	switch (spmi->InterfaceType)
 	{
 	case 1:	/* KCS */
-		si_type[intf_num] = "kcs";
+		info->si_type = SI_KCS;
 		break;
-
 	case 2:	/* SMIC */
-		si_type[intf_num] = "smic";
+		info->si_type = SI_SMIC;
 		break;
-
 	case 3:	/* BT */
-		si_type[intf_num] = "bt";
+		info->si_type = SI_BT;
 		break;
-
 	default:
 		printk(KERN_INFO "ipmi_si: Unknown ACPI/SPMI SI type %d\n",
 			spmi->InterfaceType);
+		kfree(info);
 		return -EIO;
 	}
 
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
-	if (! info) {
-		printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n");
-		return -ENOMEM;
-	}
-	memset(info, 0, sizeof(*info));
-
 	if (spmi->InterruptType & 1) {
 		/* We've got a GPE interrupt. */
 		info->irq = spmi->GPE;
 		info->irq_setup = acpi_gpe_irq_setup;
-		info->irq_cleanup = acpi_gpe_irq_cleanup;
 	} else if (spmi->InterruptType & 2) {
 		/* We've got an APIC/SAPIC interrupt. */
 		info->irq = spmi->GlobalSystemInterrupt;
 		info->irq_setup = std_irq_setup;
-		info->irq_cleanup = std_irq_cleanup;
 	} else {
 		/* Use the default interrupt setting. */
 		info->irq = 0;
@@ -1626,43 +1599,60 @@
 
 	if (spmi->addr.register_bit_width) {
 		/* A (hopefully) properly formed register bit width. */
-		regspacings[intf_num] = spmi->addr.register_bit_width / 8;
 		info->io.regspacing = spmi->addr.register_bit_width / 8;
 	} else {
-		regspacings[intf_num] = DEFAULT_REGSPACING;
 		info->io.regspacing = DEFAULT_REGSPACING;
 	}
-	regsizes[intf_num] = regspacings[intf_num];
-	info->io.regsize = regsizes[intf_num];
-	regshifts[intf_num] = spmi->addr.register_bit_offset;
-	info->io.regshift = regshifts[intf_num];
+	info->io.regsize = info->io.regspacing;
+	info->io.regshift = spmi->addr.register_bit_offset;
 
 	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
 		io_type = "memory";
 		info->io_setup = mem_setup;
-		addrs[intf_num] = spmi->addr.address;
-		info->io.info = &(addrs[intf_num]);
+		info->io.addr_type = IPMI_IO_ADDR_SPACE;
 	} else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
 		io_type = "I/O";
 		info->io_setup = port_setup;
-		ports[intf_num] = spmi->addr.address;
-		info->io.info = &(ports[intf_num]);
+		info->io.addr_type = IPMI_MEM_ADDR_SPACE;
 	} else {
 		kfree(info);
 		printk("ipmi_si: Unknown ACPI I/O Address type\n");
 		return -EIO;
 	}
+	info->io.addr_data = spmi->addr.address;
 
-	*new_info = info;
+	try_smi_init(info);
 
-	printk("ipmi_si: ACPI/SPMI specifies \"%s\" %s SI @ 0x%lx\n",
-	       si_type[intf_num], io_type, (unsigned long) spmi->addr.address);
 	return 0;
 }
+
+static __devinit void acpi_find_bmc(void)
+{
+	acpi_status      status;
+	struct SPMITable *spmi;
+	int              i;
+
+	if (acpi_disabled)
+		return;
+
+	if (acpi_failure)
+		return;
+
+	for (i = 0; ; i++) {
+		status = acpi_get_firmware_table("SPMI", i+1,
+						 ACPI_LOGICAL_ADDRESSING,
+						 (struct acpi_table_header **)
+						 &spmi);
+		if (status != AE_OK)
+			return;
+
+		try_init_acpi(spmi);
+	}
+}
 #endif
 
 #ifdef CONFIG_DMI
-typedef struct dmi_ipmi_data
+struct dmi_ipmi_data
 {
 	u8   		type;
 	u8   		addr_space;
@@ -1670,49 +1660,46 @@
 	u8   		irq;
 	u8              offset;
 	u8              slave_addr;
-} dmi_ipmi_data_t;
+};
 
-static dmi_ipmi_data_t dmi_data[SI_MAX_DRIVERS];
-static int dmi_data_entries;
-
-static int __init decode_dmi(struct dmi_header *dm, int intf_num)
+static int __devinit decode_dmi(struct dmi_header *dm,
+				struct dmi_ipmi_data *dmi)
 {
 	u8              *data = (u8 *)dm;
 	unsigned long  	base_addr;
 	u8		reg_spacing;
 	u8              len = dm->length;
-	dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
 
-	ipmi_data->type = data[4];
+	dmi->type = data[4];
 
 	memcpy(&base_addr, data+8, sizeof(unsigned long));
 	if (len >= 0x11) {
 		if (base_addr & 1) {
 			/* I/O */
 			base_addr &= 0xFFFE;
-			ipmi_data->addr_space = IPMI_IO_ADDR_SPACE;
+			dmi->addr_space = IPMI_IO_ADDR_SPACE;
 		}
 		else {
 			/* Memory */
-			ipmi_data->addr_space = IPMI_MEM_ADDR_SPACE;
+			dmi->addr_space = IPMI_MEM_ADDR_SPACE;
 		}
 		/* If bit 4 of byte 0x10 is set, then the lsb for the address
 		   is odd. */
-		ipmi_data->base_addr = base_addr | ((data[0x10] & 0x10) >> 4);
+		dmi->base_addr = base_addr | ((data[0x10] & 0x10) >> 4);
 
-		ipmi_data->irq = data[0x11];
+		dmi->irq = data[0x11];
 
 		/* The top two bits of byte 0x10 hold the register spacing. */
 		reg_spacing = (data[0x10] & 0xC0) >> 6;
 		switch(reg_spacing){
 		case 0x00: /* Byte boundaries */
-		    ipmi_data->offset = 1;
+		    dmi->offset = 1;
 		    break;
 		case 0x01: /* 32-bit boundaries */
-		    ipmi_data->offset = 4;
+		    dmi->offset = 4;
 		    break;
 		case 0x02: /* 16-byte boundaries */
-		    ipmi_data->offset = 16;
+		    dmi->offset = 16;
 		    break;
 		default:
 		    /* Some other interface, just ignore it. */
@@ -1726,217 +1713,227 @@
 		 * wrong (and all that I have seen are I/O) so we just
 		 * ignore that bit and assume I/O.  Systems that use
 		 * memory should use the newer spec, anyway. */
-		ipmi_data->base_addr = base_addr & 0xfffe;
-		ipmi_data->addr_space = IPMI_IO_ADDR_SPACE;
-		ipmi_data->offset = 1;
+		dmi->base_addr = base_addr & 0xfffe;
+		dmi->addr_space = IPMI_IO_ADDR_SPACE;
+		dmi->offset = 1;
 	}
 
-	ipmi_data->slave_addr = data[6];
+	dmi->slave_addr = data[6];
 
-	if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr)) {
-		dmi_data_entries++;
-		return 0;
-	}
-
-	memset(ipmi_data, 0, sizeof(dmi_ipmi_data_t));
-
-	return -1;
+	return 0;
 }
 
-static void __init dmi_find_bmc(void)
-{
-	struct dmi_device *dev = NULL;
-	int               intf_num = 0;
-
-	while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
-		if (intf_num >= SI_MAX_DRIVERS)
-			break;
-
-		decode_dmi((struct dmi_header *) dev->device_data, intf_num++);
-	}
-}
-
-static int try_init_smbios(int intf_num, struct smi_info **new_info)
+static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
 {
 	struct smi_info *info;
-	dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
-	char            *io_type;
 
-	if (intf_num >= dmi_data_entries)
-		return -ENODEV;
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR
+		       "ipmi_si: Could not allocate SI data\n");
+		return;
+	}
+
+	info->addr_source = "SMBIOS";
 
 	switch (ipmi_data->type) {
-		case 0x01: /* KCS */
-			si_type[intf_num] = "kcs";
-			break;
-		case 0x02: /* SMIC */
-			si_type[intf_num] = "smic";
-			break;
-		case 0x03: /* BT */
-			si_type[intf_num] = "bt";
-			break;
-		default:
-			return -EIO;
+	case 0x01: /* KCS */
+		info->si_type = SI_KCS;
+		break;
+	case 0x02: /* SMIC */
+		info->si_type = SI_SMIC;
+		break;
+	case 0x03: /* BT */
+		info->si_type = SI_BT;
+		break;
+	default:
+		return;
 	}
 
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
-	if (! info) {
-		printk(KERN_ERR "ipmi_si: Could not allocate SI data (4)\n");
-		return -ENOMEM;
-	}
-	memset(info, 0, sizeof(*info));
-
-	if (ipmi_data->addr_space == 1) {
-		io_type = "memory";
+	switch (ipmi_data->addr_space) {
+	case IPMI_MEM_ADDR_SPACE:
 		info->io_setup = mem_setup;
-		addrs[intf_num] = ipmi_data->base_addr;
-		info->io.info = &(addrs[intf_num]);
-	} else if (ipmi_data->addr_space == 2) {
-		io_type = "I/O";
-		info->io_setup = port_setup;
-		ports[intf_num] = ipmi_data->base_addr;
-		info->io.info = &(ports[intf_num]);
-	} else {
-		kfree(info);
-		printk("ipmi_si: Unknown SMBIOS I/O Address type.\n");
-		return -EIO;
-	}
+		info->io.addr_type = IPMI_MEM_ADDR_SPACE;
+		break;
 
-	regspacings[intf_num] = ipmi_data->offset;
-	info->io.regspacing = regspacings[intf_num];
-	if (! info->io.regspacing)
+	case IPMI_IO_ADDR_SPACE:
+		info->io_setup = port_setup;
+		info->io.addr_type = IPMI_IO_ADDR_SPACE;
+		break;
+
+	default:
+		kfree(info);
+		printk(KERN_WARNING
+		       "ipmi_si: Unknown SMBIOS I/O Address type: %d.\n",
+		       ipmi_data->addr_space);
+		return;
+	}
+	info->io.addr_data = ipmi_data->base_addr;
+
+	info->io.regspacing = ipmi_data->offset;
+	if (!info->io.regspacing)
 		info->io.regspacing = DEFAULT_REGSPACING;
 	info->io.regsize = DEFAULT_REGSPACING;
-	info->io.regshift = regshifts[intf_num];
+	info->io.regshift = 0;
 
 	info->slave_addr = ipmi_data->slave_addr;
 
-	irqs[intf_num] = ipmi_data->irq;
+	info->irq = ipmi_data->irq;
+	if (info->irq)
+		info->irq_setup = std_irq_setup;
 
-	*new_info = info;
+	try_smi_init(info);
+}
 
-	printk("ipmi_si: Found SMBIOS-specified state machine at %s"
-	       " address 0x%lx, slave address 0x%x\n",
-	       io_type, (unsigned long)ipmi_data->base_addr,
-	       ipmi_data->slave_addr);
-	return 0;
+static void __devinit dmi_find_bmc(void)
+{
+	struct dmi_device    *dev = NULL;
+	struct dmi_ipmi_data data;
+	int                  rv;
+
+	while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
+		rv = decode_dmi((struct dmi_header *) dev->device_data, &data);
+		if (!rv)
+			try_init_dmi(&data);
+	}
 }
 #endif /* CONFIG_DMI */
 
 #ifdef CONFIG_PCI
 
-#define PCI_ERMC_CLASSCODE  0x0C0700
+#define PCI_ERMC_CLASSCODE		0x0C0700
+#define PCI_ERMC_CLASSCODE_MASK		0xffffff00
+#define PCI_ERMC_CLASSCODE_TYPE_MASK	0xff
+#define PCI_ERMC_CLASSCODE_TYPE_SMIC	0x00
+#define PCI_ERMC_CLASSCODE_TYPE_KCS	0x01
+#define PCI_ERMC_CLASSCODE_TYPE_BT	0x02
+
 #define PCI_HP_VENDOR_ID    0x103C
 #define PCI_MMC_DEVICE_ID   0x121A
 #define PCI_MMC_ADDR_CW     0x10
 
-/* Avoid more than one attempt to probe pci smic. */
-static int pci_smic_checked = 0;
-
-static int find_pci_smic(int intf_num, struct smi_info **new_info)
+static void ipmi_pci_cleanup(struct smi_info *info)
 {
-	struct smi_info  *info;
-	int              error;
-	struct pci_dev   *pci_dev = NULL;
-	u16    		 base_addr;
-	int              fe_rmc = 0;
+	struct pci_dev *pdev = info->addr_source_data;
 
-	if (pci_smic_checked)
-		return -ENODEV;
+	pci_disable_device(pdev);
+}
 
-	pci_smic_checked = 1;
+static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
+				    const struct pci_device_id *ent)
+{
+	int rv;
+	int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK;
+	struct smi_info *info;
+	int first_reg_offset = 0;
 
-	pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID, NULL);
-	if (! pci_dev) {
-		pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL);
-		if (pci_dev && (pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID))
-			fe_rmc = 1;
-		else
-			return -ENODEV;
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return ENOMEM;
+
+	info->addr_source = "PCI";
+
+	switch (class_type) {
+	case PCI_ERMC_CLASSCODE_TYPE_SMIC:
+		info->si_type = SI_SMIC;
+		break;
+
+	case PCI_ERMC_CLASSCODE_TYPE_KCS:
+		info->si_type = SI_KCS;
+		break;
+
+	case PCI_ERMC_CLASSCODE_TYPE_BT:
+		info->si_type = SI_BT;
+		break;
+
+	default:
+		kfree(info);
+		printk(KERN_INFO "ipmi_si: %s: Unknown IPMI type: %d\n",
+		       pci_name(pdev), class_type);
+		return ENOMEM;
 	}
 
-	error = pci_read_config_word(pci_dev, PCI_MMC_ADDR_CW, &base_addr);
-	if (error)
-	{
-		pci_dev_put(pci_dev);
-		printk(KERN_ERR
-		       "ipmi_si: pci_read_config_word() failed (%d).\n",
-		       error);
-		return -ENODEV;
+	rv = pci_enable_device(pdev);
+	if (rv) {
+		printk(KERN_ERR "ipmi_si: %s: couldn't enable PCI device\n",
+		       pci_name(pdev));
+		kfree(info);
+		return rv;
 	}
 
-	/* Bit 0: 1 specifies programmed I/O, 0 specifies memory mapped I/O */
-	if (! (base_addr & 0x0001))
-	{
-		pci_dev_put(pci_dev);
-		printk(KERN_ERR
-		       "ipmi_si: memory mapped I/O not supported for PCI"
-		       " smic.\n");
-		return -ENODEV;
+	info->addr_source_cleanup = ipmi_pci_cleanup;
+	info->addr_source_data = pdev;
+
+	if (pdev->subsystem_vendor == PCI_HP_VENDOR_ID)
+		first_reg_offset = 1;
+
+	if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
+		info->io_setup = port_setup;
+		info->io.addr_type = IPMI_IO_ADDR_SPACE;
+	} else {
+		info->io_setup = mem_setup;
+		info->io.addr_type = IPMI_MEM_ADDR_SPACE;
 	}
+	info->io.addr_data = pci_resource_start(pdev, 0);
 
-	base_addr &= 0xFFFE;
-	if (! fe_rmc)
-		/* Data register starts at base address + 1 in eRMC */
-		++base_addr;
-
-	if (! is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) {
-		pci_dev_put(pci_dev);
-		return -ENODEV;
-	}
-
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
-	if (! info) {
-		pci_dev_put(pci_dev);
-		printk(KERN_ERR "ipmi_si: Could not allocate SI data (5)\n");
-		return -ENOMEM;
-	}
-	memset(info, 0, sizeof(*info));
-
-	info->io_setup = port_setup;
-	ports[intf_num] = base_addr;
-	info->io.info = &(ports[intf_num]);
-	info->io.regspacing = regspacings[intf_num];
-	if (! info->io.regspacing)
-		info->io.regspacing = DEFAULT_REGSPACING;
+	info->io.regspacing = DEFAULT_REGSPACING;
 	info->io.regsize = DEFAULT_REGSPACING;
-	info->io.regshift = regshifts[intf_num];
+	info->io.regshift = 0;
 
-	*new_info = info;
+	info->irq = pdev->irq;
+	if (info->irq)
+		info->irq_setup = std_irq_setup;
 
-	irqs[intf_num] = pci_dev->irq;
-	si_type[intf_num] = "smic";
+	info->dev = &pdev->dev;
 
-	printk("ipmi_si: Found PCI SMIC at I/O address 0x%lx\n",
-		(long unsigned int) base_addr);
+	return try_smi_init(info);
+}
 
-	pci_dev_put(pci_dev);
+static void __devexit ipmi_pci_remove(struct pci_dev *pdev)
+{
+}
+
+#ifdef CONFIG_PM
+static int ipmi_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
 	return 0;
 }
-#endif /* CONFIG_PCI */
 
-static int try_init_plug_and_play(int intf_num, struct smi_info **new_info)
+static int ipmi_pci_resume(struct pci_dev *pdev)
 {
-#ifdef CONFIG_PCI
-	if (find_pci_smic(intf_num, new_info) == 0)
-		return 0;
-#endif
-	/* Include other methods here. */
-
-	return -ENODEV;
+	return 0;
 }
+#endif
+
+static struct pci_device_id ipmi_pci_devices[] = {
+	{ PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) },
+	{ PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE) }
+};
+MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);
+
+static struct pci_driver ipmi_pci_driver = {
+        .name =         DEVICE_NAME,
+        .id_table =     ipmi_pci_devices,
+        .probe =        ipmi_pci_probe,
+        .remove =       __devexit_p(ipmi_pci_remove),
+#ifdef CONFIG_PM
+        .suspend =      ipmi_pci_suspend,
+        .resume =       ipmi_pci_resume,
+#endif
+};
+#endif /* CONFIG_PCI */
 
 
 static int try_get_dev_id(struct smi_info *smi_info)
 {
-	unsigned char      msg[2];
-	unsigned char      *resp;
-	unsigned long      resp_len;
-	enum si_sm_result smi_result;
-	int               rv = 0;
+	unsigned char         msg[2];
+	unsigned char         *resp;
+	unsigned long         resp_len;
+	enum si_sm_result     smi_result;
+	int                   rv = 0;
 
 	resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
-	if (! resp)
+	if (!resp)
 		return -ENOMEM;
 
 	/* Do a Get Device ID command, since it comes back with some
@@ -1972,7 +1969,7 @@
 	/* Otherwise, we got some data. */
 	resp_len = smi_info->handlers->get_result(smi_info->si_sm,
 						  resp, IPMI_MAX_MSG_LENGTH);
-	if (resp_len < 6) {
+	if (resp_len < 14) {
 		/* That's odd, it should be longer. */
 		rv = -EINVAL;
 		goto out;
@@ -1985,8 +1982,7 @@
 	}
 
 	/* Record info from the get device id, in case we need it. */
-	memcpy(&smi_info->device_id, &resp[3],
-	       min_t(unsigned long, resp_len-3, sizeof(smi_info->device_id)));
+	ipmi_demangle_device_id(resp+3, resp_len-3, &smi_info->device_id);
 
  out:
 	kfree(resp);
@@ -2018,7 +2014,7 @@
 	struct smi_info *smi = data;
 
 	out += sprintf(out, "interrupts_enabled:    %d\n",
-		       smi->irq && ! smi->interrupt_disabled);
+		       smi->irq && !smi->interrupt_disabled);
 	out += sprintf(out, "short_timeouts:        %ld\n",
 		       smi->short_timeouts);
 	out += sprintf(out, "long_timeouts:         %ld\n",
@@ -2089,15 +2085,14 @@
 #define DELL_POWEREDGE_8G_BMC_DEVICE_ID  0x20
 #define DELL_POWEREDGE_8G_BMC_DEVICE_REV 0x80
 #define DELL_POWEREDGE_8G_BMC_IPMI_VERSION 0x51
-#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
+#define DELL_IANA_MFR_ID 0x0002a2
 static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info)
 {
 	struct ipmi_device_id *id = &smi_info->device_id;
-	const char mfr[3]=DELL_IANA_MFR_ID;
-	if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr))) {
+	if (id->manufacturer_id == DELL_IANA_MFR_ID) {
 		if (id->device_id       == DELL_POWEREDGE_8G_BMC_DEVICE_ID  &&
 		    id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV &&
-		    id->ipmi_version    == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) {
+		    id->ipmi_version   == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) {
 			smi_info->oem_data_avail_handler =
 				oem_data_avail_to_receive_msg_avail;
 		}
@@ -2169,8 +2164,7 @@
 setup_dell_poweredge_bt_xaction_handler(struct smi_info *smi_info)
 {
 	struct ipmi_device_id *id = &smi_info->device_id;
-	const char mfr[3]=DELL_IANA_MFR_ID;
- 	if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr)) &&
+	if (id->manufacturer_id == DELL_IANA_MFR_ID &&
 	    smi_info->si_type == SI_BT)
 		register_xaction_notifier(&dell_poweredge_bt_xaction_notifier);
 }
@@ -2195,67 +2189,119 @@
 
 static inline void wait_for_timer_and_thread(struct smi_info *smi_info)
 {
-	if (smi_info->thread != NULL && smi_info->thread != ERR_PTR(-ENOMEM))
-		kthread_stop(smi_info->thread);
-	del_timer_sync(&smi_info->si_timer);
+	if (smi_info->intf) {
+		/* The timer and thread are only running if the
+		   interface has been started up and registered. */
+		if (smi_info->thread != NULL)
+			kthread_stop(smi_info->thread);
+		del_timer_sync(&smi_info->si_timer);
+	}
 }
 
-/* Returns 0 if initialized, or negative on an error. */
-static int init_one_smi(int intf_num, struct smi_info **smi)
+static struct ipmi_default_vals
 {
-	int		rv;
-	struct smi_info *new_smi;
+	int type;
+	int port;
+} __devinit ipmi_defaults[] =
+{
+	{ .type = SI_KCS, .port = 0xca2 },
+	{ .type = SI_SMIC, .port = 0xca9 },
+	{ .type = SI_BT, .port = 0xe4 },
+	{ .port = 0 }
+};
 
+static __devinit void default_find_bmc(void)
+{
+	struct smi_info *info;
+	int             i;
 
-	rv = try_init_mem(intf_num, &new_smi);
-	if (rv)
-		rv = try_init_port(intf_num, &new_smi);
-#ifdef CONFIG_ACPI
-	if (rv && si_trydefaults)
-		rv = try_init_acpi(intf_num, &new_smi);
-#endif
-#ifdef CONFIG_DMI
-	if (rv && si_trydefaults)
-		rv = try_init_smbios(intf_num, &new_smi);
-#endif
-	if (rv && si_trydefaults)
-		rv = try_init_plug_and_play(intf_num, &new_smi);
+	for (i = 0; ; i++) {
+		if (!ipmi_defaults[i].port)
+			break;
 
-	if (rv)
-		return rv;
+		info = kzalloc(sizeof(*info), GFP_KERNEL);
+		if (!info)
+			return;
+
+		info->addr_source = NULL;
+
+		info->si_type = ipmi_defaults[i].type;
+		info->io_setup = port_setup;
+		info->io.addr_data = ipmi_defaults[i].port;
+		info->io.addr_type = IPMI_IO_ADDR_SPACE;
+
+		info->io.addr = NULL;
+		info->io.regspacing = DEFAULT_REGSPACING;
+		info->io.regsize = DEFAULT_REGSPACING;
+		info->io.regshift = 0;
+
+		if (try_smi_init(info) == 0) {
+			/* Found one... */
+			printk(KERN_INFO "ipmi_si: Found default %s state"
+			       " machine at %s address 0x%lx\n",
+			       si_to_str[info->si_type],
+			       addr_space_to_str[info->io.addr_type],
+			       info->io.addr_data);
+			return;
+		}
+	}
+}
+
+static int is_new_interface(struct smi_info *info)
+{
+	struct smi_info *e;
+
+	list_for_each_entry(e, &smi_infos, link) {
+		if (e->io.addr_type != info->io.addr_type)
+			continue;
+		if (e->io.addr_data == info->io.addr_data)
+			return 0;
+	}
+
+	return 1;
+}
+
+static int try_smi_init(struct smi_info *new_smi)
+{
+	int rv;
+
+	if (new_smi->addr_source) {
+		printk(KERN_INFO "ipmi_si: Trying %s-specified %s state"
+		       " machine at %s address 0x%lx, slave address 0x%x,"
+		       " irq %d\n",
+		       new_smi->addr_source,
+		       si_to_str[new_smi->si_type],
+		       addr_space_to_str[new_smi->io.addr_type],
+		       new_smi->io.addr_data,
+		       new_smi->slave_addr, new_smi->irq);
+	}
+
+	mutex_lock(&smi_infos_lock);
+	if (!is_new_interface(new_smi)) {
+		printk(KERN_WARNING "ipmi_si: duplicate interface\n");
+		rv = -EBUSY;
+		goto out_err;
+	}
 
 	/* So we know not to free it unless we have allocated one. */
 	new_smi->intf = NULL;
 	new_smi->si_sm = NULL;
 	new_smi->handlers = NULL;
 
-	if (! new_smi->irq_setup) {
-		new_smi->irq = irqs[intf_num];
-		new_smi->irq_setup = std_irq_setup;
-		new_smi->irq_cleanup = std_irq_cleanup;
-	}
-
-	/* Default to KCS if no type is specified. */
-	if (si_type[intf_num] == NULL) {
-		if (si_trydefaults)
-			si_type[intf_num] = "kcs";
-		else {
-			rv = -EINVAL;
-			goto out_err;
-		}
-	}
-
-	/* Set up the state machine to use. */
-	if (strcmp(si_type[intf_num], "kcs") == 0) {
+	switch (new_smi->si_type) {
+	case SI_KCS:
 		new_smi->handlers = &kcs_smi_handlers;
-		new_smi->si_type = SI_KCS;
-	} else if (strcmp(si_type[intf_num], "smic") == 0) {
+		break;
+
+	case SI_SMIC:
 		new_smi->handlers = &smic_smi_handlers;
-		new_smi->si_type = SI_SMIC;
-	} else if (strcmp(si_type[intf_num], "bt") == 0) {
+		break;
+
+	case SI_BT:
 		new_smi->handlers = &bt_smi_handlers;
-		new_smi->si_type = SI_BT;
-	} else {
+		break;
+
+	default:
 		/* No support for anything else yet. */
 		rv = -EIO;
 		goto out_err;
@@ -2263,7 +2309,7 @@
 
 	/* Allocate the state machine's data and initialize it. */
 	new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);
-	if (! new_smi->si_sm) {
+	if (!new_smi->si_sm) {
 		printk(" Could not allocate state machine memory\n");
 		rv = -ENOMEM;
 		goto out_err;
@@ -2284,21 +2330,29 @@
 
 	/* Do low-level detection first. */
 	if (new_smi->handlers->detect(new_smi->si_sm)) {
+		if (new_smi->addr_source)
+			printk(KERN_INFO "ipmi_si: Interface detection"
+			       " failed\n");
 		rv = -ENODEV;
 		goto out_err;
 	}
 
 	/* Attempt a get device id command.  If it fails, we probably
-           don't have a SMI here. */
+           don't have a BMC here. */
 	rv = try_get_dev_id(new_smi);
-	if (rv)
+	if (rv) {
+		if (new_smi->addr_source)
+			printk(KERN_INFO "ipmi_si: There appears to be no BMC"
+			       " at this location\n");
 		goto out_err;
+	}
 
 	setup_oem_data_handler(new_smi);
 	setup_xaction_handlers(new_smi);
 
 	/* Try to claim any interrupts. */
-	new_smi->irq_setup(new_smi);
+	if (new_smi->irq_setup)
+		new_smi->irq_setup(new_smi);
 
 	INIT_LIST_HEAD(&(new_smi->xmit_msgs));
 	INIT_LIST_HEAD(&(new_smi->hp_xmit_msgs));
@@ -2308,7 +2362,8 @@
 
 	new_smi->interrupt_disabled = 0;
 	atomic_set(&new_smi->stop_operation, 0);
-	new_smi->intf_num = intf_num;
+	new_smi->intf_num = smi_num;
+	smi_num++;
 
 	/* Start clearing the flags before we enable interrupts or the
 	   timer to avoid racing with the timer. */
@@ -2317,27 +2372,37 @@
 	if (new_smi->irq)
 		new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ;
 
-	/* The ipmi_register_smi() code does some operations to
-	   determine the channel information, so we must be ready to
-	   handle operations before it is called.  This means we have
-	   to stop the timer if we get an error after this point. */
-	init_timer(&(new_smi->si_timer));
-	new_smi->si_timer.data = (long) new_smi;
-	new_smi->si_timer.function = smi_timeout;
-	new_smi->last_timeout_jiffies = jiffies;
-	new_smi->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
+	if (!new_smi->dev) {
+		/* If we don't already have a device from something
+		 * else (like PCI), then register a new one. */
+		new_smi->pdev = platform_device_alloc("ipmi_si",
+						      new_smi->intf_num);
+		if (rv) {
+			printk(KERN_ERR
+			       "ipmi_si_intf:"
+			       " Unable to allocate platform device\n");
+			goto out_err;
+		}
+		new_smi->dev = &new_smi->pdev->dev;
+		new_smi->dev->driver = &ipmi_driver;
 
-	add_timer(&(new_smi->si_timer));
- 	if (new_smi->si_type != SI_BT)
-		new_smi->thread = kthread_run(ipmi_thread, new_smi,
-					      "kipmi%d", new_smi->intf_num);
+		rv = platform_device_register(new_smi->pdev);
+		if (rv) {
+			printk(KERN_ERR
+			       "ipmi_si_intf:"
+			       " Unable to register system interface device:"
+			       " %d\n",
+			       rv);
+			goto out_err;
+		}
+		new_smi->dev_registered = 1;
+	}
 
 	rv = ipmi_register_smi(&handlers,
 			       new_smi,
-			       ipmi_version_major(&new_smi->device_id),
-			       ipmi_version_minor(&new_smi->device_id),
-			       new_smi->slave_addr,
-			       &(new_smi->intf));
+			       &new_smi->device_id,
+			       new_smi->dev,
+			       new_smi->slave_addr);
 	if (rv) {
 		printk(KERN_ERR
 		       "ipmi_si: Unable to register device: error %d\n",
@@ -2365,9 +2430,11 @@
 		goto out_err_stop_timer;
 	}
 
-	*smi = new_smi;
+	list_add_tail(&new_smi->link, &smi_infos);
 
-	printk(" IPMI %s interface initialized\n", si_type[intf_num]);
+	mutex_unlock(&smi_infos_lock);
+
+	printk(" IPMI %s interface initialized\n",si_to_str[new_smi->si_type]);
 
 	return 0;
 
@@ -2379,7 +2446,8 @@
 	if (new_smi->intf)
 		ipmi_unregister_smi(new_smi->intf);
 
-	new_smi->irq_cleanup(new_smi);
+	if (new_smi->irq_cleanup)
+		new_smi->irq_cleanup(new_smi);
 
 	/* Wait until we know that we are out of any interrupt
 	   handlers might have been running before we freed the
@@ -2391,23 +2459,41 @@
 			new_smi->handlers->cleanup(new_smi->si_sm);
 		kfree(new_smi->si_sm);
 	}
+	if (new_smi->addr_source_cleanup)
+		new_smi->addr_source_cleanup(new_smi);
 	if (new_smi->io_cleanup)
 		new_smi->io_cleanup(new_smi);
 
+	if (new_smi->dev_registered)
+		platform_device_unregister(new_smi->pdev);
+
+	kfree(new_smi);
+
+	mutex_unlock(&smi_infos_lock);
+
 	return rv;
 }
 
-static __init int init_ipmi_si(void)
+static __devinit int init_ipmi_si(void)
 {
-	int  rv = 0;
-	int  pos = 0;
 	int  i;
 	char *str;
+	int  rv;
 
 	if (initialized)
 		return 0;
 	initialized = 1;
 
+	/* Register the device drivers. */
+	rv = driver_register(&ipmi_driver);
+	if (rv) {
+		printk(KERN_ERR
+		       "init_ipmi_si: Unable to register driver: %d\n",
+		       rv);
+		return rv;
+	}
+
+
 	/* Parse out the si_type string into its components. */
 	str = si_type_str;
 	if (*str != '\0') {
@@ -2425,63 +2511,66 @@
 
 	printk(KERN_INFO "IPMI System Interface driver.\n");
 
+	hardcode_find_bmc();
+
 #ifdef CONFIG_DMI
 	dmi_find_bmc();
 #endif
 
-	rv = init_one_smi(0, &(smi_infos[pos]));
-	if (rv && ! ports[0] && si_trydefaults) {
-		/* If we are trying defaults and the initial port is
-                   not set, then set it. */
-		si_type[0] = "kcs";
-		ports[0] = DEFAULT_KCS_IO_PORT;
-		rv = init_one_smi(0, &(smi_infos[pos]));
-		if (rv) {
-			/* No KCS - try SMIC */
-			si_type[0] = "smic";
-			ports[0] = DEFAULT_SMIC_IO_PORT;
-			rv = init_one_smi(0, &(smi_infos[pos]));
-		}
-		if (rv) {
-			/* No SMIC - try BT */
-			si_type[0] = "bt";
-			ports[0] = DEFAULT_BT_IO_PORT;
-			rv = init_one_smi(0, &(smi_infos[pos]));
+#ifdef CONFIG_ACPI
+	if (si_trydefaults)
+		acpi_find_bmc();
+#endif
+
+#ifdef CONFIG_PCI
+	pci_module_init(&ipmi_pci_driver);
+#endif
+
+	if (si_trydefaults) {
+		mutex_lock(&smi_infos_lock);
+		if (list_empty(&smi_infos)) {
+			/* No BMC was found, try defaults. */
+			mutex_unlock(&smi_infos_lock);
+			default_find_bmc();
+		} else {
+			mutex_unlock(&smi_infos_lock);
 		}
 	}
-	if (rv == 0)
-		pos++;
 
-	for (i = 1; i < SI_MAX_PARMS; i++) {
-		rv = init_one_smi(i, &(smi_infos[pos]));
-		if (rv == 0)
-			pos++;
-	}
-
-	if (smi_infos[0] == NULL) {
+	mutex_lock(&smi_infos_lock);
+	if (list_empty(&smi_infos)) {
+		mutex_unlock(&smi_infos_lock);
+#ifdef CONFIG_PCI
+		pci_unregister_driver(&ipmi_pci_driver);
+#endif
 		printk("ipmi_si: Unable to find any System Interface(s)\n");
 		return -ENODEV;
+	} else {
+		mutex_unlock(&smi_infos_lock);
+		return 0;
 	}
-
-	return 0;
 }
 module_init(init_ipmi_si);
 
-static void __exit cleanup_one_si(struct smi_info *to_clean)
+static void __devexit cleanup_one_si(struct smi_info *to_clean)
 {
 	int           rv;
 	unsigned long flags;
 
-	if (! to_clean)
+	if (!to_clean)
 		return;
 
+	list_del(&to_clean->link);
+
 	/* Tell the timer and interrupt handlers that we are shutting
 	   down. */
 	spin_lock_irqsave(&(to_clean->si_lock), flags);
 	spin_lock(&(to_clean->msg_lock));
 
 	atomic_inc(&to_clean->stop_operation);
-	to_clean->irq_cleanup(to_clean);
+
+	if (to_clean->irq_cleanup)
+		to_clean->irq_cleanup(to_clean);
 
 	spin_unlock(&(to_clean->msg_lock));
 	spin_unlock_irqrestore(&(to_clean->si_lock), flags);
@@ -2511,20 +2600,34 @@
 
 	kfree(to_clean->si_sm);
 
+	if (to_clean->addr_source_cleanup)
+		to_clean->addr_source_cleanup(to_clean);
 	if (to_clean->io_cleanup)
 		to_clean->io_cleanup(to_clean);
+
+	if (to_clean->dev_registered)
+		platform_device_unregister(to_clean->pdev);
+
+	kfree(to_clean);
 }
 
 static __exit void cleanup_ipmi_si(void)
 {
-	int i;
+	struct smi_info *e, *tmp_e;
 
-	if (! initialized)
+	if (!initialized)
 		return;
 
-	for (i = 0; i < SI_MAX_DRIVERS; i++) {
-		cleanup_one_si(smi_infos[i]);
-	}
+#ifdef CONFIG_PCI
+	pci_unregister_driver(&ipmi_pci_driver);
+#endif
+
+	mutex_lock(&smi_infos_lock);
+	list_for_each_entry_safe(e, tmp_e, &smi_infos, link)
+		cleanup_one_si(e);
+	mutex_unlock(&smi_infos_lock);
+
+	driver_unregister(&ipmi_driver);
 }
 module_exit(cleanup_ipmi_si);
 
diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h
index bf3d496..4b731b2 100644
--- a/drivers/char/ipmi/ipmi_si_sm.h
+++ b/drivers/char/ipmi/ipmi_si_sm.h
@@ -50,11 +50,12 @@
 
 	/* Generic info used by the actual handling routines, the
            state machine shouldn't touch these. */
-	void *info;
 	void __iomem *addr;
 	int  regspacing;
 	int  regsize;
 	int  regshift;
+	int addr_type;
+	long addr_data;
 };
 
 /* Results of SMI events. */
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 1f3159e..2d11ddd 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -39,6 +39,7 @@
 #include <linux/watchdog.h>
 #include <linux/miscdevice.h>
 #include <linux/init.h>
+#include <linux/completion.h>
 #include <linux/rwsem.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
@@ -303,21 +304,22 @@
 static void panic_halt_ipmi_heartbeat(void);
 
 
-/* We use a semaphore to make sure that only one thing can send a set
+/* We use a mutex to make sure that only one thing can send a set
    timeout at one time, because we only have one copy of the data.
-   The semaphore is claimed when the set_timeout is sent and freed
+   The mutex is claimed when the set_timeout is sent and freed
    when both messages are free. */
 static atomic_t set_timeout_tofree = ATOMIC_INIT(0);
-static DECLARE_MUTEX(set_timeout_lock);
+static DEFINE_MUTEX(set_timeout_lock);
+static DECLARE_COMPLETION(set_timeout_wait);
 static void set_timeout_free_smi(struct ipmi_smi_msg *msg)
 {
     if (atomic_dec_and_test(&set_timeout_tofree))
-	    up(&set_timeout_lock);
+	    complete(&set_timeout_wait);
 }
 static void set_timeout_free_recv(struct ipmi_recv_msg *msg)
 {
     if (atomic_dec_and_test(&set_timeout_tofree))
-	    up(&set_timeout_lock);
+	    complete(&set_timeout_wait);
 }
 static struct ipmi_smi_msg set_timeout_smi_msg =
 {
@@ -399,7 +401,7 @@
 
 
 	/* We can only send one of these at a time. */
-	down(&set_timeout_lock);
+	mutex_lock(&set_timeout_lock);
 
 	atomic_set(&set_timeout_tofree, 2);
 
@@ -407,16 +409,21 @@
 				&set_timeout_recv_msg,
 				&send_heartbeat_now);
 	if (rv) {
-		up(&set_timeout_lock);
-	} else {
-		if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB)
-		    || ((send_heartbeat_now)
-			&& (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY)))
-		{
-			rv = ipmi_heartbeat();
-		}
+		mutex_unlock(&set_timeout_lock);
+		goto out;
 	}
 
+	wait_for_completion(&set_timeout_wait);
+
+	if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB)
+	    || ((send_heartbeat_now)
+		&& (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY)))
+	{
+		rv = ipmi_heartbeat();
+	}
+	mutex_unlock(&set_timeout_lock);
+
+out:
 	return rv;
 }
 
@@ -458,17 +465,17 @@
    The semaphore is claimed when the set_timeout is sent and freed
    when both messages are free. */
 static atomic_t heartbeat_tofree = ATOMIC_INIT(0);
-static DECLARE_MUTEX(heartbeat_lock);
-static DECLARE_MUTEX_LOCKED(heartbeat_wait_lock);
+static DEFINE_MUTEX(heartbeat_lock);
+static DECLARE_COMPLETION(heartbeat_wait);
 static void heartbeat_free_smi(struct ipmi_smi_msg *msg)
 {
     if (atomic_dec_and_test(&heartbeat_tofree))
-	    up(&heartbeat_wait_lock);
+	    complete(&heartbeat_wait);
 }
 static void heartbeat_free_recv(struct ipmi_recv_msg *msg)
 {
     if (atomic_dec_and_test(&heartbeat_tofree))
-	    up(&heartbeat_wait_lock);
+	    complete(&heartbeat_wait);
 }
 static struct ipmi_smi_msg heartbeat_smi_msg =
 {
@@ -511,14 +518,14 @@
 		return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
 	}
 
-	down(&heartbeat_lock);
+	mutex_lock(&heartbeat_lock);
 
 	atomic_set(&heartbeat_tofree, 2);
 
 	/* Don't reset the timer if we have the timer turned off, that
            re-enables the watchdog. */
 	if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) {
-		up(&heartbeat_lock);
+		mutex_unlock(&heartbeat_lock);
 		return 0;
 	}
 
@@ -539,14 +546,14 @@
 				      &heartbeat_recv_msg,
 				      1);
 	if (rv) {
-		up(&heartbeat_lock);
+		mutex_unlock(&heartbeat_lock);
 		printk(KERN_WARNING PFX "heartbeat failure: %d\n",
 		       rv);
 		return rv;
 	}
 
 	/* Wait for the heartbeat to be sent. */
-	down(&heartbeat_wait_lock);
+	wait_for_completion(&heartbeat_wait);
 
 	if (heartbeat_recv_msg.msg.data[0] != 0) {
 	    /* Got an error in the heartbeat response.  It was already
@@ -555,7 +562,7 @@
 	    rv = -EINVAL;
 	}
 
-	up(&heartbeat_lock);
+	mutex_unlock(&heartbeat_lock);
 
 	return rv;
 }
@@ -589,7 +596,7 @@
 				 1);
 }
 
-static struct watchdog_info ident=
+static struct watchdog_info ident =
 {
 	.options	= 0,	/* WDIOF_SETTIMEOUT, */
 	.firmware_version = 1,
@@ -790,13 +797,13 @@
 
 static int ipmi_close(struct inode *ino, struct file *filep)
 {
-	if (iminor(ino)==WATCHDOG_MINOR)
-	{
+	if (iminor(ino) == WATCHDOG_MINOR) {
 		if (expect_close == 42) {
 			ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
 			ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
 		} else {
-			printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+			printk(KERN_CRIT PFX
+			       "Unexpected close, not stopping watchdog!\n");
 			ipmi_heartbeat();
 		}
 		clear_bit(0, &ipmi_wdog_open);
@@ -996,7 +1003,7 @@
 };
 
 
-static void ipmi_new_smi(int if_num)
+static void ipmi_new_smi(int if_num, struct device *device)
 {
 	ipmi_register_watchdog(if_num);
 }
@@ -1158,7 +1165,8 @@
 	}
 
 	register_reboot_notifier(&wdog_reboot_notifier);
-	notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier);
+	atomic_notifier_chain_register(&panic_notifier_list,
+			&wdog_panic_notifier);
 
 	printk(KERN_INFO PFX "driver initialized\n");
 
@@ -1176,7 +1184,8 @@
 		release_nmi(&ipmi_nmi_handler);
 #endif
 
-	notifier_chain_unregister(&panic_notifier_list, &wdog_panic_notifier);
+	atomic_notifier_chain_unregister(&panic_notifier_list,
+			&wdog_panic_notifier);
 	unregister_reboot_notifier(&wdog_reboot_notifier);
 
 	if (! watchdog_user)
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index e5247f8..ef20c1f 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -706,7 +706,6 @@
 static int	stli_clrportstats(stliport_t *portp, comstats_t __user *cp);
 static int	stli_getportstruct(stliport_t __user *arg);
 static int	stli_getbrdstruct(stlibrd_t __user *arg);
-static void	*stli_memalloc(int len);
 static stlibrd_t *stli_allocbrd(void);
 
 static void	stli_ecpinit(stlibrd_t *brdp);
@@ -997,17 +996,6 @@
 
 /*****************************************************************************/
 
-/*
- *	Local driver kernel malloc routine.
- */
-
-static void *stli_memalloc(int len)
-{
-	return((void *) kmalloc(len, GFP_KERNEL));
-}
-
-/*****************************************************************************/
-
 static int stli_open(struct tty_struct *tty, struct file *filp)
 {
 	stlibrd_t	*brdp;
@@ -3227,13 +3215,12 @@
 #endif
 
 	for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) {
-		portp = (stliport_t *) stli_memalloc(sizeof(stliport_t));
-		if (portp == (stliport_t *) NULL) {
+		portp = kzalloc(sizeof(stliport_t), GFP_KERNEL);
+		if (!portp) {
 			printk("STALLION: failed to allocate port structure\n");
 			continue;
 		}
 
-		memset(portp, 0, sizeof(stliport_t));
 		portp->magic = STLI_PORTMAGIC;
 		portp->portnr = i;
 		portp->brdnr = brdp->brdnr;
@@ -4610,14 +4597,13 @@
 {
 	stlibrd_t	*brdp;
 
-	brdp = (stlibrd_t *) stli_memalloc(sizeof(stlibrd_t));
-	if (brdp == (stlibrd_t *) NULL) {
+	brdp = kzalloc(sizeof(stlibrd_t), GFP_KERNEL);
+	if (!brdp) {
 		printk(KERN_ERR "STALLION: failed to allocate memory "
 				"(size=%d)\n", sizeof(stlibrd_t));
-		return((stlibrd_t *) NULL);
+		return NULL;
 	}
 
-	memset(brdp, 0, sizeof(stlibrd_t));
 	brdp->magic = STLI_BOARDMAGIC;
 	return(brdp);
 }
@@ -5210,12 +5196,12 @@
 /*
  *	Allocate a temporary write buffer.
  */
-	stli_tmpwritebuf = (char *) stli_memalloc(STLI_TXBUFSIZE);
-	if (stli_tmpwritebuf == (char *) NULL)
+	stli_tmpwritebuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
+	if (!stli_tmpwritebuf)
 		printk(KERN_ERR "STALLION: failed to allocate memory "
 				"(size=%d)\n", STLI_TXBUFSIZE);
-	stli_txcookbuf = stli_memalloc(STLI_TXBUFSIZE);
-	if (stli_txcookbuf == (char *) NULL)
+	stli_txcookbuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
+	if (!stli_txcookbuf)
 		printk(KERN_ERR "STALLION: failed to allocate memory "
 				"(size=%d)\n", STLI_TXBUFSIZE);
 
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 26d0116..66719f9 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -88,21 +88,15 @@
 }
 
 #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE
-static inline int valid_phys_addr_range(unsigned long addr, size_t *count)
+static inline int valid_phys_addr_range(unsigned long addr, size_t count)
 {
-	unsigned long end_mem;
-
-	end_mem = __pa(high_memory);
-	if (addr >= end_mem)
+	if (addr + count > __pa(high_memory))
 		return 0;
 
-	if (*count > end_mem - addr)
-		*count = end_mem - addr;
-
 	return 1;
 }
 
-static inline int valid_mmap_phys_addr_range(unsigned long addr, size_t *size)
+static inline int valid_mmap_phys_addr_range(unsigned long addr, size_t size)
 {
 	return 1;
 }
@@ -119,7 +113,7 @@
 	ssize_t read, sz;
 	char *ptr;
 
-	if (!valid_phys_addr_range(p, &count))
+	if (!valid_phys_addr_range(p, count))
 		return -EFAULT;
 	read = 0;
 #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
@@ -177,7 +171,7 @@
 	unsigned long copied;
 	void *ptr;
 
-	if (!valid_phys_addr_range(p, &count))
+	if (!valid_phys_addr_range(p, count))
 		return -EFAULT;
 
 	written = 0;
@@ -249,7 +243,7 @@
 {
 	size_t size = vma->vm_end - vma->vm_start;
 
-	if (!valid_mmap_phys_addr_range(vma->vm_pgoff << PAGE_SHIFT, &size))
+	if (!valid_mmap_phys_addr_range(vma->vm_pgoff << PAGE_SHIFT, size))
 		return -EINVAL;
 
 	vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
@@ -905,7 +899,7 @@
 	unsigned int		minor;
 	char			*name;
 	umode_t			mode;
-	struct file_operations	*fops;
+	const struct file_operations	*fops;
 } devlist[] = { /* list of minor devices */
 	{1, "mem",     S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
 	{2, "kmem",    S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 3e4c041..96eb2a7 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -129,7 +129,7 @@
 	int minor = iminor(inode);
 	struct miscdevice *c;
 	int err = -ENODEV;
-	struct file_operations *old_fops, *new_fops = NULL;
+	const struct file_operations *old_fops, *new_fops = NULL;
 	
 	down(&misc_sem);
 	
diff --git a/drivers/char/mxser.h b/drivers/char/mxser.h
index e7fd0b0..7e188a4 100644
--- a/drivers/char/mxser.h
+++ b/drivers/char/mxser.h
@@ -118,7 +118,7 @@
 
 // enable CTS interrupt
 #define MOXA_MUST_IER_ECTSI		0x80
-// eanble RTS interrupt
+// enable RTS interrupt
 #define MOXA_MUST_IER_ERTSI		0x40
 // enable Xon/Xoff interrupt
 #define MOXA_MUST_IER_XINT		0x20
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 3f5d607..a9c5a72 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -504,7 +504,6 @@
 static int	stl_echpciintr(stlbrd_t *brdp);
 static int	stl_echpci64intr(stlbrd_t *brdp);
 static void	stl_offintr(void *private);
-static void	*stl_memalloc(int len);
 static stlbrd_t *stl_allocbrd(void);
 static stlport_t *stl_getport(int brdnr, int panelnr, int portnr);
 
@@ -940,17 +939,6 @@
 /*****************************************************************************/
 
 /*
- *	Local driver kernel memory allocation routine.
- */
-
-static void *stl_memalloc(int len)
-{
-	return (void *) kmalloc(len, GFP_KERNEL);
-}
-
-/*****************************************************************************/
-
-/*
  *	Allocate a new board structure. Fill out the basic info in it.
  */
 
@@ -958,14 +946,13 @@
 {
 	stlbrd_t	*brdp;
 
-	brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
-	if (brdp == (stlbrd_t *) NULL) {
+	brdp = kzalloc(sizeof(stlbrd_t), GFP_KERNEL);
+	if (!brdp) {
 		printk("STALLION: failed to allocate memory (size=%d)\n",
 			sizeof(stlbrd_t));
-		return (stlbrd_t *) NULL;
+		return NULL;
 	}
 
-	memset(brdp, 0, sizeof(stlbrd_t));
 	brdp->magic = STL_BOARDMAGIC;
 	return brdp;
 }
@@ -1017,9 +1004,9 @@
 	portp->refcount++;
 
 	if ((portp->flags & ASYNC_INITIALIZED) == 0) {
-		if (portp->tx.buf == (char *) NULL) {
-			portp->tx.buf = (char *) stl_memalloc(STL_TXBUFSIZE);
-			if (portp->tx.buf == (char *) NULL)
+		if (!portp->tx.buf) {
+			portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
+			if (!portp->tx.buf)
 				return -ENOMEM;
 			portp->tx.head = portp->tx.buf;
 			portp->tx.tail = portp->tx.buf;
@@ -2178,13 +2165,12 @@
  *	each ports data structures.
  */
 	for (i = 0; (i < panelp->nrports); i++) {
-		portp = (stlport_t *) stl_memalloc(sizeof(stlport_t));
-		if (portp == (stlport_t *) NULL) {
+		portp = kzalloc(sizeof(stlport_t), GFP_KERNEL);
+		if (!portp) {
 			printk("STALLION: failed to allocate memory "
 				"(size=%d)\n", sizeof(stlport_t));
 			break;
 		}
-		memset(portp, 0, sizeof(stlport_t));
 
 		portp->magic = STL_PORTMAGIC;
 		portp->portnr = i;
@@ -2315,13 +2301,12 @@
  *	can complete the setup.
  */
 
-	panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t));
-	if (panelp == (stlpanel_t *) NULL) {
+	panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL);
+	if (!panelp) {
 		printk(KERN_WARNING "STALLION: failed to allocate memory "
 			"(size=%d)\n", sizeof(stlpanel_t));
-		return(-ENOMEM);
+		return -ENOMEM;
 	}
-	memset(panelp, 0, sizeof(stlpanel_t));
 
 	panelp->magic = STL_PANELMAGIC;
 	panelp->brdnr = brdp->brdnr;
@@ -2490,13 +2475,12 @@
 		status = inb(ioaddr + ECH_PNLSTATUS);
 		if ((status & ECH_PNLIDMASK) != nxtid)
 			break;
-		panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t));
-		if (panelp == (stlpanel_t *) NULL) {
+		panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL);
+		if (!panelp) {
 			printk("STALLION: failed to allocate memory "
 				"(size=%d)\n", sizeof(stlpanel_t));
 			break;
 		}
-		memset(panelp, 0, sizeof(stlpanel_t));
 		panelp->magic = STL_PANELMAGIC;
 		panelp->brdnr = brdp->brdnr;
 		panelp->panelnr = panelnr;
@@ -3074,8 +3058,8 @@
 /*
  *	Allocate a temporary write buffer.
  */
-	stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE);
-	if (stl_tmpwritebuf == (char *) NULL)
+	stl_tmpwritebuf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
+	if (!stl_tmpwritebuf)
 		printk("STALLION: failed to allocate memory (size=%d)\n",
 			STL_TXBUFSIZE);
 
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index d68be61..fee2aca 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -941,17 +941,6 @@
 	return mgsl_get_text_ptr;
 }
 
-/*
- * tmp_buf is used as a temporary buffer by mgsl_write.  We need to
- * lock it in case the COPY_FROM_USER blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ioports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-
 static inline int mgsl_paranoia_check(struct mgsl_struct *info,
 					char *name, const char *routine)
 {
@@ -2150,7 +2139,7 @@
 	if (mgsl_paranoia_check(info, tty->name, "mgsl_write"))
 		goto cleanup;
 
-	if (!tty || !info->xmit_buf || !tmp_buf)
+	if (!tty || !info->xmit_buf)
 		goto cleanup;
 
 	if ( info->params.mode == MGSL_MODE_HDLC ||
@@ -3438,7 +3427,6 @@
 {
 	struct mgsl_struct	*info;
 	int 			retval, line;
-	unsigned long		page;
 	unsigned long flags;
 
 	/* verify range of specified line number */	
@@ -3472,18 +3460,6 @@
 		goto cleanup;
 	}
 	
-	if (!tmp_buf) {
-		page = get_zeroed_page(GFP_KERNEL);
-		if (!page) {
-			retval = -ENOMEM;
-			goto cleanup;
-		}
-		if (tmp_buf)
-			free_page(page);
-		else
-			tmp_buf = (unsigned char *) page;
-	}
-	
 	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 	spin_lock_irqsave(&info->netlock, flags);
@@ -4502,11 +4478,6 @@
 		kfree(tmp);
 	}
 	
-	if (tmp_buf) {
-		free_page((unsigned long) tmp_buf);
-		tmp_buf = NULL;
-	}
-	
 	if (pci_registered)
 		pci_unregister_driver(&synclink_pci_driver);
 }
@@ -6025,7 +5996,7 @@
 	 * <15..8>	?		RxFIFO IRQ Request Level
 	 *
 	 * Note: For async mode the receive FIFO level must be set
-	 * to 0 to aviod the situation where the FIFO contains fewer bytes
+	 * to 0 to avoid the situation where the FIFO contains fewer bytes
 	 * than the trigger level and no more data is expected.
 	 *
 	 * <7>		0		Exited Hunt IA (Interrupt Arm)
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 738ec2f..b4d1f4e 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -1,5 +1,5 @@
 /*
- * $Id: synclink_gt.c,v 4.22 2006/01/09 20:16:06 paulkf Exp $
+ * $Id: synclink_gt.c,v 4.25 2006/02/06 21:20:33 paulkf Exp $
  *
  * Device driver for Microgate SyncLink GT serial adapters.
  *
@@ -92,7 +92,7 @@
  * module identification
  */
 static char *driver_name     = "SyncLink GT";
-static char *driver_version  = "$Revision: 4.22 $";
+static char *driver_version  = "$Revision: 4.25 $";
 static char *tty_driver_name = "synclink_gt";
 static char *tty_dev_prefix  = "ttySLG";
 MODULE_LICENSE("GPL");
@@ -188,6 +188,20 @@
 #define SLGT_REG_SIZE  256
 
 /*
+ * conditional wait facility
+ */
+struct cond_wait {
+	struct cond_wait *next;
+	wait_queue_head_t q;
+	wait_queue_t wait;
+	unsigned int data;
+};
+static void init_cond_wait(struct cond_wait *w, unsigned int data);
+static void add_cond_wait(struct cond_wait **head, struct cond_wait *w);
+static void remove_cond_wait(struct cond_wait **head, struct cond_wait *w);
+static void flush_cond_wait(struct cond_wait **head);
+
+/*
  * DMA buffer descriptor and access macros
  */
 struct slgt_desc
@@ -269,6 +283,9 @@
 	struct timer_list	tx_timer;
 	struct timer_list	rx_timer;
 
+	unsigned int            gpio_present;
+	struct cond_wait        *gpio_wait_q;
+
 	spinlock_t lock;	/* spinlock for synchronizing with ISR */
 
 	struct work_struct task;
@@ -379,6 +396,11 @@
 #define MASK_OVERRUN BIT4
 
 #define GSR   0x00 /* global status */
+#define JCR   0x04 /* JTAG control */
+#define IODR  0x08 /* GPIO direction */
+#define IOER  0x0c /* GPIO interrupt enable */
+#define IOVR  0x10 /* GPIO value */
+#define IOSR  0x14 /* GPIO interrupt status */
 #define TDR   0x80 /* tx data */
 #define RDR   0x80 /* rx data */
 #define TCR   0x82 /* tx control */
@@ -503,6 +525,9 @@
 static void set_break(struct tty_struct *tty, int break_state);
 static int  get_interface(struct slgt_info *info, int __user *if_mode);
 static int  set_interface(struct slgt_info *info, int if_mode);
+static int  set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
+static int  get_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
+static int  wait_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
 
 /*
  * driver functions
@@ -1112,6 +1137,12 @@
 		return get_interface(info, argp);
 	case MGSL_IOCSIF:
 		return set_interface(info,(int)arg);
+	case MGSL_IOCSGPIO:
+		return set_gpio(info, argp);
+	case MGSL_IOCGGPIO:
+		return get_gpio(info, argp);
+	case MGSL_IOCWAITGPIO:
+		return wait_gpio(info, argp);
 	case TIOCGICOUNT:
 		spin_lock_irqsave(&info->lock,flags);
 		cnow = info->icount;
@@ -1762,10 +1793,6 @@
 		DBGDATA(info, p, count, "rx");
 
 		for(i=0 ; i < count; i+=2, p+=2) {
-			if (tty && chars) {
-				tty_flip_buffer_push(tty);
-				chars = 0;
-			}
 			ch = *p;
 			icount->rx++;
 
@@ -2158,6 +2185,24 @@
 	}
 }
 
+static void isr_gpio(struct slgt_info *info, unsigned int changed, unsigned int state)
+{
+	struct cond_wait *w, *prev;
+
+	/* wake processes waiting for specific transitions */
+	for (w = info->gpio_wait_q, prev = NULL ; w != NULL ; w = w->next) {
+		if (w->data & changed) {
+			w->data = state;
+			wake_up_interruptible(&w->q);
+			if (prev != NULL)
+				prev->next = w->next;
+			else
+				info->gpio_wait_q = w->next;
+		} else
+			prev = w;
+	}
+}
+
 /* interrupt service routine
  *
  * 	irq	interrupt number
@@ -2193,6 +2238,22 @@
 		}
 	}
 
+	if (info->gpio_present) {
+		unsigned int state;
+		unsigned int changed;
+		while ((changed = rd_reg32(info, IOSR)) != 0) {
+			DBGISR(("%s iosr=%08x\n", info->device_name, changed));
+			/* read latched state of GPIO signals */
+			state = rd_reg32(info, IOVR);
+			/* clear pending GPIO interrupt bits */
+			wr_reg32(info, IOSR, changed);
+			for (i=0 ; i < info->port_count ; i++) {
+				if (info->port_array[i] != NULL)
+					isr_gpio(info->port_array[i], changed, state);
+			}
+		}
+	}
+
 	for(i=0; i < info->port_count ; i++) {
 		struct slgt_info *port = info->port_array[i];
 
@@ -2276,6 +2337,8 @@
 		set_signals(info);
 	}
 
+	flush_cond_wait(&info->gpio_wait_q);
+
 	spin_unlock_irqrestore(&info->lock,flags);
 
 	if (info->tty)
@@ -2650,6 +2713,175 @@
 	return 0;
 }
 
+/*
+ * set general purpose IO pin state and direction
+ *
+ * user_gpio fields:
+ * state   each bit indicates a pin state
+ * smask   set bit indicates pin state to set
+ * dir     each bit indicates a pin direction (0=input, 1=output)
+ * dmask   set bit indicates pin direction to set
+ */
+static int set_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
+{
+ 	unsigned long flags;
+	struct gpio_desc gpio;
+	__u32 data;
+
+	if (!info->gpio_present)
+		return -EINVAL;
+	if (copy_from_user(&gpio, user_gpio, sizeof(gpio)))
+		return -EFAULT;
+	DBGINFO(("%s set_gpio state=%08x smask=%08x dir=%08x dmask=%08x\n",
+		 info->device_name, gpio.state, gpio.smask,
+		 gpio.dir, gpio.dmask));
+
+	spin_lock_irqsave(&info->lock,flags);
+	if (gpio.dmask) {
+		data = rd_reg32(info, IODR);
+		data |= gpio.dmask & gpio.dir;
+		data &= ~(gpio.dmask & ~gpio.dir);
+		wr_reg32(info, IODR, data);
+	}
+	if (gpio.smask) {
+		data = rd_reg32(info, IOVR);
+		data |= gpio.smask & gpio.state;
+		data &= ~(gpio.smask & ~gpio.state);
+		wr_reg32(info, IOVR, data);
+	}
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	return 0;
+}
+
+/*
+ * get general purpose IO pin state and direction
+ */
+static int get_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
+{
+	struct gpio_desc gpio;
+	if (!info->gpio_present)
+		return -EINVAL;
+	gpio.state = rd_reg32(info, IOVR);
+	gpio.smask = 0xffffffff;
+	gpio.dir   = rd_reg32(info, IODR);
+	gpio.dmask = 0xffffffff;
+	if (copy_to_user(user_gpio, &gpio, sizeof(gpio)))
+		return -EFAULT;
+	DBGINFO(("%s get_gpio state=%08x dir=%08x\n",
+		 info->device_name, gpio.state, gpio.dir));
+	return 0;
+}
+
+/*
+ * conditional wait facility
+ */
+static void init_cond_wait(struct cond_wait *w, unsigned int data)
+{
+	init_waitqueue_head(&w->q);
+	init_waitqueue_entry(&w->wait, current);
+	w->data = data;
+}
+
+static void add_cond_wait(struct cond_wait **head, struct cond_wait *w)
+{
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&w->q, &w->wait);
+	w->next = *head;
+	*head = w;
+}
+
+static void remove_cond_wait(struct cond_wait **head, struct cond_wait *cw)
+{
+	struct cond_wait *w, *prev;
+	remove_wait_queue(&cw->q, &cw->wait);
+	set_current_state(TASK_RUNNING);
+	for (w = *head, prev = NULL ; w != NULL ; prev = w, w = w->next) {
+		if (w == cw) {
+			if (prev != NULL)
+				prev->next = w->next;
+			else
+				*head = w->next;
+			break;
+		}
+	}
+}
+
+static void flush_cond_wait(struct cond_wait **head)
+{
+	while (*head != NULL) {
+		wake_up_interruptible(&(*head)->q);
+		*head = (*head)->next;
+	}
+}
+
+/*
+ * wait for general purpose I/O pin(s) to enter specified state
+ *
+ * user_gpio fields:
+ * state - bit indicates target pin state
+ * smask - set bit indicates watched pin
+ *
+ * The wait ends when at least one watched pin enters the specified
+ * state. When 0 (no error) is returned, user_gpio->state is set to the
+ * state of all GPIO pins when the wait ends.
+ *
+ * Note: Each pin may be a dedicated input, dedicated output, or
+ * configurable input/output. The number and configuration of pins
+ * varies with the specific adapter model. Only input pins (dedicated
+ * or configured) can be monitored with this function.
+ */
+static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
+{
+ 	unsigned long flags;
+	int rc = 0;
+	struct gpio_desc gpio;
+	struct cond_wait wait;
+	u32 state;
+
+	if (!info->gpio_present)
+		return -EINVAL;
+	if (copy_from_user(&gpio, user_gpio, sizeof(gpio)))
+		return -EFAULT;
+	DBGINFO(("%s wait_gpio() state=%08x smask=%08x\n",
+		 info->device_name, gpio.state, gpio.smask));
+	/* ignore output pins identified by set IODR bit */
+	if ((gpio.smask &= ~rd_reg32(info, IODR)) == 0)
+		return -EINVAL;
+	init_cond_wait(&wait, gpio.smask);
+
+	spin_lock_irqsave(&info->lock, flags);
+	/* enable interrupts for watched pins */
+	wr_reg32(info, IOER, rd_reg32(info, IOER) | gpio.smask);
+	/* get current pin states */
+	state = rd_reg32(info, IOVR);
+
+	if (gpio.smask & ~(state ^ gpio.state)) {
+		/* already in target state */
+		gpio.state = state;
+	} else {
+		/* wait for target state */
+		add_cond_wait(&info->gpio_wait_q, &wait);
+		spin_unlock_irqrestore(&info->lock, flags);
+		schedule();
+		if (signal_pending(current))
+			rc = -ERESTARTSYS;
+		else
+			gpio.state = wait.data;
+		spin_lock_irqsave(&info->lock, flags);
+		remove_cond_wait(&info->gpio_wait_q, &wait);
+	}
+
+	/* disable all GPIO interrupts if no waiting processes */
+	if (info->gpio_wait_q == NULL)
+		wr_reg32(info, IOER, 0);
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	if ((rc == 0) && copy_to_user(user_gpio, &gpio, sizeof(gpio)))
+		rc = -EFAULT;
+	return rc;
+}
+
 static int modem_input_wait(struct slgt_info *info,int arg)
 {
  	unsigned long flags;
@@ -3166,8 +3398,10 @@
 		} else {
 			port_array[0]->irq_requested = 1;
 			adapter_test(port_array[0]);
-			for (i=1 ; i < port_count ; i++)
+			for (i=1 ; i < port_count ; i++) {
 				port_array[i]->init_error = port_array[0]->init_error;
+				port_array[i]->gpio_present = port_array[0]->gpio_present;
+			}
 		}
 	}
 }
@@ -4301,7 +4535,7 @@
 			break;
 		}
 	}
-
+	info->gpio_present = (rd_reg32(info, JCR) & BIT5) ? 1 : 0;
 	info->init_error = rc ? 0 : DiagStatus_AddressFailure;
 	return rc;
 }
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index 4c27218..2546637 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -767,6 +767,7 @@
 		printk(KERN_ERR "tlclk: can't get major %d.\n", tlclk_major);
 		return ret;
 	}
+	tlclk_major = ret;
 	alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL);
 	if (!alarm_events)
 		goto out1;
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 48d795b..98b126c 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -376,7 +376,7 @@
 	return copied;
 }
 
-EXPORT_SYMBOL_GPL(tty_insert_flip_string);
+EXPORT_SYMBOL(tty_insert_flip_string);
 
 int tty_insert_flip_string_flags(struct tty_struct *tty, const unsigned char *chars, const char *flags, size_t size)
 {
@@ -543,14 +543,12 @@
 	struct tty_ldisc *ld;
 	unsigned long flags;
 	
-	if (disc < N_TTY || disc >= NR_LDISCS)
-		BUG();
+	BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
 		
 	spin_lock_irqsave(&tty_ldisc_lock, flags);
 	ld = &tty_ldiscs[disc];
-	if(ld->refcount == 0)
-		BUG();
-	ld->refcount --;
+	BUG_ON(ld->refcount == 0);
+	ld->refcount--;
 	module_put(ld->owner);
 	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 }
@@ -645,8 +643,7 @@
 {
 	unsigned long flags;
 
-	if(ld == NULL)
-		BUG();
+	BUG_ON(ld == NULL);
 		
 	spin_lock_irqsave(&tty_ldisc_lock, flags);
 	if(ld->refcount == 0)
@@ -1097,8 +1094,8 @@
 				p->signal->tty = NULL;
 			if (!p->signal->leader)
 				continue;
-			send_group_sig_info(SIGHUP, SEND_SIG_PRIV, p);
-			send_group_sig_info(SIGCONT, SEND_SIG_PRIV, p);
+			group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+			group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
 			if (tty->pgrp > 0)
 				p->signal->tty_old_pgrp = tty->pgrp;
 		} while_each_task_pid(tty->session, PIDTYPE_SID, p);
@@ -2675,7 +2672,7 @@
 	tty_hangup(tty);
 #else
 	struct tty_struct *tty = arg;
-	struct task_struct *p;
+	struct task_struct *g, *p;
 	int session;
 	int		i;
 	struct file	*filp;
@@ -2696,8 +2693,18 @@
 		tty->driver->flush_buffer(tty);
 	
 	read_lock(&tasklist_lock);
+	/* Kill the entire session */
 	do_each_task_pid(session, PIDTYPE_SID, p) {
-		if (p->signal->tty == tty || session > 0) {
+		printk(KERN_NOTICE "SAK: killed process %d"
+			" (%s): p->signal->session==tty->session\n",
+			p->pid, p->comm);
+		send_sig(SIGKILL, p, 1);
+	} while_each_task_pid(session, PIDTYPE_SID, p);
+	/* Now kill any processes that happen to have the
+	 * tty open.
+	 */
+	do_each_thread(g, p) {
+		if (p->signal->tty == tty) {
 			printk(KERN_NOTICE "SAK: killed process %d"
 			    " (%s): p->signal->session==tty->session\n",
 			    p->pid, p->comm);
@@ -2724,7 +2731,7 @@
 			rcu_read_unlock();
 		}
 		task_unlock(p);
-	} while_each_task_pid(session, PIDTYPE_SID, p);
+	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
 #endif
 }
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index ca4844c..acc5d47 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -2328,6 +2328,10 @@
 		case TIOCL_SETVESABLANK:
 			set_vesa_blanking(p);
 			break;
+		case TIOCL_GETKMSGREDIRECT:
+			data = kmsg_redirect;
+			ret = __put_user(data, p);
+			break;
 		case TIOCL_SETKMSGREDIRECT:
 			if (!capable(CAP_SYS_ADMIN)) {
 				ret = -EPERM;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index aed80e6..9b6ae7d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -52,9 +52,8 @@
  * changes to devices when the CPU clock speed changes.
  * The mutex locks both lists.
  */
-static struct notifier_block *cpufreq_policy_notifier_list;
-static struct notifier_block *cpufreq_transition_notifier_list;
-static DECLARE_RWSEM (cpufreq_notifier_rwsem);
+static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
+static BLOCKING_NOTIFIER_HEAD(cpufreq_transition_notifier_list);
 
 
 static LIST_HEAD(cpufreq_governor_list);
@@ -247,8 +246,6 @@
 	dprintk("notification %u of frequency transition to %u kHz\n",
 		state, freqs->new);
 
-	down_read(&cpufreq_notifier_rwsem);
-
 	policy = cpufreq_cpu_data[freqs->cpu];
 	switch (state) {
 
@@ -266,20 +263,19 @@
 				freqs->old = policy->cur;
 			}
 		}
-		notifier_call_chain(&cpufreq_transition_notifier_list,
-					CPUFREQ_PRECHANGE, freqs);
+		blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+				CPUFREQ_PRECHANGE, freqs);
 		adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
 		break;
 
 	case CPUFREQ_POSTCHANGE:
 		adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
-		notifier_call_chain(&cpufreq_transition_notifier_list,
-					CPUFREQ_POSTCHANGE, freqs);
+		blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+				CPUFREQ_POSTCHANGE, freqs);
 		if (likely(policy) && likely(policy->cpu == freqs->cpu))
 			policy->cur = freqs->new;
 		break;
 	}
-	up_read(&cpufreq_notifier_rwsem);
 }
 EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
 
@@ -1007,7 +1003,7 @@
 		freqs.old = cpu_policy->cur;
 		freqs.new = cur_freq;
 
-		notifier_call_chain(&cpufreq_transition_notifier_list,
+		blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
 				    CPUFREQ_SUSPENDCHANGE, &freqs);
 		adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs);
 
@@ -1088,7 +1084,8 @@
 			freqs.old = cpu_policy->cur;
 			freqs.new = cur_freq;
 
-			notifier_call_chain(&cpufreq_transition_notifier_list,
+			blocking_notifier_call_chain(
+					&cpufreq_transition_notifier_list,
 					CPUFREQ_RESUMECHANGE, &freqs);
 			adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
 
@@ -1125,24 +1122,24 @@
  *      changes in cpufreq policy.
  *
  *	This function may sleep, and has the same return conditions as
- *	notifier_chain_register.
+ *	blocking_notifier_chain_register.
  */
 int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
 {
 	int ret;
 
-	down_write(&cpufreq_notifier_rwsem);
 	switch (list) {
 	case CPUFREQ_TRANSITION_NOTIFIER:
-		ret = notifier_chain_register(&cpufreq_transition_notifier_list, nb);
+		ret = blocking_notifier_chain_register(
+				&cpufreq_transition_notifier_list, nb);
 		break;
 	case CPUFREQ_POLICY_NOTIFIER:
-		ret = notifier_chain_register(&cpufreq_policy_notifier_list, nb);
+		ret = blocking_notifier_chain_register(
+				&cpufreq_policy_notifier_list, nb);
 		break;
 	default:
 		ret = -EINVAL;
 	}
-	up_write(&cpufreq_notifier_rwsem);
 
 	return ret;
 }
@@ -1157,24 +1154,24 @@
  *	Remove a driver from the CPU frequency notifier list.
  *
  *	This function may sleep, and has the same return conditions as
- *	notifier_chain_unregister.
+ *	blocking_notifier_chain_unregister.
  */
 int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list)
 {
 	int ret;
 
-	down_write(&cpufreq_notifier_rwsem);
 	switch (list) {
 	case CPUFREQ_TRANSITION_NOTIFIER:
-		ret = notifier_chain_unregister(&cpufreq_transition_notifier_list, nb);
+		ret = blocking_notifier_chain_unregister(
+				&cpufreq_transition_notifier_list, nb);
 		break;
 	case CPUFREQ_POLICY_NOTIFIER:
-		ret = notifier_chain_unregister(&cpufreq_policy_notifier_list, nb);
+		ret = blocking_notifier_chain_unregister(
+				&cpufreq_policy_notifier_list, nb);
 		break;
 	default:
 		ret = -EINVAL;
 	}
-	up_write(&cpufreq_notifier_rwsem);
 
 	return ret;
 }
@@ -1346,29 +1343,23 @@
 	if (ret)
 		goto error_out;
 
-	down_read(&cpufreq_notifier_rwsem);
-
 	/* adjust if necessary - all reasons */
-	notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST,
-			    policy);
+	blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
+			CPUFREQ_ADJUST, policy);
 
 	/* adjust if necessary - hardware incompatibility*/
-	notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_INCOMPATIBLE,
-			    policy);
+	blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
+			CPUFREQ_INCOMPATIBLE, policy);
 
 	/* verify the cpu speed can be set within this limit,
 	   which might be different to the first one */
 	ret = cpufreq_driver->verify(policy);
-	if (ret) {
-		up_read(&cpufreq_notifier_rwsem);
+	if (ret)
 		goto error_out;
-	}
 
 	/* notification of the new policy */
-	notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY,
-			    policy);
-
-	up_read(&cpufreq_notifier_rwsem);
+	blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
+			CPUFREQ_NOTIFY, policy);
 
 	data->min = policy->min;
 	data->max = policy->max;
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index ac38766..037f6bf 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -35,12 +35,7 @@
  */
 
 #define DEF_FREQUENCY_UP_THRESHOLD		(80)
-#define MIN_FREQUENCY_UP_THRESHOLD		(0)
-#define MAX_FREQUENCY_UP_THRESHOLD		(100)
-
 #define DEF_FREQUENCY_DOWN_THRESHOLD		(20)
-#define MIN_FREQUENCY_DOWN_THRESHOLD		(0)
-#define MAX_FREQUENCY_DOWN_THRESHOLD		(100)
 
 /* 
  * The polling frequency of this governor depends on the capability of 
@@ -53,10 +48,14 @@
  * All times here are in uS.
  */
 static unsigned int 				def_sampling_rate;
-#define MIN_SAMPLING_RATE			(def_sampling_rate / 2)
+#define MIN_SAMPLING_RATE_RATIO			(2)
+/* for correct statistics, we need at least 10 ticks between each measure */
+#define MIN_STAT_SAMPLING_RATE			(MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10))
+#define MIN_SAMPLING_RATE			(def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
 #define MAX_SAMPLING_RATE			(500 * def_sampling_rate)
-#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER	(100000)
-#define DEF_SAMPLING_DOWN_FACTOR		(5)
+#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER	(1000)
+#define DEF_SAMPLING_DOWN_FACTOR		(1)
+#define MAX_SAMPLING_DOWN_FACTOR		(10)
 #define TRANSITION_LATENCY_LIMIT		(10 * 1000)
 
 static void do_dbs_timer(void *data);
@@ -66,6 +65,8 @@
 	unsigned int 		prev_cpu_idle_up;
 	unsigned int 		prev_cpu_idle_down;
 	unsigned int 		enable;
+	unsigned int		down_skip;
+	unsigned int		requested_freq;
 };
 static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
 
@@ -87,6 +88,8 @@
 	.up_threshold 		= DEF_FREQUENCY_UP_THRESHOLD,
 	.down_threshold 	= DEF_FREQUENCY_DOWN_THRESHOLD,
 	.sampling_down_factor 	= DEF_SAMPLING_DOWN_FACTOR,
+	.ignore_nice		= 0,
+	.freq_step		= 5,
 };
 
 static inline unsigned int get_cpu_idle_time(unsigned int cpu)
@@ -136,7 +139,7 @@
 	unsigned int input;
 	int ret;
 	ret = sscanf (buf, "%u", &input);
-	if (ret != 1 )
+	if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
 		return -EINVAL;
 
 	mutex_lock(&dbs_mutex);
@@ -173,8 +176,7 @@
 	ret = sscanf (buf, "%u", &input);
 
 	mutex_lock(&dbs_mutex);
-	if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || 
-			input < MIN_FREQUENCY_UP_THRESHOLD ||
+	if (ret != 1 || input > 100 || input < 0 ||
 			input <= dbs_tuners_ins.down_threshold) {
 		mutex_unlock(&dbs_mutex);
 		return -EINVAL;
@@ -194,8 +196,7 @@
 	ret = sscanf (buf, "%u", &input);
 
 	mutex_lock(&dbs_mutex);
-	if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD || 
-			input < MIN_FREQUENCY_DOWN_THRESHOLD ||
+	if (ret != 1 || input > 100 || input < 0 ||
 			input >= dbs_tuners_ins.up_threshold) {
 		mutex_unlock(&dbs_mutex);
 		return -EINVAL;
@@ -297,31 +298,17 @@
 static void dbs_check_cpu(int cpu)
 {
 	unsigned int idle_ticks, up_idle_ticks, down_idle_ticks;
+	unsigned int tmp_idle_ticks, total_idle_ticks;
 	unsigned int freq_step;
 	unsigned int freq_down_sampling_rate;
-	static int down_skip[NR_CPUS];
-	static int requested_freq[NR_CPUS];
-	static unsigned short init_flag = 0;
-	struct cpu_dbs_info_s *this_dbs_info;
-	struct cpu_dbs_info_s *dbs_info;
-
+	struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
 	struct cpufreq_policy *policy;
-	unsigned int j;
 
-	this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
 	if (!this_dbs_info->enable)
 		return;
 
 	policy = this_dbs_info->cur_policy;
 
-	if ( init_flag == 0 ) {
-		for_each_online_cpu(j) {
-			dbs_info = &per_cpu(cpu_dbs_info, j);
-			requested_freq[j] = dbs_info->cur_policy->cur;
-		}
-		init_flag = 1;
-	}
-	
 	/* 
 	 * The default safe range is 20% to 80% 
 	 * Every sampling_rate, we check
@@ -337,39 +324,29 @@
 	 */
 
 	/* Check for frequency increase */
-
 	idle_ticks = UINT_MAX;
-	for_each_cpu_mask(j, policy->cpus) {
-		unsigned int tmp_idle_ticks, total_idle_ticks;
-		struct cpu_dbs_info_s *j_dbs_info;
 
-		j_dbs_info = &per_cpu(cpu_dbs_info, j);
-		/* Check for frequency increase */
-		total_idle_ticks = get_cpu_idle_time(j);
-		tmp_idle_ticks = total_idle_ticks -
-			j_dbs_info->prev_cpu_idle_up;
-		j_dbs_info->prev_cpu_idle_up = total_idle_ticks;
+	/* Check for frequency increase */
+	total_idle_ticks = get_cpu_idle_time(cpu);
+	tmp_idle_ticks = total_idle_ticks -
+		this_dbs_info->prev_cpu_idle_up;
+	this_dbs_info->prev_cpu_idle_up = total_idle_ticks;
 
-		if (tmp_idle_ticks < idle_ticks)
-			idle_ticks = tmp_idle_ticks;
-	}
+	if (tmp_idle_ticks < idle_ticks)
+		idle_ticks = tmp_idle_ticks;
 
 	/* Scale idle ticks by 100 and compare with up and down ticks */
 	idle_ticks *= 100;
 	up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) *
-		usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+			usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
 
 	if (idle_ticks < up_idle_ticks) {
-		down_skip[cpu] = 0;
-		for_each_cpu_mask(j, policy->cpus) {
-			struct cpu_dbs_info_s *j_dbs_info;
+		this_dbs_info->down_skip = 0;
+		this_dbs_info->prev_cpu_idle_down =
+			this_dbs_info->prev_cpu_idle_up;
 
-			j_dbs_info = &per_cpu(cpu_dbs_info, j);
-			j_dbs_info->prev_cpu_idle_down = 
-					j_dbs_info->prev_cpu_idle_up;
-		}
 		/* if we are already at full speed then break out early */
-		if (requested_freq[cpu] == policy->max)
+		if (this_dbs_info->requested_freq == policy->max)
 			return;
 		
 		freq_step = (dbs_tuners_ins.freq_step * policy->max) / 100;
@@ -378,49 +355,45 @@
 		if (unlikely(freq_step == 0))
 			freq_step = 5;
 		
-		requested_freq[cpu] += freq_step;
-		if (requested_freq[cpu] > policy->max)
-			requested_freq[cpu] = policy->max;
+		this_dbs_info->requested_freq += freq_step;
+		if (this_dbs_info->requested_freq > policy->max)
+			this_dbs_info->requested_freq = policy->max;
 
-		__cpufreq_driver_target(policy, requested_freq[cpu], 
+		__cpufreq_driver_target(policy, this_dbs_info->requested_freq,
 			CPUFREQ_RELATION_H);
 		return;
 	}
 
 	/* Check for frequency decrease */
-	down_skip[cpu]++;
-	if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor)
+	this_dbs_info->down_skip++;
+	if (this_dbs_info->down_skip < dbs_tuners_ins.sampling_down_factor)
 		return;
 
-	idle_ticks = UINT_MAX;
-	for_each_cpu_mask(j, policy->cpus) {
-		unsigned int tmp_idle_ticks, total_idle_ticks;
-		struct cpu_dbs_info_s *j_dbs_info;
+	/* Check for frequency decrease */
+	total_idle_ticks = this_dbs_info->prev_cpu_idle_up;
+	tmp_idle_ticks = total_idle_ticks -
+		this_dbs_info->prev_cpu_idle_down;
+	this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
 
-		j_dbs_info = &per_cpu(cpu_dbs_info, j);
-		total_idle_ticks = j_dbs_info->prev_cpu_idle_up;
-		tmp_idle_ticks = total_idle_ticks -
-			j_dbs_info->prev_cpu_idle_down;
-		j_dbs_info->prev_cpu_idle_down = total_idle_ticks;
-
-		if (tmp_idle_ticks < idle_ticks)
-			idle_ticks = tmp_idle_ticks;
-	}
+	if (tmp_idle_ticks < idle_ticks)
+		idle_ticks = tmp_idle_ticks;
 
 	/* Scale idle ticks by 100 and compare with up and down ticks */
 	idle_ticks *= 100;
-	down_skip[cpu] = 0;
+	this_dbs_info->down_skip = 0;
 
 	freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
 		dbs_tuners_ins.sampling_down_factor;
 	down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) *
-			usecs_to_jiffies(freq_down_sampling_rate);
+		usecs_to_jiffies(freq_down_sampling_rate);
 
 	if (idle_ticks > down_idle_ticks) {
-		/* if we are already at the lowest speed then break out early
+		/*
+		 * if we are already at the lowest speed then break out early
 		 * or if we 'cannot' reduce the speed as the user might want
-		 * freq_step to be zero */
-		if (requested_freq[cpu] == policy->min
+		 * freq_step to be zero
+		 */
+		if (this_dbs_info->requested_freq == policy->min
 				|| dbs_tuners_ins.freq_step == 0)
 			return;
 
@@ -430,13 +403,12 @@
 		if (unlikely(freq_step == 0))
 			freq_step = 5;
 
-		requested_freq[cpu] -= freq_step;
-		if (requested_freq[cpu] < policy->min)
-			requested_freq[cpu] = policy->min;
+		this_dbs_info->requested_freq -= freq_step;
+		if (this_dbs_info->requested_freq < policy->min)
+			this_dbs_info->requested_freq = policy->min;
 
-		__cpufreq_driver_target(policy,
-			requested_freq[cpu],
-			CPUFREQ_RELATION_H);
+		__cpufreq_driver_target(policy, this_dbs_info->requested_freq,
+				CPUFREQ_RELATION_H);
 		return;
 	}
 }
@@ -493,11 +465,13 @@
 			j_dbs_info = &per_cpu(cpu_dbs_info, j);
 			j_dbs_info->cur_policy = policy;
 		
-			j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
+			j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(cpu);
 			j_dbs_info->prev_cpu_idle_down
 				= j_dbs_info->prev_cpu_idle_up;
 		}
 		this_dbs_info->enable = 1;
+		this_dbs_info->down_skip = 0;
+		this_dbs_info->requested_freq = policy->cur;
 		sysfs_create_group(&policy->kobj, &dbs_attr_group);
 		dbs_enable++;
 		/*
@@ -507,16 +481,17 @@
 		if (dbs_enable == 1) {
 			unsigned int latency;
 			/* policy latency is in nS. Convert it to uS first */
+			latency = policy->cpuinfo.transition_latency / 1000;
+			if (latency == 0)
+				latency = 1;
 
-			latency = policy->cpuinfo.transition_latency;
-			if (latency < 1000)
-				latency = 1000;
-
-			def_sampling_rate = (latency / 1000) *
+			def_sampling_rate = 10 * latency *
 					DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
+
+			if (def_sampling_rate < MIN_STAT_SAMPLING_RATE)
+				def_sampling_rate = MIN_STAT_SAMPLING_RATE;
+
 			dbs_tuners_ins.sampling_rate = def_sampling_rate;
-			dbs_tuners_ins.ignore_nice = 0;
-			dbs_tuners_ins.freq_step = 5;
 
 			dbs_timer_init();
 		}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 69aa1db..956d121 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -84,6 +84,7 @@
 static struct dbs_tuners dbs_tuners_ins = {
 	.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
 	.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
+	.ignore_nice = 0,
 };
 
 static inline unsigned int get_cpu_idle_time(unsigned int cpu)
@@ -350,6 +351,9 @@
 	freq_next = (freq_next * policy->cur) /
 			(dbs_tuners_ins.up_threshold - 10);
 
+	if (freq_next < policy->min)
+		freq_next = policy->min;
+
 	if (freq_next <= ((policy->cur * 95) / 100))
 		__cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L);
 }
@@ -395,8 +399,11 @@
 			return -EINVAL;
 
 		if (policy->cpuinfo.transition_latency >
-				(TRANSITION_LATENCY_LIMIT * 1000))
+				(TRANSITION_LATENCY_LIMIT * 1000)) {
+			printk(KERN_WARNING "ondemand governor failed to load "
+			       "due to too long transition latency\n");
 			return -EINVAL;
+		}
 		if (this_dbs_info->enable) /* Already enabled */
 			break;
 
@@ -431,8 +438,6 @@
 				def_sampling_rate = MIN_STAT_SAMPLING_RATE;
 
 			dbs_tuners_ins.sampling_rate = def_sampling_rate;
-			dbs_tuners_ins.ignore_nice = 0;
-
 			dbs_timer_init();
 		}
 
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 52f3eb4..4f08984 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -64,35 +64,35 @@
 
 config EDAC_E7XXX
 	tristate "Intel e7xxx (e7205, e7500, e7501, e7505)"
-	depends on EDAC_MM_EDAC && PCI
+	depends on EDAC_MM_EDAC && PCI && X86_32
 	help
 	  Support for error detection and correction on the Intel
 	  E7205, E7500, E7501 and E7505 server chipsets.
 
 config EDAC_E752X
 	tristate "Intel e752x (e7520, e7525, e7320)"
-	depends on EDAC_MM_EDAC && PCI
+	depends on EDAC_MM_EDAC && PCI && X86 && HOTPLUG
 	help
 	  Support for error detection and correction on the Intel
 	  E7520, E7525, E7320 server chipsets.
 
 config EDAC_I82875P
 	tristate "Intel 82875p (D82875P, E7210)"
-	depends on EDAC_MM_EDAC && PCI
+	depends on EDAC_MM_EDAC && PCI && X86_32
 	help
 	  Support for error detection and correction on the Intel
 	  DP82785P and E7210 server chipsets.
 
 config EDAC_I82860
 	tristate "Intel 82860"
-	depends on EDAC_MM_EDAC && PCI
+	depends on EDAC_MM_EDAC && PCI && X86_32
 	help
 	  Support for error detection and correction on the Intel
 	  82860 chipset.
 
 config EDAC_R82600
 	tristate "Radisys 82600 embedded chipset"
-	depends on EDAC_MM_EDAC
+	depends on EDAC_MM_EDAC && PCI && X86_32
 	help
 	  Support for error detection and correction on the Radisys
 	  82600 embedded chipset.
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index 2fcc812..53423ad 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
@@ -12,25 +12,26 @@
  *
  */
 
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
-
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
-
 #include <linux/slab.h>
-
 #include "edac_mc.h"
 
+#define amd76x_printk(level, fmt, arg...) \
+	edac_printk(level, "amd76x", fmt, ##arg)
+
+#define amd76x_mc_printk(mci, level, fmt, arg...) \
+	edac_mc_chipset_printk(mci, level, "amd76x", fmt, ##arg)
 
 #define AMD76X_NR_CSROWS 8
 #define AMD76X_NR_CHANS  1
 #define AMD76X_NR_DIMMS  4
 
-
 /* AMD 76x register addresses - device 0 function 0 - PCI bridge */
+
 #define AMD76X_ECC_MODE_STATUS	0x48	/* Mode and status of ECC (32b)
 					 *
 					 * 31:16 reserved
@@ -42,6 +43,7 @@
 					 *  7:4  UE cs row
 					 *  3:0  CE cs row
 					 */
+
 #define AMD76X_DRAM_MODE_STATUS	0x58	/* DRAM Mode and status (32b)
 					 *
 					 * 31:26 clock disable 5 - 0
@@ -56,6 +58,7 @@
 					 * 15:8  reserved
 					 *  7:0  x4 mode enable 7 - 0
 					 */
+
 #define AMD76X_MEM_BASE_ADDR	0xC0	/* Memory base address (8 x 32b)
 					 *
 					 * 31:23 chip-select base
@@ -66,29 +69,28 @@
 					 *  0    chip-select enable
 					 */
 
-
 struct amd76x_error_info {
 	u32 ecc_mode_status;
 };
 
-
 enum amd76x_chips {
 	AMD761 = 0,
 	AMD762
 };
 
-
 struct amd76x_dev_info {
 	const char *ctl_name;
 };
 
-
 static const struct amd76x_dev_info amd76x_devs[] = {
-	[AMD761] = {.ctl_name = "AMD761"},
-	[AMD762] = {.ctl_name = "AMD762"},
+	[AMD761] = {
+		.ctl_name = "AMD761"
+	},
+	[AMD762] = {
+		.ctl_name = "AMD762"
+	},
 };
 
-
 /**
  *	amd76x_get_error_info	-	fetch error information
  *	@mci: Memory controller
@@ -97,23 +99,21 @@
  *	Fetch and store the AMD76x ECC status. Clear pending status
  *	on the chip so that further errors will be reported
  */
-
-static void amd76x_get_error_info (struct mem_ctl_info *mci,
-				   struct amd76x_error_info *info)
+static void amd76x_get_error_info(struct mem_ctl_info *mci,
+		struct amd76x_error_info *info)
 {
 	pci_read_config_dword(mci->pdev, AMD76X_ECC_MODE_STATUS,
 				&info->ecc_mode_status);
 
 	if (info->ecc_mode_status & BIT(8))
 		pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS,
-				   (u32) BIT(8), (u32) BIT(8));
+				(u32) BIT(8), (u32) BIT(8));
 
 	if (info->ecc_mode_status & BIT(9))
 		pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS,
-				   (u32) BIT(9), (u32) BIT(9));
+				(u32) BIT(9), (u32) BIT(9));
 }
 
-
 /**
  *	amd76x_process_error_info	-	Error check
  *	@mci: Memory controller
@@ -124,8 +124,7 @@
  *	A return of 1 indicates an error. Also if handle_errors is true
  *	then attempt to handle and clean up after the error
  */
-
-static int amd76x_process_error_info (struct mem_ctl_info *mci,
+static int amd76x_process_error_info(struct mem_ctl_info *mci,
 		struct amd76x_error_info *info, int handle_errors)
 {
 	int error_found;
@@ -141,9 +140,8 @@
 
 		if (handle_errors) {
 			row = (info->ecc_mode_status >> 4) & 0xf;
-			edac_mc_handle_ue(mci,
-			    mci->csrows[row].first_page, 0, row,
-			    mci->ctl_name);
+			edac_mc_handle_ue(mci, mci->csrows[row].first_page, 0,
+				row, mci->ctl_name);
 		}
 	}
 
@@ -155,11 +153,11 @@
 
 		if (handle_errors) {
 			row = info->ecc_mode_status & 0xf;
-			edac_mc_handle_ce(mci,
-			    mci->csrows[row].first_page, 0, 0, row, 0,
-			    mci->ctl_name);
+			edac_mc_handle_ce(mci, mci->csrows[row].first_page, 0,
+				0, row, 0, mci->ctl_name);
 		}
 	}
+
 	return error_found;
 }
 
@@ -170,16 +168,14 @@
  *	Called by the poll handlers this function reads the status
  *	from the controller and checks for errors.
  */
-
 static void amd76x_check(struct mem_ctl_info *mci)
 {
 	struct amd76x_error_info info;
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 	amd76x_get_error_info(mci, &info);
 	amd76x_process_error_info(mci, &info, 1);
 }
 
-
 /**
  *	amd76x_probe1	-	Perform set up for detected device
  *	@pdev; PCI device detected
@@ -189,7 +185,6 @@
  *	controller status reporting. We configure and set up the
  *	memory controller reporting and claim the device.
  */
-
 static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
 {
 	int rc = -ENODEV;
@@ -203,12 +198,11 @@
 	};
 	u32 ems;
 	u32 ems_mode;
+	struct amd76x_error_info discard;
 
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
-
+	debugf0("%s()\n", __func__);
 	pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems);
 	ems_mode = (ems >> 10) & 0x3;
-
 	mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS);
 
 	if (mci == NULL) {
@@ -216,16 +210,13 @@
 		goto fail;
 	}
 
-	debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
-
-	mci->pdev = pci_dev_get(pdev);
+	debugf0("%s(): mci = %p\n", __func__, mci);
+	mci->pdev = pdev;
 	mci->mtype_cap = MEM_FLAG_RDDR;
-
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
 	mci->edac_cap = ems_mode ?
-	    (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE;
-
-	mci->mod_name = BS_MOD_STR;
+			(EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE;
+	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = "$Revision: 1.4.2.5 $";
 	mci->ctl_name = amd76x_devs[dev_idx].ctl_name;
 	mci->edac_check = amd76x_check;
@@ -240,18 +231,15 @@
 
 		/* find the DRAM Chip Select Base address and mask */
 		pci_read_config_dword(mci->pdev,
-				      AMD76X_MEM_BASE_ADDR + (index * 4),
-				      &mba);
+				AMD76X_MEM_BASE_ADDR + (index * 4), &mba);
 
 		if (!(mba & BIT(0)))
 			continue;
 
 		mba_base = mba & 0xff800000UL;
 		mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL;
-
 		pci_read_config_dword(mci->pdev, AMD76X_DRAM_MODE_STATUS,
-				      &dms);
-
+				&dms);
 		csrow->first_page = mba_base >> PAGE_SHIFT;
 		csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT;
 		csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
@@ -262,40 +250,33 @@
 		csrow->edac_mode = ems_modes[ems_mode];
 	}
 
-	/* clear counters */
-	pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS, (u32) (0x3 << 8),
-			 (u32) (0x3 << 8));
+	amd76x_get_error_info(mci, &discard);  /* clear counters */
 
 	if (edac_mc_add_mc(mci)) {
-		debugf3("MC: " __FILE__
-			": %s(): failed edac_mc_add_mc()\n", __func__);
+		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
 		goto fail;
 	}
 
 	/* get this far and it's successful */
-	debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
+	debugf3("%s(): success\n", __func__);
 	return 0;
 
 fail:
-	if (mci) {
-		if(mci->pdev)
-			pci_dev_put(mci->pdev);
+	if (mci != NULL)
 		edac_mc_free(mci);
-	}
 	return rc;
 }
 
 /* returns count (>= 0), or negative on error */
 static int __devinit amd76x_init_one(struct pci_dev *pdev,
-				     const struct pci_device_id *ent)
+		const struct pci_device_id *ent)
 {
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
 
 	/* don't need to call pci_device_enable() */
 	return amd76x_probe1(pdev, ent->driver_data);
 }
 
-
 /**
  *	amd76x_remove_one	-	driver shutdown
  *	@pdev: PCI device being handed back
@@ -304,35 +285,36 @@
  *	structure for the device then delete the mci and free the
  *	resources.
  */
-
 static void __devexit amd76x_remove_one(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 
-	debugf0(__FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
 
-	if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL)
+	if ((mci = edac_mc_del_mc(pdev)) == NULL)
 		return;
-	if (edac_mc_del_mc(mci))
-		return;
-	pci_dev_put(mci->pdev);
+
 	edac_mc_free(mci);
 }
 
-
 static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = {
-	{PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	 AMD762},
-	{PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	 AMD761},
-	{0,}			/* 0 terminated list. */
+	{
+		PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		AMD762
+	},
+	{
+		PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		AMD761
+	},
+	{
+		0,
+	}	/* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl);
 
-
 static struct pci_driver amd76x_driver = {
-	.name = BS_MOD_STR,
+	.name = EDAC_MOD_STR,
 	.probe = amd76x_init_one,
 	.remove = __devexit_p(amd76x_remove_one),
 	.id_table = amd76x_pci_tbl,
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index c454ded..66572c5 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -17,18 +17,19 @@
  *
  */
 
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
-
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
-
 #include <linux/slab.h>
-
 #include "edac_mc.h"
 
+#define e752x_printk(level, fmt, arg...) \
+	edac_printk(level, "e752x", fmt, ##arg)
+
+#define e752x_mc_printk(mci, level, fmt, arg...) \
+	edac_mc_chipset_printk(mci, level, "e752x", fmt, ##arg)
 
 #ifndef PCI_DEVICE_ID_INTEL_7520_0
 #define PCI_DEVICE_ID_INTEL_7520_0      0x3590
@@ -56,7 +57,6 @@
 
 #define E752X_NR_CSROWS		8	/* number of csrows */
 
-
 /* E752X register addresses - device 0 function 0 */
 #define E752X_DRB		0x60	/* DRAM row boundary register (8b) */
 #define E752X_DRA		0x70	/* DRAM row attribute register (8b) */
@@ -156,7 +156,6 @@
 	E7320 = 2
 };
 
-
 struct e752x_pvt {
 	struct pci_dev *bridge_ck;
 	struct pci_dev *dev_d0f0;
@@ -170,9 +169,9 @@
 	const struct e752x_dev_info *dev_info;
 };
 
-
 struct e752x_dev_info {
 	u16 err_dev;
+	u16 ctl_dev;
 	const char *ctl_name;
 };
 
@@ -198,38 +197,47 @@
 
 static const struct e752x_dev_info e752x_devs[] = {
 	[E7520] = {
-		   .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR,
-		   .ctl_name = "E7520"},
+		.err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR,
+		.ctl_dev = PCI_DEVICE_ID_INTEL_7520_0,
+		.ctl_name = "E7520"
+	},
 	[E7525] = {
-		   .err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR,
-		   .ctl_name = "E7525"},
+		.err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR,
+		.ctl_dev = PCI_DEVICE_ID_INTEL_7525_0,
+		.ctl_name = "E7525"
+	},
 	[E7320] = {
-		   .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR,
-		   .ctl_name = "E7320"},
+		.err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR,
+		.ctl_dev = PCI_DEVICE_ID_INTEL_7320_0,
+		.ctl_name = "E7320"
+	},
 };
 
-
 static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
-				      unsigned long page)
+		unsigned long page)
 {
 	u32 remap;
 	struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 
 	if (page < pvt->tolm)
 		return page;
+
 	if ((page >= 0x100000) && (page < pvt->remapbase))
 		return page;
+
 	remap = (page - pvt->tolm) + pvt->remapbase;
+
 	if (remap < pvt->remaplimit)
 		return remap;
-	printk(KERN_ERR "Invalid page %lx - out of range\n", page);
+
+	e752x_printk(KERN_ERR, "Invalid page %lx - out of range\n", page);
 	return pvt->tolm - 1;
 }
 
 static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
-		       u32 sec1_add, u16 sec1_syndrome)
+		u32 sec1_add, u16 sec1_syndrome)
 {
 	u32 page;
 	int row;
@@ -237,7 +245,7 @@
 	int i;
 	struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 
 	/* convert the addr to 4k page */
 	page = sec1_add >> (PAGE_SHIFT - 4);
@@ -246,35 +254,36 @@
 	if (pvt->mc_symmetric) {
 		/* chip select are bits 14 & 13 */
 		row = ((page >> 1) & 3);
-		printk(KERN_WARNING
-		       "Test row %d Table %d %d %d %d %d %d %d %d\n",
-		       row, pvt->map[0], pvt->map[1], pvt->map[2],
-		       pvt->map[3], pvt->map[4], pvt->map[5],
-		       pvt->map[6], pvt->map[7]);
+		e752x_printk(KERN_WARNING,
+			"Test row %d Table %d %d %d %d %d %d %d %d\n", row,
+			pvt->map[0], pvt->map[1], pvt->map[2], pvt->map[3],
+			pvt->map[4], pvt->map[5], pvt->map[6], pvt->map[7]);
 
 		/* test for channel remapping */
 		for (i = 0; i < 8; i++) {
 			if (pvt->map[i] == row)
 				break;
 		}
-		printk(KERN_WARNING "Test computed row %d\n", i);
+
+		e752x_printk(KERN_WARNING, "Test computed row %d\n", i);
+
 		if (i < 8)
 			row = i;
 		else
-			printk(KERN_WARNING
-			       "MC%d: row %d not found in remap table\n",
-			       mci->mc_idx, row);
+			e752x_mc_printk(mci, KERN_WARNING,
+				"row %d not found in remap table\n", row);
 	} else
 		row = edac_mc_find_csrow_by_page(mci, page);
+
 	/* 0 = channel A, 1 = channel B */
 	channel = !(error_one & 1);
 
 	if (!pvt->map_type)
 		row = 7 - row;
-	edac_mc_handle_ce(mci, page, 0, sec1_syndrome, row, channel,
-	    "e752x CE");
-}
 
+	edac_mc_handle_ce(mci, page, 0, sec1_syndrome, row, channel,
+		"e752x CE");
+}
 
 static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
 		u32 sec1_add, u16 sec1_syndrome, int *error_found,
@@ -286,36 +295,42 @@
 		do_process_ce(mci, error_one, sec1_add, sec1_syndrome);
 }
 
-static void do_process_ue(struct mem_ctl_info *mci, u16 error_one, u32 ded_add,
-		u32 scrb_add)
+static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
+		u32 ded_add, u32 scrb_add)
 {
 	u32 error_2b, block_page;
 	int row;
 	struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 
 	if (error_one & 0x0202) {
 		error_2b = ded_add;
+
 		/* convert to 4k address */
 		block_page = error_2b >> (PAGE_SHIFT - 4);
+
 		row = pvt->mc_symmetric ?
-		    /* chip select are bits 14 & 13 */
-		    ((block_page >> 1) & 3) :
-		    edac_mc_find_csrow_by_page(mci, block_page);
+			/* chip select are bits 14 & 13 */
+			((block_page >> 1) & 3) :
+			edac_mc_find_csrow_by_page(mci, block_page);
+
 		edac_mc_handle_ue(mci, block_page, 0, row,
-				       "e752x UE from Read");
+			"e752x UE from Read");
 	}
 	if (error_one & 0x0404) {
 		error_2b = scrb_add;
+
 		/* convert to 4k address */
 		block_page = error_2b >> (PAGE_SHIFT - 4);
+
 		row = pvt->mc_symmetric ?
-		    /* chip select are bits 14 & 13 */
-		    ((block_page >> 1) & 3) :
-		    edac_mc_find_csrow_by_page(mci, block_page);
+			/* chip select are bits 14 & 13 */
+			((block_page >> 1) & 3) :
+			edac_mc_find_csrow_by_page(mci, block_page);
+
 		edac_mc_handle_ue(mci, block_page, 0, row,
-				       "e752x UE from Scruber");
+				"e752x UE from Scruber");
 	}
 }
 
@@ -336,7 +351,7 @@
 	if (!handle_error)
 		return;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 	edac_mc_handle_ue_no_info(mci, "e752x UE log memory write");
 }
 
@@ -348,13 +363,13 @@
 	struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
 
 	error_1b = retry_add;
-	page = error_1b >> (PAGE_SHIFT - 4);	/* convert the addr to 4k page */
+	page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */
 	row = pvt->mc_symmetric ?
-	    ((page >> 1) & 3) :	/* chip select are bits 14 & 13 */
-	    edac_mc_find_csrow_by_page(mci, page);
-	printk(KERN_WARNING
-	       "MC%d: CE page 0x%lx, row %d : Memory read retry\n",
-	       mci->mc_idx, (long unsigned int) page, row);
+		((page >> 1) & 3) : /* chip select are bits 14 & 13 */
+		edac_mc_find_csrow_by_page(mci, page);
+	e752x_mc_printk(mci, KERN_WARNING,
+		"CE page 0x%lx, row %d : Memory read retry\n",
+		(long unsigned int) page, row);
 }
 
 static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error,
@@ -372,8 +387,7 @@
 	*error_found = 1;
 
 	if (handle_error)
-		printk(KERN_WARNING "MC%d: Memory threshold CE\n",
-		       mci->mc_idx);
+		e752x_mc_printk(mci, KERN_WARNING, "Memory threshold CE\n");
 }
 
 static char *global_message[11] = {
@@ -391,8 +405,8 @@
 
 	for (i = 0; i < 11; i++) {
 		if (errors & (1 << i))
-			printk(KERN_WARNING "%sError %s\n",
-			       fatal_message[fatal], global_message[i]);
+			e752x_printk(KERN_WARNING, "%sError %s\n",
+				fatal_message[fatal], global_message[i]);
 	}
 }
 
@@ -418,8 +432,8 @@
 
 	for (i = 0; i < 7; i++) {
 		if (errors & (1 << i))
-			printk(KERN_WARNING "%sError %s\n",
-			       fatal_message[fatal], hub_message[i]);
+			e752x_printk(KERN_WARNING, "%sError %s\n",
+				fatal_message[fatal], hub_message[i]);
 	}
 }
 
@@ -445,8 +459,8 @@
 
 	for (i = 0; i < 4; i++) {
 		if (errors & (1 << i))
-			printk(KERN_WARNING "Non-Fatal Error %s\n",
-			       membuf_message[i]);
+			e752x_printk(KERN_WARNING, "Non-Fatal Error %s\n",
+				membuf_message[i]);
 	}
 }
 
@@ -458,8 +472,7 @@
 		do_membuf_error(errors);
 }
 
-#if 0
-char *sysbus_message[10] = {
+static char *sysbus_message[10] = {
 	"Addr or Request Parity",
 	"Data Strobe Glitch",
 	"Addr Strobe Glitch",
@@ -470,7 +483,6 @@
 	"Memory Parity",
 	"IO Subsystem Parity"
 };
-#endif  /*  0  */
 
 static void do_sysbus_error(int fatal, u32 errors)
 {
@@ -478,8 +490,8 @@
 
 	for (i = 0; i < 10; i++) {
 		if (errors & (1 << i))
-			printk(KERN_WARNING "%sError System Bus %s\n",
-			       fatal_message[fatal], global_message[i]);
+			e752x_printk(KERN_WARNING, "%sError System Bus %s\n",
+				fatal_message[fatal], sysbus_message[i]);
 	}
 }
 
@@ -492,33 +504,42 @@
 		do_sysbus_error(fatal, errors);
 }
 
-static void e752x_check_hub_interface (struct e752x_error_info *info,
+static void e752x_check_hub_interface(struct e752x_error_info *info,
 		int *error_found, int handle_error)
 {
 	u8 stat8;
 
 	//pci_read_config_byte(dev,E752X_HI_FERR,&stat8);
+
 	stat8 = info->hi_ferr;
+
 	if(stat8 & 0x7f) { /* Error, so process */
 		stat8 &= 0x7f;
+
 		if(stat8 & 0x2b)
 			hub_error(1, stat8 & 0x2b, error_found, handle_error);
+
 		if(stat8 & 0x54)
 			hub_error(0, stat8 & 0x54, error_found, handle_error);
 	}
+
 	//pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
+
 	stat8 = info->hi_nerr;
+
 	if(stat8 & 0x7f) { /* Error, so process */
 		stat8 &= 0x7f;
+
 		if (stat8 & 0x2b)
 			hub_error(1, stat8 & 0x2b, error_found, handle_error);
+
 		if(stat8 & 0x54)
 			hub_error(0, stat8 & 0x54, error_found, handle_error);
 	}
 }
 
-static void e752x_check_sysbus (struct e752x_error_info *info, int *error_found,
-		int handle_error)
+static void e752x_check_sysbus(struct e752x_error_info *info,
+		int *error_found, int handle_error)
 {
 	u32 stat32, error32;
 
@@ -530,27 +551,34 @@
 
 	error32 = (stat32 >> 16) & 0x3ff;
 	stat32 = stat32 & 0x3ff;
+
 	if(stat32 & 0x083)
 		sysbus_error(1, stat32 & 0x083, error_found, handle_error);
+
 	if(stat32 & 0x37c)
 		sysbus_error(0, stat32 & 0x37c, error_found, handle_error);
+
 	if(error32 & 0x083)
 		sysbus_error(1, error32 & 0x083, error_found, handle_error);
+
 	if(error32 & 0x37c)
 		sysbus_error(0, error32 & 0x37c, error_found, handle_error);
 }
 
-static void e752x_check_membuf (struct e752x_error_info *info, int *error_found,
-		int handle_error)
+static void e752x_check_membuf (struct e752x_error_info *info,
+		int *error_found, int handle_error)
 {
 	u8 stat8;
 
 	stat8 = info->buf_ferr;
+
 	if (stat8 & 0x0f) { /* Error, so process */
 		stat8 &= 0x0f;
 		membuf_error(stat8, error_found, handle_error);
 	}
+
 	stat8 = info->buf_nerr;
+
 	if (stat8 & 0x0f) { /* Error, so process */
 		stat8 &= 0x0f;
 		membuf_error(stat8, error_found, handle_error);
@@ -558,7 +586,8 @@
 }
 
 static void e752x_check_dram (struct mem_ctl_info *mci,
-		struct e752x_error_info *info, int *error_found, int handle_error)
+		struct e752x_error_info *info, int *error_found,
+		int handle_error)
 {
 	u16 error_one, error_next;
 
@@ -608,7 +637,7 @@
 }
 
 static void e752x_get_error_info (struct mem_ctl_info *mci,
-				  struct e752x_error_info *info)
+		struct e752x_error_info *info)
 {
 	struct pci_dev *dev;
 	struct e752x_pvt *pvt;
@@ -616,7 +645,6 @@
 	memset(info, 0, sizeof(*info));
 	pvt = (struct e752x_pvt *) mci->pvt_info;
 	dev = pvt->dev_d0f1;
-
 	pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global);
 
 	if (info->ferr_global) {
@@ -727,7 +755,8 @@
 static void e752x_check(struct mem_ctl_info *mci)
 {
 	struct e752x_error_info info;
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+
+	debugf3("%s()\n", __func__);
 	e752x_get_error_info(mci, &info);
 	e752x_process_error_info(mci, &info, 1);
 }
@@ -736,23 +765,21 @@
 {
 	int rc = -ENODEV;
 	int index;
-	u16 pci_data, stat;
-	u32 stat32;
-	u16 stat16;
+	u16 pci_data;
 	u8 stat8;
 	struct mem_ctl_info *mci = NULL;
 	struct e752x_pvt *pvt = NULL;
 	u16 ddrcsr;
 	u32 drc;
-	int drc_chan;		/* Number of channels 0=1chan,1=2chan */
-	int drc_drbg;		/* DRB granularity 0=64mb,1=128mb */
-	int drc_ddim;		/* DRAM Data Integrity Mode 0=none,2=edac */
+	int drc_chan;	/* Number of channels 0=1chan,1=2chan */
+	int drc_drbg;	/* DRB granularity 0=64mb, 1=128mb */
+	int drc_ddim;	/* DRAM Data Integrity Mode 0=none,2=edac */
 	u32 dra;
 	unsigned long last_cumul_size;
-	struct pci_dev *pres_dev;
 	struct pci_dev *dev = NULL;
+	struct e752x_error_info discard;
 
-	debugf0("MC: " __FILE__ ": %s(): mci\n", __func__);
+	debugf0("%s(): mci\n", __func__);
 	debugf0("Starting Probe1\n");
 
 	/* enable device 0 function 1 */
@@ -776,34 +803,35 @@
 		goto fail;
 	}
 
-	debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__);
-
+	debugf3("%s(): init mci\n", __func__);
 	mci->mtype_cap = MEM_FLAG_RDDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
 	    EDAC_FLAG_S4ECD4ED;
 	/* FIXME - what if different memory types are in different csrows? */
-	mci->mod_name = BS_MOD_STR;
+	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = "$Revision: 1.5.2.11 $";
 	mci->pdev = pdev;
 
-	debugf3("MC: " __FILE__ ": %s(): init pvt\n", __func__);
+	debugf3("%s(): init pvt\n", __func__);
 	pvt = (struct e752x_pvt *) mci->pvt_info;
 	pvt->dev_info = &e752x_devs[dev_idx];
 	pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
-					 pvt->dev_info->err_dev,
-					 pvt->bridge_ck);
+					pvt->dev_info->err_dev,
+					pvt->bridge_ck);
+
 	if (pvt->bridge_ck == NULL)
 		pvt->bridge_ck = pci_scan_single_device(pdev->bus,
-							PCI_DEVFN(0, 1));
+					PCI_DEVFN(0, 1));
+
 	if (pvt->bridge_ck == NULL) {
-		printk(KERN_ERR "MC: error reporting device not found:"
-		       "vendor %x device 0x%x (broken BIOS?)\n",
-		       PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
+		e752x_printk(KERN_ERR, "error reporting device not found:"
+			"vendor %x device 0x%x (broken BIOS?)\n",
+			PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
 		goto fail;
 	}
-	pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
 
-	debugf3("MC: " __FILE__ ": %s(): more mci init\n", __func__);
+	pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
+	debugf3("%s(): more mci init\n", __func__);
 	mci->ctl_name = pvt->dev_info->ctl_name;
 	mci->edac_check = e752x_check;
 	mci->ctl_page_to_phys = ctl_page_to_phys;
@@ -820,6 +848,7 @@
 	for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
 		u8 value;
 		u32 cumul_size;
+
 		/* mem_dev 0=x8, 1=x4 */
 		int mem_dev = (dra >> (index * 4 + 2)) & 0x3;
 		struct csrow_info *csrow = &mci->csrows[index];
@@ -828,17 +857,18 @@
 		pci_read_config_byte(mci->pdev, E752X_DRB + index, &value);
 		/* convert a 128 or 64 MiB DRB to a page size. */
 		cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);
-		debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n",
-			__func__, index, cumul_size);
+		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
+			cumul_size);
+
 		if (cumul_size == last_cumul_size)
-			continue;	/* not populated */
+			continue; /* not populated */
 
 		csrow->first_page = last_cumul_size;
 		csrow->last_page = cumul_size - 1;
 		csrow->nr_pages = cumul_size - last_cumul_size;
 		last_cumul_size = cumul_size;
-		csrow->grain = 1 << 12;	/* 4KiB - resolution of CELOG */
-		csrow->mtype = MEM_RDDR;	/* only one type supported */
+		csrow->grain = 1 << 12;  /* 4KiB - resolution of CELOG */
+		csrow->mtype = MEM_RDDR;  /* only one type supported */
 		csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;
 
 		/*
@@ -862,29 +892,32 @@
 		u8 value;
 		u8 last = 0;
 		u8 row = 0;
-		for (index = 0; index < 8; index += 2) {
 
+		for (index = 0; index < 8; index += 2) {
 			pci_read_config_byte(mci->pdev, E752X_DRB + index,
-					     &value);
+					&value);
+
 			/* test if there is a dimm in this slot */
 			if (value == last) {
 				/* no dimm in the slot, so flag it as empty */
 				pvt->map[index] = 0xff;
 				pvt->map[index + 1] = 0xff;
-			} else {	/* there is a dimm in the slot */
+			} else { /* there is a dimm in the slot */
 				pvt->map[index] = row;
 				row++;
 				last = value;
 				/* test the next value to see if the dimm is
 				   double sided */
 				pci_read_config_byte(mci->pdev,
-						     E752X_DRB + index + 1,
-						     &value);
+						E752X_DRB + index + 1,
+						&value);
 				pvt->map[index + 1] = (value == last) ?
-				    0xff :	/* the dimm is single sided,
-						   so flag as empty */
-				    row;	/* this is a double sided dimm
-						   to save the next row # */
+					0xff :	/* the dimm is single sided,
+						 * so flag as empty
+						 */
+					row;	/* this is a double sided dimm
+						 * to save the next row #
+						 */
 				row++;
 				last = value;
 			}
@@ -896,9 +929,8 @@
 	pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
 
 	mci->edac_cap |= EDAC_FLAG_NONE;
+	debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
 
-	debugf3("MC: " __FILE__ ": %s(): tolm, remapbase, remaplimit\n",
-		__func__);
 	/* load the top of low memory, remap base, and remap limit vars */
 	pci_read_config_word(mci->pdev, E752X_TOLM, &pci_data);
 	pvt->tolm = ((u32) pci_data) << 4;
@@ -906,43 +938,18 @@
 	pvt->remapbase = ((u32) pci_data) << 14;
 	pci_read_config_word(mci->pdev, E752X_REMAPLIMIT, &pci_data);
 	pvt->remaplimit = ((u32) pci_data) << 14;
-	printk("tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm,
-	       pvt->remapbase, pvt->remaplimit);
+	e752x_printk(KERN_INFO,
+		"tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm,
+		pvt->remapbase, pvt->remaplimit);
 
 	if (edac_mc_add_mc(mci)) {
-		debugf3("MC: " __FILE__
-			": %s(): failed edac_mc_add_mc()\n",
-			__func__);
+		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
 		goto fail;
 	}
 
-	/* Walk through the PCI table and clear errors */
-	switch (dev_idx) {
-	case E7520:
-		dev = pci_get_device(PCI_VENDOR_ID_INTEL,
-				      PCI_DEVICE_ID_INTEL_7520_0, NULL);
-		break;
-	case E7525:
-		dev = pci_get_device(PCI_VENDOR_ID_INTEL,
-				      PCI_DEVICE_ID_INTEL_7525_0, NULL);
-		break;
-	case E7320:
-		dev = pci_get_device(PCI_VENDOR_ID_INTEL,
-				      PCI_DEVICE_ID_INTEL_7320_0, NULL);
-		break;
-	}
-
-
+	dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev,
+			NULL);
 	pvt->dev_d0f0 = dev;
-	for (pres_dev = dev;
-	     ((struct pci_dev *) pres_dev->global_list.next != dev);
-	     pres_dev = (struct pci_dev *) pres_dev->global_list.next) {
-		pci_read_config_dword(pres_dev, PCI_COMMAND, &stat32);
-		stat = (u16) (stat32 >> 16);
-		/* clear any error bits */
-		if (stat32 & ((1 << 6) + (1 << 8)))
-			pci_write_config_word(pres_dev, PCI_STATUS, stat);
-	}
 	/* find the error reporting device and clear errors */
 	dev = pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck);
 	/* Turn off error disable & SMI in case the BIOS turned it on */
@@ -954,67 +961,51 @@
 	pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00);
 	pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00);
 	pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00);
-	/* clear other MCH errors */
-	pci_read_config_dword(dev, E752X_FERR_GLOBAL, &stat32);
-	pci_write_config_dword(dev, E752X_FERR_GLOBAL, stat32);
-	pci_read_config_dword(dev, E752X_NERR_GLOBAL, &stat32);
-	pci_write_config_dword(dev, E752X_NERR_GLOBAL, stat32);
-	pci_read_config_byte(dev, E752X_HI_FERR, &stat8);
-	pci_write_config_byte(dev, E752X_HI_FERR, stat8);
-	pci_read_config_byte(dev, E752X_HI_NERR, &stat8);
-	pci_write_config_byte(dev, E752X_HI_NERR, stat8);
-	pci_read_config_dword(dev, E752X_SYSBUS_FERR, &stat32);
-	pci_write_config_dword(dev, E752X_SYSBUS_FERR, stat32);
-	pci_read_config_byte(dev, E752X_BUF_FERR, &stat8);
-	pci_write_config_byte(dev, E752X_BUF_FERR, stat8);
-	pci_read_config_byte(dev, E752X_BUF_NERR, &stat8);
-	pci_write_config_byte(dev, E752X_BUF_NERR, stat8);
-	pci_read_config_word(dev, E752X_DRAM_FERR, &stat16);
-	pci_write_config_word(dev, E752X_DRAM_FERR, stat16);
-	pci_read_config_word(dev, E752X_DRAM_NERR, &stat16);
-	pci_write_config_word(dev, E752X_DRAM_NERR, stat16);
+
+	e752x_get_error_info(mci, &discard); /* clear other MCH errors */
 
 	/* get this far and it's successful */
-	debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
+	debugf3("%s(): success\n", __func__);
 	return 0;
 
 fail:
 	if (mci) {
 		if (pvt->dev_d0f0)
 			pci_dev_put(pvt->dev_d0f0);
+
 		if (pvt->dev_d0f1)
 			pci_dev_put(pvt->dev_d0f1);
+
 		if (pvt->bridge_ck)
 			pci_dev_put(pvt->bridge_ck);
+
 		edac_mc_free(mci);
 	}
+
 	return rc;
 }
 
 /* returns count (>= 0), or negative on error */
 static int __devinit e752x_init_one(struct pci_dev *pdev,
-				    const struct pci_device_id *ent)
+		const struct pci_device_id *ent)
 {
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
 
 	/* wake up and enable device */
 	if(pci_enable_device(pdev) < 0)
 		return -EIO;
+
 	return e752x_probe1(pdev, ent->driver_data);
 }
 
-
 static void __devexit e752x_remove_one(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 	struct e752x_pvt *pvt;
 
-	debugf0(__FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
 
-	if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL)
-		return;
-
-	if (edac_mc_del_mc(mci))
+	if ((mci = edac_mc_del_mc(pdev)) == NULL)
 		return;
 
 	pvt = (struct e752x_pvt *) mci->pvt_info;
@@ -1024,45 +1015,48 @@
 	edac_mc_free(mci);
 }
 
-
 static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {
-	{PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	 E7520},
-	{PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	 E7525},
-	{PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	 E7320},
-	{0,}			/* 0 terminated list. */
+	{
+		PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		E7520
+	},
+	{
+		PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		E7525
+	},
+	{
+		PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		E7320
+	},
+	{
+		0,
+	}	/* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
 
-
 static struct pci_driver e752x_driver = {
-	.name = BS_MOD_STR,
+	.name = EDAC_MOD_STR,
 	.probe = e752x_init_one,
 	.remove = __devexit_p(e752x_remove_one),
 	.id_table = e752x_pci_tbl,
 };
 
-
 static int __init e752x_init(void)
 {
 	int pci_rc;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 	pci_rc = pci_register_driver(&e752x_driver);
 	return (pci_rc < 0) ? pci_rc : 0;
 }
 
-
 static void __exit e752x_exit(void)
 {
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 	pci_unregister_driver(&e752x_driver);
 }
 
-
 module_init(e752x_init);
 module_exit(e752x_exit);
 
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index d5e320d..a9518d3 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -11,9 +11,9 @@
  *	http://www.anime.net/~goemon/linux-ecc/
  *
  * Contributors:
- * 	Eric Biederman (Linux Networx)
- * 	Tom Zimmerman (Linux Networx)
- * 	Jim Garlick (Lawrence Livermore National Labs)
+ *	Eric Biederman (Linux Networx)
+ *	Tom Zimmerman (Linux Networx)
+ *	Jim Garlick (Lawrence Livermore National Labs)
  *	Dave Peterson (Lawrence Livermore National Labs)
  *	That One Guy (Some other place)
  *	Wang Zhenyu (intel.com)
@@ -22,7 +22,6 @@
  *
  */
 
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -31,6 +30,11 @@
 #include <linux/slab.h>
 #include "edac_mc.h"
 
+#define e7xxx_printk(level, fmt, arg...) \
+	edac_printk(level, "e7xxx", fmt, ##arg)
+
+#define e7xxx_mc_printk(mci, level, fmt, arg...) \
+	edac_mc_chipset_printk(mci, level, "e7xxx", fmt, ##arg)
 
 #ifndef PCI_DEVICE_ID_INTEL_7205_0
 #define PCI_DEVICE_ID_INTEL_7205_0	0x255d
@@ -64,11 +68,9 @@
 #define PCI_DEVICE_ID_INTEL_7505_1_ERR	0x2551
 #endif				/* PCI_DEVICE_ID_INTEL_7505_1_ERR */
 
-
 #define E7XXX_NR_CSROWS		8	/* number of csrows */
 #define E7XXX_NR_DIMMS		8	/* FIXME - is this correct? */
 
-
 /* E7XXX register addresses - device 0 function 0 */
 #define E7XXX_DRB		0x60	/* DRAM row boundary register (8b) */
 #define E7XXX_DRA		0x70	/* DRAM row attribute register (8b) */
@@ -118,7 +120,6 @@
 	E7205,
 };
 
-
 struct e7xxx_pvt {
 	struct pci_dev *bridge_ck;
 	u32 tolm;
@@ -127,13 +128,11 @@
 	const struct e7xxx_dev_info *dev_info;
 };
 
-
 struct e7xxx_dev_info {
 	u16 err_dev;
 	const char *ctl_name;
 };
 
-
 struct e7xxx_error_info {
 	u8 dram_ferr;
 	u8 dram_nerr;
@@ -144,108 +143,110 @@
 
 static const struct e7xxx_dev_info e7xxx_devs[] = {
 	[E7500] = {
-		   .err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR,
-		   .ctl_name = "E7500"},
+		.err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR,
+		.ctl_name = "E7500"
+	},
 	[E7501] = {
-		   .err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR,
-		   .ctl_name = "E7501"},
+		.err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR,
+		.ctl_name = "E7501"
+	},
 	[E7505] = {
-		   .err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR,
-		   .ctl_name = "E7505"},
+		.err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR,
+		.ctl_name = "E7505"
+	},
 	[E7205] = {
-		   .err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR,
-		   .ctl_name = "E7205"},
+		.err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR,
+		.ctl_name = "E7205"
+	},
 };
 
-
 /* FIXME - is this valid for both SECDED and S4ECD4ED? */
 static inline int e7xxx_find_channel(u16 syndrome)
 {
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 
 	if ((syndrome & 0xff00) == 0)
 		return 0;
+
 	if ((syndrome & 0x00ff) == 0)
 		return 1;
+
 	if ((syndrome & 0xf000) == 0 || (syndrome & 0x0f00) == 0)
 		return 0;
+
 	return 1;
 }
 
-
-static unsigned long
-ctl_page_to_phys(struct mem_ctl_info *mci, unsigned long page)
+static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
+		unsigned long page)
 {
 	u32 remap;
 	struct e7xxx_pvt *pvt = (struct e7xxx_pvt *) mci->pvt_info;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 
 	if ((page < pvt->tolm) ||
-	    ((page >= 0x100000) && (page < pvt->remapbase)))
+			((page >= 0x100000) && (page < pvt->remapbase)))
 		return page;
+
 	remap = (page - pvt->tolm) + pvt->remapbase;
+
 	if (remap < pvt->remaplimit)
 		return remap;
-	printk(KERN_ERR "Invalid page %lx - out of range\n", page);
+
+	e7xxx_printk(KERN_ERR, "Invalid page %lx - out of range\n", page);
 	return pvt->tolm - 1;
 }
 
-
-static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
+static void process_ce(struct mem_ctl_info *mci,
+		struct e7xxx_error_info *info)
 {
 	u32 error_1b, page;
 	u16 syndrome;
 	int row;
 	int channel;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
-
+	debugf3("%s()\n", __func__);
 	/* read the error address */
 	error_1b = info->dram_celog_add;
 	/* FIXME - should use PAGE_SHIFT */
-	page = error_1b >> 6;	/* convert the address to 4k page */
+	page = error_1b >> 6;  /* convert the address to 4k page */
 	/* read the syndrome */
 	syndrome = info->dram_celog_syndrome;
 	/* FIXME - check for -1 */
 	row = edac_mc_find_csrow_by_page(mci, page);
 	/* convert syndrome to channel */
 	channel = e7xxx_find_channel(syndrome);
-	edac_mc_handle_ce(mci, page, 0, syndrome, row, channel,
-			       "e7xxx CE");
+	edac_mc_handle_ce(mci, page, 0, syndrome, row, channel, "e7xxx CE");
 }
 
-
 static void process_ce_no_info(struct mem_ctl_info *mci)
 {
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 	edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow");
 }
 
-
-static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
+static void process_ue(struct mem_ctl_info *mci,
+		struct e7xxx_error_info *info)
 {
 	u32 error_2b, block_page;
 	int row;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
-
+	debugf3("%s()\n", __func__);
 	/* read the error address */
 	error_2b = info->dram_uelog_add;
 	/* FIXME - should use PAGE_SHIFT */
-	block_page = error_2b >> 6;	/* convert to 4k address */
+	block_page = error_2b >> 6;  /* convert to 4k address */
 	row = edac_mc_find_csrow_by_page(mci, block_page);
 	edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE");
 }
 
-
 static void process_ue_no_info(struct mem_ctl_info *mci)
 {
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 	edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow");
 }
 
-
 static void e7xxx_get_error_info (struct mem_ctl_info *mci,
 		struct e7xxx_error_info *info)
 {
@@ -253,31 +254,29 @@
 
 	pvt = (struct e7xxx_pvt *) mci->pvt_info;
 	pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR,
-	    &info->dram_ferr);
+			&info->dram_ferr);
 	pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR,
-	    &info->dram_nerr);
+			&info->dram_nerr);
 
 	if ((info->dram_ferr & 1) || (info->dram_nerr & 1)) {
 		pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_CELOG_ADD,
-		    &info->dram_celog_add);
+				&info->dram_celog_add);
 		pci_read_config_word(pvt->bridge_ck,
-		    E7XXX_DRAM_CELOG_SYNDROME, &info->dram_celog_syndrome);
+				E7XXX_DRAM_CELOG_SYNDROME,
+				&info->dram_celog_syndrome);
 	}
 
 	if ((info->dram_ferr & 2) || (info->dram_nerr & 2))
 		pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_UELOG_ADD,
-		    &info->dram_uelog_add);
+				&info->dram_uelog_add);
 
 	if (info->dram_ferr & 3)
-		pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03,
-		    0x03);
+		pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03);
 
 	if (info->dram_nerr & 3)
-		pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03,
-		    0x03);
+		pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03);
 }
 
-
 static int e7xxx_process_error_info (struct mem_ctl_info *mci,
 		struct e7xxx_error_info *info, int handle_errors)
 {
@@ -325,17 +324,15 @@
 	return error_found;
 }
 
-
 static void e7xxx_check(struct mem_ctl_info *mci)
 {
 	struct e7xxx_error_info info;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 	e7xxx_get_error_info(mci, &info);
 	e7xxx_process_error_info(mci, &info, 1);
 }
 
-
 static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
 {
 	int rc = -ENODEV;
@@ -349,19 +346,20 @@
 	int drc_ddim;		/* DRAM Data Integrity Mode 0=none,2=edac */
 	u32 dra;
 	unsigned long last_cumul_size;
+	struct e7xxx_error_info discard;
 
-
-	debugf0("MC: " __FILE__ ": %s(): mci\n", __func__);
+	debugf0("%s(): mci\n", __func__);
 
 	/* need to find out the number of channels */
 	pci_read_config_dword(pdev, E7XXX_DRC, &drc);
+
 	/* only e7501 can be single channel */
 	if (dev_idx == E7501) {
 		drc_chan = ((drc >> 22) & 0x1);
 		drc_drbg = (drc >> 18) & 0x3;
 	}
-	drc_ddim = (drc >> 20) & 0x3;
 
+	drc_ddim = (drc >> 20) & 0x3;
 	mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1);
 
 	if (mci == NULL) {
@@ -369,33 +367,31 @@
 		goto fail;
 	}
 
-	debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__);
-
+	debugf3("%s(): init mci\n", __func__);
 	mci->mtype_cap = MEM_FLAG_RDDR;
-	mci->edac_ctl_cap =
-	    EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED;
+	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
+			EDAC_FLAG_S4ECD4ED;
 	/* FIXME - what if different memory types are in different csrows? */
-	mci->mod_name = BS_MOD_STR;
+	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = "$Revision: 1.5.2.9 $";
 	mci->pdev = pdev;
 
-	debugf3("MC: " __FILE__ ": %s(): init pvt\n", __func__);
+	debugf3("%s(): init pvt\n", __func__);
 	pvt = (struct e7xxx_pvt *) mci->pvt_info;
 	pvt->dev_info = &e7xxx_devs[dev_idx];
 	pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
-					 pvt->dev_info->err_dev,
-					 pvt->bridge_ck);
+					pvt->dev_info->err_dev,
+					pvt->bridge_ck);
+
 	if (!pvt->bridge_ck) {
-		printk(KERN_ERR
-		       "MC: error reporting device not found:"
-		       "vendor %x device 0x%x (broken BIOS?)\n",
-		       PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev);
+		e7xxx_printk(KERN_ERR, "error reporting device not found:"
+			"vendor %x device 0x%x (broken BIOS?)\n",
+			PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev);
 		goto fail;
 	}
 
-	debugf3("MC: " __FILE__ ": %s(): more mci init\n", __func__);
+	debugf3("%s(): more mci init\n", __func__);
 	mci->ctl_name = pvt->dev_info->ctl_name;
-
 	mci->edac_check = e7xxx_check;
 	mci->ctl_page_to_phys = ctl_page_to_phys;
 
@@ -418,17 +414,18 @@
 		pci_read_config_byte(mci->pdev, E7XXX_DRB + index, &value);
 		/* convert a 64 or 32 MiB DRB to a page size. */
 		cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);
-		debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n",
-			__func__, index, cumul_size);
+		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
+			cumul_size);
+
 		if (cumul_size == last_cumul_size)
-			continue;	/* not populated */
+			continue;  /* not populated */
 
 		csrow->first_page = last_cumul_size;
 		csrow->last_page = cumul_size - 1;
 		csrow->nr_pages = cumul_size - last_cumul_size;
 		last_cumul_size = cumul_size;
-		csrow->grain = 1 << 12;	/* 4KiB - resolution of CELOG */
-		csrow->mtype = MEM_RDDR;	/* only one type supported */
+		csrow->grain = 1 << 12;  /* 4KiB - resolution of CELOG */
+		csrow->mtype = MEM_RDDR;  /* only one type supported */
 		csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;
 
 		/*
@@ -449,8 +446,7 @@
 
 	mci->edac_cap |= EDAC_FLAG_NONE;
 
-	debugf3("MC: " __FILE__ ": %s(): tolm, remapbase, remaplimit\n",
-		__func__);
+	debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
 	/* load the top of low memory, remap base, and remap limit vars */
 	pci_read_config_word(mci->pdev, E7XXX_TOLM, &pci_data);
 	pvt->tolm = ((u32) pci_data) << 4;
@@ -458,22 +454,20 @@
 	pvt->remapbase = ((u32) pci_data) << 14;
 	pci_read_config_word(mci->pdev, E7XXX_REMAPLIMIT, &pci_data);
 	pvt->remaplimit = ((u32) pci_data) << 14;
-	printk("tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm,
-	       pvt->remapbase, pvt->remaplimit);
+	e7xxx_printk(KERN_INFO,
+		"tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm,
+		pvt->remapbase, pvt->remaplimit);
 
 	/* clear any pending errors, or initial state bits */
-	pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03);
-	pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03);
+	e7xxx_get_error_info(mci, &discard);
 
 	if (edac_mc_add_mc(mci) != 0) {
-		debugf3("MC: " __FILE__
-			": %s(): failed edac_mc_add_mc()\n",
-			__func__);
+		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
 		goto fail;
 	}
 
 	/* get this far and it's successful */
-	debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
+	debugf3("%s(): success\n", __func__);
 	return 0;
 
 fail:
@@ -487,62 +481,67 @@
 }
 
 /* returns count (>= 0), or negative on error */
-static int __devinit
-e7xxx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit e7xxx_init_one(struct pci_dev *pdev,
+		const struct pci_device_id *ent)
 {
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
 
 	/* wake up and enable device */
 	return pci_enable_device(pdev) ?
-	    -EIO : e7xxx_probe1(pdev, ent->driver_data);
+		-EIO : e7xxx_probe1(pdev, ent->driver_data);
 }
 
-
 static void __devexit e7xxx_remove_one(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 	struct e7xxx_pvt *pvt;
 
-	debugf0(__FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
 
-	if (((mci = edac_mc_find_mci_by_pdev(pdev)) != 0) &&
-	    edac_mc_del_mc(mci)) {
-		pvt = (struct e7xxx_pvt *) mci->pvt_info;
-		pci_dev_put(pvt->bridge_ck);
-		edac_mc_free(mci);
-	}
+	if ((mci = edac_mc_del_mc(pdev)) == NULL)
+		return;
+
+	pvt = (struct e7xxx_pvt *) mci->pvt_info;
+	pci_dev_put(pvt->bridge_ck);
+	edac_mc_free(mci);
 }
 
-
 static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = {
-	{PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	 E7205},
-	{PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	 E7500},
-	{PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	 E7501},
-	{PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	 E7505},
-	{0,}			/* 0 terminated list. */
+	{
+		PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		E7205
+	},
+	{
+		PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		E7500
+	},
+	{
+		PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		E7501
+	},
+	{
+		PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		E7505
+	},
+	{
+		0,
+	}	/* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl);
 
-
 static struct pci_driver e7xxx_driver = {
-	.name = BS_MOD_STR,
+	.name = EDAC_MOD_STR,
 	.probe = e7xxx_init_one,
 	.remove = __devexit_p(e7xxx_remove_one),
 	.id_table = e7xxx_pci_tbl,
 };
 
-
 static int __init e7xxx_init(void)
 {
 	return pci_register_driver(&e7xxx_driver);
 }
 
-
 static void __exit e7xxx_exit(void)
 {
 	pci_unregister_driver(&e7xxx_driver);
@@ -551,8 +550,7 @@
 module_init(e7xxx_init);
 module_exit(e7xxx_exit);
 
-
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
-	      "Based on.work by Dan Hollis et al");
+	"Based on.work by Dan Hollis et al");
 MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers");
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 9c20527..ea06e3a 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -12,7 +12,6 @@
  *
  */
 
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
@@ -29,14 +28,13 @@
 #include <linux/list.h>
 #include <linux/sysdev.h>
 #include <linux/ctype.h>
-
+#include <linux/kthread.h>
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/edac.h>
-
 #include "edac_mc.h"
 
-#define	EDAC_MC_VERSION	"edac_mc  Ver: 2.0.0 " __DATE__
+#define EDAC_MC_VERSION "Ver: 2.0.0 " __DATE__
 
 /* For now, disable the EDAC sysfs code.  The sysfs interface that EDAC
  * presents to user space needs more thought, and is likely to change
@@ -47,7 +45,7 @@
 #ifdef CONFIG_EDAC_DEBUG
 /* Values of 0 to 4 will generate output */
 int edac_debug_level = 1;
-EXPORT_SYMBOL(edac_debug_level);
+EXPORT_SYMBOL_GPL(edac_debug_level);
 #endif
 
 /* EDAC Controls, setable by module parameter, and sysfs */
@@ -64,13 +62,14 @@
 static DECLARE_MUTEX(mem_ctls_mutex);
 static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices);
 
+static struct task_struct *edac_thread;
+
 /* Structure of the whitelist and blacklist arrays */
 struct edac_pci_device_list {
 	unsigned int  vendor;		/* Vendor ID */
 	unsigned int  device;		/* Deviice ID */
 };
 
-
 #define MAX_LISTED_PCI_DEVICES		32
 
 /* List of PCI devices (vendor-id:device-id) that should be skipped */
@@ -123,7 +122,6 @@
 	[EDAC_S16ECD16ED] = "S16ECD16ED"
 };
 
-
 /* sysfs object: /sys/devices/system/edac */
 static struct sysdev_class edac_class = {
 	set_kset_name("edac"),
@@ -136,9 +134,15 @@
 static struct kobject edac_memctrl_kobj;
 static struct kobject edac_pci_kobj;
 
+/* We use these to wait for the reference counts on edac_memctrl_kobj and
+ * edac_pci_kobj to reach 0.
+ */
+static struct completion edac_memctrl_kobj_complete;
+static struct completion edac_pci_kobj_complete;
+
 /*
  * /sys/devices/system/edac/mc;
- * 	data structures and methods
+ *	data structures and methods
  */
 #if 0
 static ssize_t memctrl_string_show(void *ptr, char *buffer)
@@ -165,33 +169,34 @@
 }
 
 struct memctrl_dev_attribute {
-	struct attribute	attr;
-	void	*value;
+	struct attribute attr;
+	void *value;
 	ssize_t (*show)(void *,char *);
 	ssize_t (*store)(void *, const char *, size_t);
 };
 
 /* Set of show/store abstract level functions for memory control object */
-static ssize_t
-memctrl_dev_show(struct kobject *kobj, struct attribute *attr, char *buffer)
+static ssize_t memctrl_dev_show(struct kobject *kobj,
+		struct attribute *attr, char *buffer)
 {
 	struct memctrl_dev_attribute *memctrl_dev;
 	memctrl_dev = (struct memctrl_dev_attribute*)attr;
 
 	if (memctrl_dev->show)
 		return memctrl_dev->show(memctrl_dev->value, buffer);
+
 	return -EIO;
 }
 
-static ssize_t
-memctrl_dev_store(struct kobject *kobj, struct attribute *attr,
-			const char *buffer, size_t count)
+static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr,
+		const char *buffer, size_t count)
 {
 	struct memctrl_dev_attribute *memctrl_dev;
 	memctrl_dev = (struct memctrl_dev_attribute*)attr;
 
 	if (memctrl_dev->store)
 		return memctrl_dev->store(memctrl_dev->value, buffer, count);
+
 	return -EIO;
 }
 
@@ -227,7 +232,6 @@
 MEMCTRL_ATTR(log_ce,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
 MEMCTRL_ATTR(poll_msec,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
 
-
 /* Base Attributes of the memory ECC object */
 static struct memctrl_dev_attribute *memctrl_attr[] = {
 	&attr_panic_on_ue,
@@ -240,13 +244,14 @@
 /* Main MC kobject release() function */
 static void edac_memctrl_master_release(struct kobject *kobj)
 {
-	debugf1("EDAC MC: " __FILE__ ": %s()\n", __func__);
+	debugf1("%s()\n", __func__);
+	complete(&edac_memctrl_kobj_complete);
 }
 
 static struct kobj_type ktype_memctrl = {
-	.release	= edac_memctrl_master_release,
-	.sysfs_ops	= &memctrlfs_ops,
-	.default_attrs	= (struct attribute **) memctrl_attr,
+	.release = edac_memctrl_master_release,
+	.sysfs_ops = &memctrlfs_ops,
+	.default_attrs = (struct attribute **) memctrl_attr,
 };
 
 #endif  /* DISABLE_EDAC_SYSFS */
@@ -268,32 +273,31 @@
 {
 	int err=0;
 
-	debugf1("MC: " __FILE__ ": %s()\n", __func__);
+	debugf1("%s()\n", __func__);
 
 	/* create the /sys/devices/system/edac directory */
 	err = sysdev_class_register(&edac_class);
+
 	if (!err) {
 		/* Init the MC's kobject */
 		memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj));
-		kobject_init(&edac_memctrl_kobj);
-
 		edac_memctrl_kobj.parent = &edac_class.kset.kobj;
 		edac_memctrl_kobj.ktype = &ktype_memctrl;
 
 		/* generate sysfs "..../edac/mc"   */
 		err = kobject_set_name(&edac_memctrl_kobj,"mc");
+
 		if (!err) {
 			/* FIXME: maybe new sysdev_create_subdir() */
 			err = kobject_register(&edac_memctrl_kobj);
-			if (err) {
+
+			if (err)
 				debugf1("Failed to register '.../edac/mc'\n");
-			} else {
+			else
 				debugf1("Registered '.../edac/mc' kobject\n");
-			}
 		}
-	} else {
-		debugf1(KERN_WARNING "__FILE__ %s() error=%d\n", __func__,err);
-	}
+	} else
+		debugf1("%s() error=%d\n", __func__, err);
 
 	return err;
 }
@@ -308,11 +312,12 @@
 #ifndef DISABLE_EDAC_SYSFS
 	debugf0("MC: " __FILE__ ": %s()\n", __func__);
 
-	/* Unregister the MC's kobject */
+	/* Unregister the MC's kobject and wait for reference count to reach
+	 * 0.
+	 */
+	init_completion(&edac_memctrl_kobj_complete);
 	kobject_unregister(&edac_memctrl_kobj);
-
-	/* release the master edac mc kobject */
-	kobject_put(&edac_memctrl_kobj);
+	wait_for_completion(&edac_memctrl_kobj_complete);
 
 	/* Unregister the 'edac' object */
 	sysdev_class_unregister(&edac_class);
@@ -331,7 +336,6 @@
 	int *count;
 };
 
-
 #if 0
 /* Output the list as:  vendor_id:device:id<,vendor_id:device_id> */
 static ssize_t edac_pci_list_string_show(void *ptr, char *buffer)
@@ -356,7 +360,6 @@
 	}
 
 	len += snprintf(p + len,(PAGE_SIZE-len), "\n");
-
 	return (ssize_t) len;
 }
 
@@ -378,7 +381,7 @@
 
 	/* if null byte, we are done */
 	if (!**s) {
-		(*s)++;	/* keep *s moving */
+		(*s)++;  /* keep *s moving */
 		return 0;
 	}
 
@@ -395,6 +398,7 @@
 
 	/* parse vendor_id */
 	runner = *s;
+
 	while (runner < *e) {
 		/* scan for vendor:device delimiter */
 		if (*runner == ':') {
@@ -402,6 +406,7 @@
 			runner = p + 1;
 			break;
 		}
+
 		runner++;
 	}
 
@@ -417,12 +422,11 @@
 	}
 
 	*s = runner;
-
 	return 1;
 }
 
 static ssize_t edac_pci_list_string_store(void *ptr, const char *buffer,
-					size_t count)
+		size_t count)
 {
 	struct list_control *listctl;
 	struct edac_pci_device_list *list;
@@ -432,14 +436,12 @@
 
 	s = (char*)buffer;
 	e = s + count;
-
 	listctl = ptr;
 	list = listctl->list;
 	index = listctl->count;
-
 	*index = 0;
-	while (*index < MAX_LISTED_PCI_DEVICES) {
 
+	while (*index < MAX_LISTED_PCI_DEVICES) {
 		if (parse_one_device(&s,&e,&vendor_id,&device_id)) {
 			list[ *index ].vendor = vendor_id;
 			list[ *index ].device = device_id;
@@ -472,15 +474,15 @@
 }
 
 struct edac_pci_dev_attribute {
-	struct attribute	attr;
-	void	*value;
+	struct attribute attr;
+	void *value;
 	ssize_t (*show)(void *,char *);
 	ssize_t (*store)(void *, const char *,size_t);
 };
 
 /* Set of show/store abstract level functions for PCI Parity object */
 static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr,
-				char *buffer)
+		char *buffer)
 {
 	struct edac_pci_dev_attribute *edac_pci_dev;
 	edac_pci_dev= (struct edac_pci_dev_attribute*)attr;
@@ -490,8 +492,8 @@
 	return -EIO;
 }
 
-static ssize_t edac_pci_dev_store(struct kobject *kobj, struct attribute *attr,
-				const char *buffer, size_t count)
+static ssize_t edac_pci_dev_store(struct kobject *kobj,
+		struct attribute *attr, const char *buffer, size_t count)
 {
 	struct edac_pci_dev_attribute *edac_pci_dev;
 	edac_pci_dev= (struct edac_pci_dev_attribute*)attr;
@@ -506,7 +508,6 @@
 	.store  = edac_pci_dev_store
 };
 
-
 #define EDAC_PCI_ATTR(_name,_mode,_show,_store)			\
 struct edac_pci_dev_attribute edac_pci_attr_##_name = {		\
 	.attr = {.name = __stringify(_name), .mode = _mode },	\
@@ -549,9 +550,11 @@
 #endif
 
 /* PCI Parity control files */
-EDAC_PCI_ATTR(check_pci_parity,S_IRUGO|S_IWUSR,edac_pci_int_show,edac_pci_int_store);
-EDAC_PCI_ATTR(panic_on_pci_parity,S_IRUGO|S_IWUSR,edac_pci_int_show,edac_pci_int_store);
-EDAC_PCI_ATTR(pci_parity_count,S_IRUGO,edac_pci_int_show,NULL);
+EDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
+	edac_pci_int_store);
+EDAC_PCI_ATTR(panic_on_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
+	edac_pci_int_store);
+EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL);
 
 /* Base Attributes of the memory ECC object */
 static struct edac_pci_dev_attribute *edac_pci_attr[] = {
@@ -564,13 +567,14 @@
 /* No memory to release */
 static void edac_pci_release(struct kobject *kobj)
 {
-	debugf1("EDAC PCI: " __FILE__ ": %s()\n", __func__);
+	debugf1("%s()\n", __func__);
+	complete(&edac_pci_kobj_complete);
 }
 
 static struct kobj_type ktype_edac_pci = {
-	.release	= edac_pci_release,
-	.sysfs_ops	= &edac_pci_sysfs_ops,
-	.default_attrs	= (struct attribute **) edac_pci_attr,
+	.release = edac_pci_release,
+	.sysfs_ops = &edac_pci_sysfs_ops,
+	.default_attrs = (struct attribute **) edac_pci_attr,
 };
 
 #endif  /* DISABLE_EDAC_SYSFS */
@@ -588,24 +592,24 @@
 {
 	int err;
 
-	debugf1("MC: " __FILE__ ": %s()\n", __func__);
+	debugf1("%s()\n", __func__);
 
 	memset(&edac_pci_kobj, 0, sizeof(edac_pci_kobj));
-
-	kobject_init(&edac_pci_kobj);
 	edac_pci_kobj.parent = &edac_class.kset.kobj;
 	edac_pci_kobj.ktype = &ktype_edac_pci;
-
 	err = kobject_set_name(&edac_pci_kobj, "pci");
+
 	if (!err) {
 		/* Instanstiate the csrow object */
 		/* FIXME: maybe new sysdev_create_subdir() */
 		err = kobject_register(&edac_pci_kobj);
+
 		if (err)
 			debugf1("Failed to register '.../edac/pci'\n");
 		else
 			debugf1("Registered '.../edac/pci' kobject\n");
 	}
+
 	return err;
 }
 #endif  /* DISABLE_EDAC_SYSFS */
@@ -613,10 +617,10 @@
 static void edac_sysfs_pci_teardown(void)
 {
 #ifndef DISABLE_EDAC_SYSFS
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
-
+	debugf0("%s()\n", __func__);
+	init_completion(&edac_pci_kobj_complete);
 	kobject_unregister(&edac_pci_kobj);
-	kobject_put(&edac_pci_kobj);
+	wait_for_completion(&edac_pci_kobj_complete);
 #endif
 }
 
@@ -633,6 +637,7 @@
 		size = snprintf(data, EDAC_MC_LABEL_LEN,"%s\n",
 			csrow->channels[0].label);
 	}
+
 	return size;
 }
 
@@ -644,11 +649,12 @@
 		size = snprintf(data, EDAC_MC_LABEL_LEN, "%s\n",
 			csrow->channels[1].label);
 	}
+
 	return size;
 }
 
 static ssize_t csrow_ch0_dimm_label_store(struct csrow_info *csrow,
-			const char *data, size_t size)
+		const char *data, size_t size)
 {
 	ssize_t max_size = 0;
 
@@ -657,11 +663,12 @@
 		strncpy(csrow->channels[0].label, data, max_size);
 		csrow->channels[0].label[max_size] = '\0';
 	}
+
 	return size;
 }
 
 static ssize_t csrow_ch1_dimm_label_store(struct csrow_info *csrow,
-			const char *data, size_t size)
+		const char *data, size_t size)
 {
 	ssize_t max_size = 0;
 
@@ -670,6 +677,7 @@
 		strncpy(csrow->channels[1].label, data, max_size);
 		csrow->channels[1].label[max_size] = '\0';
 	}
+
 	return max_size;
 }
 
@@ -690,6 +698,7 @@
 	if (csrow->nr_channels > 0) {
 		size = sprintf(data,"%u\n", csrow->channels[0].ce_count);
 	}
+
 	return size;
 }
 
@@ -700,6 +709,7 @@
 	if (csrow->nr_channels > 1) {
 		size = sprintf(data,"%u\n", csrow->channels[1].ce_count);
 	}
+
 	return size;
 }
 
@@ -724,7 +734,7 @@
 }
 
 struct csrowdev_attribute {
-	struct attribute	attr;
+	struct attribute attr;
 	ssize_t (*show)(struct csrow_info *,char *);
 	ssize_t (*store)(struct csrow_info *, const char *,size_t);
 };
@@ -734,24 +744,26 @@
 
 /* Set of show/store higher level functions for csrow objects */
 static ssize_t csrowdev_show(struct kobject *kobj, struct attribute *attr,
-				char *buffer)
+		char *buffer)
 {
 	struct csrow_info *csrow = to_csrow(kobj);
 	struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
 
 	if (csrowdev_attr->show)
 		return csrowdev_attr->show(csrow, buffer);
+
 	return -EIO;
 }
 
 static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
-				const char *buffer, size_t count)
+		const char *buffer, size_t count)
 {
 	struct csrow_info *csrow = to_csrow(kobj);
 	struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr);
 
 	if (csrowdev_attr->store)
 		return csrowdev_attr->store(csrow, buffer, count);
+
 	return -EIO;
 }
 
@@ -785,7 +797,6 @@
 		csrow_ch1_dimm_label_show,
 		csrow_ch1_dimm_label_store);
 
-
 /* Attributes of the CSROW<id> object */
 static struct csrowdev_attribute *csrow_attr[] = {
 	&attr_dev_type,
@@ -801,40 +812,43 @@
 	NULL,
 };
 
-
 /* No memory to release */
 static void edac_csrow_instance_release(struct kobject *kobj)
 {
-	debugf1("EDAC MC: " __FILE__ ": %s()\n", __func__);
+	struct csrow_info *cs;
+
+	debugf1("%s()\n", __func__);
+	cs = container_of(kobj, struct csrow_info, kobj);
+	complete(&cs->kobj_complete);
 }
 
 static struct kobj_type ktype_csrow = {
-	.release	= edac_csrow_instance_release,
-	.sysfs_ops	= &csrowfs_ops,
-	.default_attrs	= (struct attribute **) csrow_attr,
+	.release = edac_csrow_instance_release,
+	.sysfs_ops = &csrowfs_ops,
+	.default_attrs = (struct attribute **) csrow_attr,
 };
 
 /* Create a CSROW object under specifed edac_mc_device */
 static int edac_create_csrow_object(struct kobject *edac_mci_kobj,
-				struct csrow_info *csrow, int index )
+		struct csrow_info *csrow, int index)
 {
 	int err = 0;
 
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
-
+	debugf0("%s()\n", __func__);
 	memset(&csrow->kobj, 0, sizeof(csrow->kobj));
 
 	/* generate ..../edac/mc/mc<id>/csrow<index>   */
 
-	kobject_init(&csrow->kobj);
 	csrow->kobj.parent = edac_mci_kobj;
 	csrow->kobj.ktype = &ktype_csrow;
 
 	/* name this instance of csrow<id> */
 	err = kobject_set_name(&csrow->kobj,"csrow%d",index);
+
 	if (!err) {
 		/* Instanstiate the csrow object */
 		err = kobject_register(&csrow->kobj);
+
 		if (err)
 			debugf0("Failed to register CSROW%d\n",index);
 		else
@@ -846,8 +860,8 @@
 
 /* sysfs data structures and methods for the MCI kobjects */
 
-static ssize_t mci_reset_counters_store(struct mem_ctl_info  *mci,
-					const char *data, size_t count )
+static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
+		const char *data, size_t count)
 {
 	int row, chan;
 
@@ -855,16 +869,18 @@
 	mci->ce_noinfo_count = 0;
 	mci->ue_count = 0;
 	mci->ce_count = 0;
+
 	for (row = 0; row < mci->nr_csrows; row++) {
 		struct csrow_info *ri = &mci->csrows[row];
 
 		ri->ue_count = 0;
 		ri->ce_count = 0;
+
 		for (chan = 0; chan < ri->nr_channels; chan++)
 			ri->channels[chan].ce_count = 0;
 	}
-	mci->start_time = jiffies;
 
+	mci->start_time = jiffies;
 	return count;
 }
 
@@ -922,18 +938,16 @@
 
 	p += mci_output_edac_cap(p,mci->edac_ctl_cap);
 	p += sprintf(p, "\n");
-
 	return p - data;
 }
 
 static ssize_t mci_edac_current_capability_show(struct mem_ctl_info *mci,
-						char *data)
+		char *data)
 {
 	char *p = data;
 
 	p += mci_output_edac_cap(p,mci->edac_cap);
 	p += sprintf(p, "\n");
-
 	return p - data;
 }
 
@@ -950,13 +964,13 @@
 	return p - buf;
 }
 
-static ssize_t mci_supported_mem_type_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_supported_mem_type_show(struct mem_ctl_info *mci,
+		char *data)
 {
 	char *p = data;
 
 	p += mci_output_mtype_cap(p,mci->mtype_cap);
 	p += sprintf(p, "\n");
-
 	return p - data;
 }
 
@@ -970,6 +984,7 @@
 
 		if (!csrow->nr_pages)
 			continue;
+
 		total_pages += csrow->nr_pages;
 	}
 
@@ -977,7 +992,7 @@
 }
 
 struct mcidev_attribute {
-	struct attribute	attr;
+	struct attribute attr;
 	ssize_t (*show)(struct mem_ctl_info *,char *);
 	ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
 };
@@ -986,30 +1001,32 @@
 #define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr)
 
 static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
-			char *buffer)
+		char *buffer)
 {
 	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
 	struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr);
 
 	if (mcidev_attr->show)
 		return mcidev_attr->show(mem_ctl_info, buffer);
+
 	return -EIO;
 }
 
 static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
-				const char *buffer, size_t count)
+		const char *buffer, size_t count)
 {
 	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
 	struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr);
 
 	if (mcidev_attr->store)
 		return mcidev_attr->store(mem_ctl_info, buffer, count);
+
 	return -EIO;
 }
 
 static struct sysfs_ops mci_ops = {
-	.show   = mcidev_show,
-	.store  = mcidev_store
+	.show = mcidev_show,
+	.store = mcidev_store
 };
 
 #define MCIDEV_ATTR(_name,_mode,_show,_store)			\
@@ -1037,7 +1054,6 @@
 MCIDEV_ATTR(supported_mem_type,S_IRUGO,
 	mci_supported_mem_type_show,NULL);
 
-
 static struct mcidev_attribute *mci_attr[] = {
 	&mci_attr_reset_counters,
 	&mci_attr_module_name,
@@ -1054,25 +1070,22 @@
 	NULL
 };
 
-
 /*
  * Release of a MC controlling instance
  */
 static void edac_mci_instance_release(struct kobject *kobj)
 {
 	struct mem_ctl_info *mci;
-	mci = container_of(kobj,struct mem_ctl_info,edac_mci_kobj);
 
-	debugf0("MC: " __FILE__ ": %s() idx=%d calling kfree\n",
-		__func__, mci->mc_idx);
-
-	kfree(mci);
+	mci = to_mci(kobj);
+	debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
+	complete(&mci->kobj_complete);
 }
 
 static struct kobj_type ktype_mci = {
-	.release	= edac_mci_instance_release,
-	.sysfs_ops	= &mci_ops,
-	.default_attrs	= (struct attribute **) mci_attr,
+	.release = edac_mci_instance_release,
+	.sysfs_ops = &mci_ops,
+	.default_attrs = (struct attribute **) mci_attr,
 };
 
 #endif  /* DISABLE_EDAC_SYSFS */
@@ -1099,13 +1112,12 @@
 	struct csrow_info *csrow;
 	struct kobject *edac_mci_kobj=&mci->edac_mci_kobj;
 
-	debugf0("MC: " __FILE__ ": %s() idx=%d\n", __func__, mci->mc_idx);
-
+	debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
 	memset(edac_mci_kobj, 0, sizeof(*edac_mci_kobj));
-	kobject_init(edac_mci_kobj);
 
 	/* set the name of the mc<id> object */
 	err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx);
+
 	if (err)
 		return err;
 
@@ -1115,50 +1127,48 @@
 
 	/* register the mc<id> kobject */
 	err = kobject_register(edac_mci_kobj);
+
 	if (err)
 		return err;
 
 	/* create a symlink for the device */
 	err = sysfs_create_link(edac_mci_kobj, &mci->pdev->dev.kobj,
 				EDAC_DEVICE_SYMLINK);
-	if (err) {
-		kobject_unregister(edac_mci_kobj);
-		return err;
-	}
+
+	if (err)
+		goto fail0;
 
 	/* Make directories for each CSROW object
 	 * under the mc<id> kobject
 	 */
 	for (i = 0; i < mci->nr_csrows; i++) {
-
 		csrow = &mci->csrows[i];
 
 		/* Only expose populated CSROWs */
 		if (csrow->nr_pages > 0) {
 			err = edac_create_csrow_object(edac_mci_kobj,csrow,i);
+
 			if (err)
-				goto fail;
+				goto fail1;
 		}
 	}
 
-	/* Mark this MCI instance as having sysfs entries */
-	mci->sysfs_active = MCI_SYSFS_ACTIVE;
-
 	return 0;
 
-
 	/* CSROW error: backout what has already been registered,  */
-fail:
+fail1:
 	for ( i--; i >= 0; i--) {
 		if (csrow->nr_pages > 0) {
+			init_completion(&csrow->kobj_complete);
 			kobject_unregister(&mci->csrows[i].kobj);
-			kobject_put(&mci->csrows[i].kobj);
+			wait_for_completion(&csrow->kobj_complete);
 		}
 	}
 
+fail0:
+	init_completion(&mci->kobj_complete);
 	kobject_unregister(edac_mci_kobj);
-	kobject_put(edac_mci_kobj);
-
+	wait_for_completion(&mci->kobj_complete);
 	return err;
 }
 #endif  /* DISABLE_EDAC_SYSFS */
@@ -1171,20 +1181,21 @@
 #ifndef DISABLE_EDAC_SYSFS
 	int i;
 
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
 
 	/* remove all csrow kobjects */
 	for (i = 0; i < mci->nr_csrows; i++) {
-		if (mci->csrows[i].nr_pages > 0)  {
+		if (mci->csrows[i].nr_pages > 0) {
+			init_completion(&mci->csrows[i].kobj_complete);
 			kobject_unregister(&mci->csrows[i].kobj);
-			kobject_put(&mci->csrows[i].kobj);
+			wait_for_completion(&mci->csrows[i].kobj_complete);
 		}
 	}
 
 	sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
-
+	init_completion(&mci->kobj_complete);
 	kobject_unregister(&mci->edac_mci_kobj);
-	kobject_put(&mci->edac_mci_kobj);
+	wait_for_completion(&mci->kobj_complete);
 #endif  /* DISABLE_EDAC_SYSFS */
 }
 
@@ -1192,8 +1203,6 @@
 
 #ifdef CONFIG_EDAC_DEBUG
 
-EXPORT_SYMBOL(edac_mc_dump_channel);
-
 void edac_mc_dump_channel(struct channel_info *chan)
 {
 	debugf4("\tchannel = %p\n", chan);
@@ -1202,9 +1211,7 @@
 	debugf4("\tchannel->label = '%s'\n", chan->label);
 	debugf4("\tchannel->csrow = %p\n\n", chan->csrow);
 }
-
-
-EXPORT_SYMBOL(edac_mc_dump_csrow);
+EXPORT_SYMBOL_GPL(edac_mc_dump_channel);
 
 void edac_mc_dump_csrow(struct csrow_info *csrow)
 {
@@ -1220,9 +1227,7 @@
 	debugf4("\tcsrow->channels = %p\n", csrow->channels);
 	debugf4("\tcsrow->mci = %p\n\n", csrow->mci);
 }
-
-
-EXPORT_SYMBOL(edac_mc_dump_mci);
+EXPORT_SYMBOL_GPL(edac_mc_dump_csrow);
 
 void edac_mc_dump_mci(struct mem_ctl_info *mci)
 {
@@ -1238,9 +1243,9 @@
 		mci->mod_name, mci->ctl_name);
 	debugf3("\tpvt_info = %p\n\n", mci->pvt_info);
 }
+EXPORT_SYMBOL_GPL(edac_mc_dump_mci);
 
-
-#endif				/* CONFIG_EDAC_DEBUG */
+#endif  /* CONFIG_EDAC_DEBUG */
 
 /* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'.
  * Adjust 'ptr' so that its alignment is at least as stringent as what the
@@ -1249,7 +1254,7 @@
  * If 'size' is a constant, the compiler will optimize this whole function
  * down to either a no-op or the addition of a constant to the value of 'ptr'.
  */
-static inline char * align_ptr (void *ptr, unsigned size)
+static inline char * align_ptr(void *ptr, unsigned size)
 {
 	unsigned align, r;
 
@@ -1276,9 +1281,6 @@
 	return (char *) (((unsigned long) ptr) + align - r);
 }
 
-
-EXPORT_SYMBOL(edac_mc_alloc);
-
 /**
  * edac_mc_alloc: Allocate a struct mem_ctl_info structure
  * @size_pvt:	size of private storage needed
@@ -1296,7 +1298,7 @@
  *	struct mem_ctl_info pointer
  */
 struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
-					unsigned nr_chans)
+		unsigned nr_chans)
 {
 	struct mem_ctl_info *mci;
 	struct csrow_info *csi, *csrow;
@@ -1327,8 +1329,7 @@
 	chi = (struct channel_info *) (((char *) mci) + ((unsigned long) chi));
 	pvt = sz_pvt ? (((char *) mci) + ((unsigned long) pvt)) : NULL;
 
-	memset(mci, 0, size);	/* clear all fields */
-
+	memset(mci, 0, size);  /* clear all fields */
 	mci->csrows = csi;
 	mci->pvt_info = pvt;
 	mci->nr_csrows = nr_csrows;
@@ -1350,50 +1351,24 @@
 
 	return mci;
 }
-
-
-EXPORT_SYMBOL(edac_mc_free);
+EXPORT_SYMBOL_GPL(edac_mc_alloc);
 
 /**
  * edac_mc_free:  Free a previously allocated 'mci' structure
  * @mci: pointer to a struct mem_ctl_info structure
- *
- * Free up a previously allocated mci structure
- * A MCI structure can be in 2 states after being allocated
- * by edac_mc_alloc().
- *	1) Allocated in a MC driver's probe, but not yet committed
- *	2) Allocated and committed, by a call to  edac_mc_add_mc()
- * edac_mc_add_mc() is the function that adds the sysfs entries
- * thus, this free function must determine which state the 'mci'
- * structure is in, then either free it directly or
- * perform kobject cleanup by calling edac_remove_sysfs_mci_device().
- *
- * VOID Return
  */
 void edac_mc_free(struct mem_ctl_info *mci)
 {
-	/* only if sysfs entries for this mci instance exist
-	 * do we remove them and defer the actual kfree via
-	 * the kobject 'release()' callback.
- 	 *
-	 * Otherwise, do a straight kfree now.
-	 */
-	if (mci->sysfs_active == MCI_SYSFS_ACTIVE)
-		edac_remove_sysfs_mci_device(mci);
-	else
-		kfree(mci);
+	kfree(mci);
 }
+EXPORT_SYMBOL_GPL(edac_mc_free);
 
-
-
-EXPORT_SYMBOL(edac_mc_find_mci_by_pdev);
-
-struct mem_ctl_info *edac_mc_find_mci_by_pdev(struct pci_dev *pdev)
+static struct mem_ctl_info *find_mci_by_pdev(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 	struct list_head *item;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 
 	list_for_each(item, &mc_devices) {
 		mci = list_entry(item, struct mem_ctl_info, link);
@@ -1405,7 +1380,7 @@
 	return NULL;
 }
 
-static int add_mc_to_global_list (struct mem_ctl_info *mci)
+static int add_mc_to_global_list(struct mem_ctl_info *mci)
 {
 	struct list_head *item, *insert_before;
 	struct mem_ctl_info *p;
@@ -1415,11 +1390,12 @@
 		mci->mc_idx = 0;
 		insert_before = &mc_devices;
 	} else {
-		if (edac_mc_find_mci_by_pdev(mci->pdev)) {
-			printk(KERN_WARNING
-				"EDAC MC: %s (%s) %s %s already assigned %d\n",
-				mci->pdev->dev.bus_id, pci_name(mci->pdev),
-				mci->mod_name, mci->ctl_name, mci->mc_idx);
+		if (find_mci_by_pdev(mci->pdev)) {
+			edac_printk(KERN_WARNING, EDAC_MC,
+				"%s (%s) %s %s already assigned %d\n",
+				mci->pdev->dev.bus_id,
+				pci_name(mci->pdev), mci->mod_name,
+				mci->ctl_name, mci->mc_idx);
 			return 1;
 		}
 
@@ -1447,12 +1423,26 @@
 	return 0;
 }
 
+static void complete_mc_list_del(struct rcu_head *head)
+{
+	struct mem_ctl_info *mci;
 
+	mci = container_of(head, struct mem_ctl_info, rcu);
+	INIT_LIST_HEAD(&mci->link);
+	complete(&mci->complete);
+}
 
-EXPORT_SYMBOL(edac_mc_add_mc);
+static void del_mc_from_global_list(struct mem_ctl_info *mci)
+{
+	list_del_rcu(&mci->link);
+	init_completion(&mci->complete);
+	call_rcu(&mci->rcu, complete_mc_list_del);
+	wait_for_completion(&mci->complete);
+}
 
 /**
- * edac_mc_add_mc: Insert the 'mci' structure into the mci global list
+ * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and
+ *                 create sysfs entries associated with mci structure
  * @mci: pointer to the mci structure to be added to the list
  *
  * Return:
@@ -1463,111 +1453,90 @@
 /* FIXME - should a warning be printed if no error detection? correction? */
 int edac_mc_add_mc(struct mem_ctl_info *mci)
 {
-	int rc = 1;
-
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
 #ifdef CONFIG_EDAC_DEBUG
 	if (edac_debug_level >= 3)
 		edac_mc_dump_mci(mci);
+
 	if (edac_debug_level >= 4) {
 		int i;
 
 		for (i = 0; i < mci->nr_csrows; i++) {
 			int j;
+
 			edac_mc_dump_csrow(&mci->csrows[i]);
 			for (j = 0; j < mci->csrows[i].nr_channels; j++)
-				edac_mc_dump_channel(&mci->csrows[i].
-							  channels[j]);
+				edac_mc_dump_channel(
+					&mci->csrows[i].channels[j]);
 		}
 	}
 #endif
 	down(&mem_ctls_mutex);
 
 	if (add_mc_to_global_list(mci))
-		goto finish;
+		goto fail0;
 
 	/* set load time so that error rate can be tracked */
 	mci->start_time = jiffies;
 
         if (edac_create_sysfs_mci_device(mci)) {
-                printk(KERN_WARNING
-                       "EDAC MC%d: failed to create sysfs device\n",
-                       mci->mc_idx);
-		/* FIXME - should there be an error code and unwind? */
-                goto finish;
+                edac_mc_printk(mci, KERN_WARNING,
+			"failed to create sysfs device\n");
+                goto fail1;
         }
 
 	/* Report action taken */
-	printk(KERN_INFO
-	       "EDAC MC%d: Giving out device to %s %s: PCI %s\n",
-	       mci->mc_idx, mci->mod_name, mci->ctl_name,
-	       pci_name(mci->pdev));
+	edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: PCI %s\n",
+		mci->mod_name, mci->ctl_name, pci_name(mci->pdev));
 
-
-	rc = 0;
-
-finish:
 	up(&mem_ctls_mutex);
-	return rc;
+	return 0;
+
+fail1:
+	del_mc_from_global_list(mci);
+
+fail0:
+	up(&mem_ctls_mutex);
+	return 1;
 }
+EXPORT_SYMBOL_GPL(edac_mc_add_mc);
 
-
-
-static void complete_mc_list_del (struct rcu_head *head)
+/**
+ * edac_mc_del_mc: Remove sysfs entries for specified mci structure and
+ *                 remove mci structure from global list
+ * @pdev: Pointer to 'struct pci_dev' representing mci structure to remove.
+ *
+ * Return pointer to removed mci structure, or NULL if device not found.
+ */
+struct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 
-	mci = container_of(head, struct mem_ctl_info, rcu);
-	INIT_LIST_HEAD(&mci->link);
-	complete(&mci->complete);
-}
-
-static void del_mc_from_global_list (struct mem_ctl_info *mci)
-{
-	list_del_rcu(&mci->link);
-	init_completion(&mci->complete);
-	call_rcu(&mci->rcu, complete_mc_list_del);
-	wait_for_completion(&mci->complete);
-}
-
-EXPORT_SYMBOL(edac_mc_del_mc);
-
-/**
- * edac_mc_del_mc:  Remove the specified mci structure from global list
- * @mci:	Pointer to struct mem_ctl_info structure
- *
- * Returns:
- *	0	Success
- *	1 	Failure
- */
-int edac_mc_del_mc(struct mem_ctl_info *mci)
-{
-	int rc = 1;
-
-	debugf0("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+	debugf0("MC: %s()\n", __func__);
 	down(&mem_ctls_mutex);
+
+	if ((mci = find_mci_by_pdev(pdev)) == NULL) {
+		up(&mem_ctls_mutex);
+		return NULL;
+	}
+
+	edac_remove_sysfs_mci_device(mci);
 	del_mc_from_global_list(mci);
-	printk(KERN_INFO
-	       "EDAC MC%d: Removed device %d for %s %s: PCI %s\n",
-	       mci->mc_idx, mci->mc_idx, mci->mod_name, mci->ctl_name,
-	       pci_name(mci->pdev));
-	rc = 0;
 	up(&mem_ctls_mutex);
-
-	return rc;
+	edac_printk(KERN_INFO, EDAC_MC,
+		"Removed device %d for %s %s: PCI %s\n", mci->mc_idx,
+		mci->mod_name, mci->ctl_name, pci_name(mci->pdev));
+	return mci;
 }
+EXPORT_SYMBOL_GPL(edac_mc_del_mc);
 
-
-EXPORT_SYMBOL(edac_mc_scrub_block);
-
-void edac_mc_scrub_block(unsigned long page, unsigned long offset,
-			      u32 size)
+void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
 {
 	struct page *pg;
 	void *virt_addr;
 	unsigned long flags = 0;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 
 	/* ECC error page was not in our memory. Ignore it. */
 	if(!pfn_valid(page))
@@ -1590,19 +1559,15 @@
 	if (PageHighMem(pg))
 		local_irq_restore(flags);
 }
-
+EXPORT_SYMBOL_GPL(edac_mc_scrub_block);
 
 /* FIXME - should return -1 */
-EXPORT_SYMBOL(edac_mc_find_csrow_by_page);
-
-int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
-				    unsigned long page)
+int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
 {
 	struct csrow_info *csrows = mci->csrows;
 	int row, i;
 
-	debugf1("MC%d: " __FILE__ ": %s(): 0x%lx\n", mci->mc_idx, __func__,
-		page);
+	debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page);
 	row = -1;
 
 	for (i = 0; i < mci->nr_csrows; i++) {
@@ -1611,11 +1576,10 @@
 		if (csrow->nr_pages == 0)
 			continue;
 
-		debugf3("MC%d: " __FILE__
-			": %s(): first(0x%lx) page(0x%lx)"
-			" last(0x%lx) mask(0x%lx)\n", mci->mc_idx,
-			__func__, csrow->first_page, page,
-			csrow->last_page, csrow->page_mask);
+		debugf3("MC%d: %s(): first(0x%lx) page(0x%lx) last(0x%lx) "
+			"mask(0x%lx)\n", mci->mc_idx, __func__,
+			csrow->first_page, page, csrow->last_page,
+			csrow->page_mask);
 
 		if ((page >= csrow->first_page) &&
 		    (page <= csrow->last_page) &&
@@ -1627,56 +1591,52 @@
 	}
 
 	if (row == -1)
-		printk(KERN_ERR
-		       "EDAC MC%d: could not look up page error address %lx\n",
-		       mci->mc_idx, (unsigned long) page);
+		edac_mc_printk(mci, KERN_ERR,
+			"could not look up page error address %lx\n",
+			(unsigned long) page);
 
 	return row;
 }
-
-
-EXPORT_SYMBOL(edac_mc_handle_ce);
+EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page);
 
 /* FIXME - setable log (warning/emerg) levels */
 /* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */
 void edac_mc_handle_ce(struct mem_ctl_info *mci,
-			    unsigned long page_frame_number,
-			    unsigned long offset_in_page,
-			    unsigned long syndrome, int row, int channel,
-			    const char *msg)
+		unsigned long page_frame_number, unsigned long offset_in_page,
+		unsigned long syndrome, int row, int channel, const char *msg)
 {
 	unsigned long remapped_page;
 
-	debugf3("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+	debugf3("MC%d: %s()\n", mci->mc_idx, __func__);
 
 	/* FIXME - maybe make panic on INTERNAL ERROR an option */
 	if (row >= mci->nr_csrows || row < 0) {
 		/* something is wrong */
-		printk(KERN_ERR
-		       "EDAC MC%d: INTERNAL ERROR: row out of range (%d >= %d)\n",
-		       mci->mc_idx, row, mci->nr_csrows);
+		edac_mc_printk(mci, KERN_ERR,
+			"INTERNAL ERROR: row out of range "
+			"(%d >= %d)\n", row, mci->nr_csrows);
 		edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
 		return;
 	}
+
 	if (channel >= mci->csrows[row].nr_channels || channel < 0) {
 		/* something is wrong */
-		printk(KERN_ERR
-		       "EDAC MC%d: INTERNAL ERROR: channel out of range "
-		       "(%d >= %d)\n",
-		       mci->mc_idx, channel, mci->csrows[row].nr_channels);
+		edac_mc_printk(mci, KERN_ERR,
+			"INTERNAL ERROR: channel out of range "
+			"(%d >= %d)\n", channel,
+			mci->csrows[row].nr_channels);
 		edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
 		return;
 	}
 
 	if (log_ce)
 		/* FIXME - put in DIMM location */
-		printk(KERN_WARNING
-		       "EDAC MC%d: CE page 0x%lx, offset 0x%lx,"
-		       " grain %d, syndrome 0x%lx, row %d, channel %d,"
-		       " label \"%s\": %s\n", mci->mc_idx,
-		       page_frame_number, offset_in_page,
-		       mci->csrows[row].grain, syndrome, row, channel,
-		       mci->csrows[row].channels[channel].label, msg);
+		edac_mc_printk(mci, KERN_WARNING,
+			"CE page 0x%lx, offset 0x%lx, grain %d, syndrome "
+			"0x%lx, row %d, channel %d, label \"%s\": %s\n",
+			page_frame_number, offset_in_page,
+			mci->csrows[row].grain, syndrome, row, channel,
+			mci->csrows[row].channels[channel].label, msg);
 
 	mci->ce_count++;
 	mci->csrows[row].ce_count++;
@@ -1697,31 +1657,25 @@
 		    page_frame_number;
 
 		edac_mc_scrub_block(remapped_page, offset_in_page,
-					 mci->csrows[row].grain);
+					mci->csrows[row].grain);
 	}
 }
+EXPORT_SYMBOL_GPL(edac_mc_handle_ce);
 
-
-EXPORT_SYMBOL(edac_mc_handle_ce_no_info);
-
-void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci,
-				    const char *msg)
+void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
 {
 	if (log_ce)
-		printk(KERN_WARNING
-		       "EDAC MC%d: CE - no information available: %s\n",
-		       mci->mc_idx, msg);
+		edac_mc_printk(mci, KERN_WARNING,
+			"CE - no information available: %s\n", msg);
+
 	mci->ce_noinfo_count++;
 	mci->ce_count++;
 }
-
-
-EXPORT_SYMBOL(edac_mc_handle_ue);
+EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info);
 
 void edac_mc_handle_ue(struct mem_ctl_info *mci,
-			    unsigned long page_frame_number,
-			    unsigned long offset_in_page, int row,
-			    const char *msg)
+		unsigned long page_frame_number, unsigned long offset_in_page,
+		int row, const char *msg)
 {
 	int len = EDAC_MC_LABEL_LEN * 4;
 	char labels[len + 1];
@@ -1729,65 +1683,61 @@
 	int chan;
 	int chars;
 
-	debugf3("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+	debugf3("MC%d: %s()\n", mci->mc_idx, __func__);
 
 	/* FIXME - maybe make panic on INTERNAL ERROR an option */
 	if (row >= mci->nr_csrows || row < 0) {
 		/* something is wrong */
-		printk(KERN_ERR
-		       "EDAC MC%d: INTERNAL ERROR: row out of range (%d >= %d)\n",
-		       mci->mc_idx, row, mci->nr_csrows);
+		edac_mc_printk(mci, KERN_ERR,
+			"INTERNAL ERROR: row out of range "
+			"(%d >= %d)\n", row, mci->nr_csrows);
 		edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
 		return;
 	}
 
 	chars = snprintf(pos, len + 1, "%s",
-			 mci->csrows[row].channels[0].label);
+			mci->csrows[row].channels[0].label);
 	len -= chars;
 	pos += chars;
+
 	for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0);
 	     chan++) {
 		chars = snprintf(pos, len + 1, ":%s",
-				 mci->csrows[row].channels[chan].label);
+				mci->csrows[row].channels[chan].label);
 		len -= chars;
 		pos += chars;
 	}
 
 	if (log_ue)
-		printk(KERN_EMERG
-		       "EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, row %d,"
-		       " labels \"%s\": %s\n", mci->mc_idx,
-		       page_frame_number, offset_in_page,
-		       mci->csrows[row].grain, row, labels, msg);
+		edac_mc_printk(mci, KERN_EMERG,
+			"UE page 0x%lx, offset 0x%lx, grain %d, row %d, "
+			"labels \"%s\": %s\n", page_frame_number,
+			offset_in_page, mci->csrows[row].grain, row, labels,
+			msg);
 
 	if (panic_on_ue)
-		panic
-		    ("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, row %d,"
-		     " labels \"%s\": %s\n", mci->mc_idx,
-		     page_frame_number, offset_in_page,
-		     mci->csrows[row].grain, row, labels, msg);
+		panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, "
+			"row %d, labels \"%s\": %s\n", mci->mc_idx,
+			page_frame_number, offset_in_page,
+			mci->csrows[row].grain, row, labels, msg);
 
 	mci->ue_count++;
 	mci->csrows[row].ue_count++;
 }
+EXPORT_SYMBOL_GPL(edac_mc_handle_ue);
 
-
-EXPORT_SYMBOL(edac_mc_handle_ue_no_info);
-
-void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci,
-				    const char *msg)
+void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
 {
 	if (panic_on_ue)
 		panic("EDAC MC%d: Uncorrected Error", mci->mc_idx);
 
 	if (log_ue)
-		printk(KERN_WARNING
-		       "EDAC MC%d: UE - no information available: %s\n",
-		       mci->mc_idx, msg);
+		edac_mc_printk(mci, KERN_WARNING,
+			"UE - no information available: %s\n", msg);
 	mci->ue_noinfo_count++;
 	mci->ue_count++;
 }
-
+EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info);
 
 #ifdef CONFIG_PCI
 
@@ -1799,18 +1749,22 @@
 	where = secondary ? PCI_SEC_STATUS : PCI_STATUS;
 	pci_read_config_word(dev, where, &status);
 
-	/* If we get back 0xFFFF then we must suspect that the card has been pulled but
-	   the Linux PCI layer has not yet finished cleaning up. We don't want to report
-	   on such devices */
+	/* If we get back 0xFFFF then we must suspect that the card has been
+	 * pulled but the Linux PCI layer has not yet finished cleaning up.
+	 * We don't want to report on such devices
+	 */
 
 	if (status == 0xFFFF) {
 		u32 sanity;
+
 		pci_read_config_dword(dev, 0, &sanity);
+
 		if (sanity == 0xFFFFFFFF)
 			return 0;
 	}
+
 	status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |
-		  PCI_STATUS_PARITY;
+		PCI_STATUS_PARITY;
 
 	if (status)
 		/* reset only the bits we are interested in */
@@ -1822,7 +1776,7 @@
 typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);
 
 /* Clear any PCI parity errors logged by this device. */
-static void edac_pci_dev_parity_clear( struct pci_dev *dev )
+static void edac_pci_dev_parity_clear(struct pci_dev *dev)
 {
 	u8 header_type;
 
@@ -1853,25 +1807,22 @@
 	/* check the status reg for errors */
 	if (status) {
 		if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
-			printk(KERN_CRIT
-			   	"EDAC PCI- "
+			edac_printk(KERN_CRIT, EDAC_PCI,
 				"Signaled System Error on %s\n",
-				pci_name (dev));
+				pci_name(dev));
 
 		if (status & (PCI_STATUS_PARITY)) {
-			printk(KERN_CRIT
-			   	"EDAC PCI- "
+			edac_printk(KERN_CRIT, EDAC_PCI,
 				"Master Data Parity Error on %s\n",
-				pci_name (dev));
+				pci_name(dev));
 
 			atomic_inc(&pci_parity_count);
 		}
 
 		if (status & (PCI_STATUS_DETECTED_PARITY)) {
-			printk(KERN_CRIT
-			   	"EDAC PCI- "
+			edac_printk(KERN_CRIT, EDAC_PCI,
 				"Detected Parity Error on %s\n",
-				pci_name (dev));
+				pci_name(dev));
 
 			atomic_inc(&pci_parity_count);
 		}
@@ -1892,25 +1843,22 @@
 		/* check the secondary status reg for errors */
 		if (status) {
 			if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
-				printk(KERN_CRIT
-					"EDAC PCI-Bridge- "
+				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
 					"Signaled System Error on %s\n",
-					pci_name (dev));
+					pci_name(dev));
 
 			if (status & (PCI_STATUS_PARITY)) {
-				printk(KERN_CRIT
-					"EDAC PCI-Bridge- "
-					"Master Data Parity Error on %s\n",
-					pci_name (dev));
+				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+					"Master Data Parity Error on "
+					"%s\n", pci_name(dev));
 
 				atomic_inc(&pci_parity_count);
 			}
 
 			if (status & (PCI_STATUS_DETECTED_PARITY)) {
-				printk(KERN_CRIT
-					"EDAC PCI-Bridge- "
+				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
 					"Detected Parity Error on %s\n",
-					pci_name (dev));
+					pci_name(dev));
 
 				atomic_inc(&pci_parity_count);
 			}
@@ -1929,58 +1877,55 @@
  * Returns:  	0 not found
  *		1 found on list
  */
-static int check_dev_on_list(struct edac_pci_device_list *list, int free_index,
-				struct pci_dev *dev)
+static int check_dev_on_list(struct edac_pci_device_list *list,
+		int free_index, struct pci_dev *dev)
 {
-        int i;
-        int rc = 0;     /* Assume not found */
-        unsigned short vendor=dev->vendor;
-        unsigned short device=dev->device;
+	int i;
+	int rc = 0;     /* Assume not found */
+	unsigned short vendor=dev->vendor;
+	unsigned short device=dev->device;
 
-        /* Scan the list, looking for a vendor/device match
-         */
-        for (i = 0; i < free_index; i++, list++ ) {
-                if (    (list->vendor == vendor ) &&
-                        (list->device == device )) {
-                        rc = 1;
-                        break;
-                }
-        }
+	/* Scan the list, looking for a vendor/device match */
+	for (i = 0; i < free_index; i++, list++ ) {
+		if ((list->vendor == vendor ) && (list->device == device )) {
+			rc = 1;
+			break;
+		}
+	}
 
-        return rc;
+	return rc;
 }
 
 /*
  * pci_dev parity list iterator
- * 	Scan the PCI device list for one iteration, looking for SERRORs
+ *	Scan the PCI device list for one iteration, looking for SERRORs
  *	Master Parity ERRORS or Parity ERRORs on primary or secondary devices
  */
 static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
 {
-	struct pci_dev *dev=NULL;
+	struct pci_dev *dev = NULL;
 
 	/* request for kernel access to the next PCI device, if any,
 	 * and while we are looking at it have its reference count
 	 * bumped until we are done with it
 	 */
 	while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-
-                /* if whitelist exists then it has priority, so only scan those
-                 * devices on the whitelist
-                 */
-                if (pci_whitelist_count > 0 ) {
-                        if (check_dev_on_list(pci_whitelist,
+		/* if whitelist exists then it has priority, so only scan
+		 * those devices on the whitelist
+		 */
+		if (pci_whitelist_count > 0 ) {
+			if (check_dev_on_list(pci_whitelist,
 					pci_whitelist_count, dev))
 				fn(dev);
-                } else {
+		} else {
 			/*
 			 * if no whitelist, then check if this devices is
 			 * blacklisted
 			 */
-                        if (!check_dev_on_list(pci_blacklist,
+			if (!check_dev_on_list(pci_blacklist,
 					pci_blacklist_count, dev))
 				fn(dev);
-                }
+		}
 	}
 }
 
@@ -1989,7 +1934,7 @@
 	unsigned long flags;
 	int before_count;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 
 	if (!check_pci_parity)
 		return;
@@ -2011,7 +1956,6 @@
 	}
 }
 
-
 static inline void clear_pci_parity_errors(void)
 {
 	/* Clear any PCI bus parity errors that devices initially have logged
@@ -2020,37 +1964,30 @@
 	edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
 }
 
-
 #else  /* CONFIG_PCI */
 
-
 static inline void do_pci_parity_check(void)
 {
 	/* no-op */
 }
 
-
 static inline void clear_pci_parity_errors(void)
 {
 	/* no-op */
 }
 
-
 #endif  /* CONFIG_PCI */
 
 /*
  * Iterate over all MC instances and check for ECC, et al, errors
  */
-static inline void check_mc_devices (void)
+static inline void check_mc_devices(void)
 {
-	unsigned long flags;
 	struct list_head *item;
 	struct mem_ctl_info *mci;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
-
-	/* during poll, have interrupts off */
-	local_irq_save(flags);
+	debugf3("%s()\n", __func__);
+	down(&mem_ctls_mutex);
 
 	list_for_each(item, &mc_devices) {
 		mci = list_entry(item, struct mem_ctl_info, link);
@@ -2059,10 +1996,9 @@
 			mci->edac_check(mci);
 	}
 
-	local_irq_restore(flags);
+	up(&mem_ctls_mutex);
 }
 
-
 /*
  * Check MC status every poll_msec.
  * Check PCI status every poll_msec as well.
@@ -2073,70 +2009,21 @@
  */
 static void do_edac_check(void)
 {
-
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
-
+	debugf3("%s()\n", __func__);
 	check_mc_devices();
-
 	do_pci_parity_check();
 }
 
-
-/*
- * EDAC thread state information
- */
-struct bs_thread_info
-{
-	struct task_struct *task;
-	struct completion *event;
-	char *name;
-	void (*run)(void);
-};
-
-static struct bs_thread_info bs_thread;
-
-/*
- *  edac_kernel_thread
- *      This the kernel thread that processes edac operations
- *      in a normal thread environment
- */
 static int edac_kernel_thread(void *arg)
 {
-	struct bs_thread_info *thread = (struct bs_thread_info *) arg;
-
-	/* detach thread */
-	daemonize(thread->name);
-
-	current->exit_signal = SIGCHLD;
-	allow_signal(SIGKILL);
-	thread->task = current;
-
-	/* indicate to starting task we have started */
-	complete(thread->event);
-
-	/* loop forever, until we are told to stop */
-	while(thread->run != NULL) {
-		void (*run)(void);
-
-		/* call the function to check the memory controllers */
-		run = thread->run;
-		if (run)
-			run();
-
-		if (signal_pending(current))
-			flush_signals(current);
-
-		/* ensure we are interruptable */
-		set_current_state(TASK_INTERRUPTIBLE);
+	while (!kthread_should_stop()) {
+		do_edac_check();
 
 		/* goto sleep for the interval */
-		schedule_timeout((HZ * poll_msec) / 1000);
+		schedule_timeout_interruptible((HZ * poll_msec) / 1000);
 		try_to_freeze();
 	}
 
-	/* notify waiter that we are exiting */
-	complete(thread->event);
-
 	return 0;
 }
 
@@ -2146,10 +2033,7 @@
  */
 static int __init edac_mc_init(void)
 {
-	int ret;
-	struct completion event;
-
-	printk(KERN_INFO "MC: " __FILE__ " version " EDAC_MC_VERSION "\n");
+	edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n");
 
 	/*
 	 * Harvest and clear any boot/initialization PCI parity errors
@@ -2160,80 +2044,54 @@
 	 */
 	clear_pci_parity_errors();
 
-	/* perform check for first time to harvest boot leftovers */
-	do_edac_check();
-
-	/* Create the MC sysfs entires */
+	/* Create the MC sysfs entries */
 	if (edac_sysfs_memctrl_setup()) {
-		printk(KERN_ERR "EDAC MC: Error initializing sysfs code\n");
+		edac_printk(KERN_ERR, EDAC_MC,
+			"Error initializing sysfs code\n");
 		return -ENODEV;
 	}
 
 	/* Create the PCI parity sysfs entries */
 	if (edac_sysfs_pci_setup()) {
 		edac_sysfs_memctrl_teardown();
-		printk(KERN_ERR "EDAC PCI: Error initializing sysfs code\n");
+		edac_printk(KERN_ERR, EDAC_MC,
+			"EDAC PCI: Error initializing sysfs code\n");
 		return -ENODEV;
 	}
 
-	/* Create our kernel thread */
-	init_completion(&event);
-	bs_thread.event = &event;
-	bs_thread.name = "kedac";
-	bs_thread.run = do_edac_check;
-
 	/* create our kernel thread */
-	ret = kernel_thread(edac_kernel_thread, &bs_thread, CLONE_KERNEL);
-	if (ret < 0) {
+	edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac");
+
+	if (IS_ERR(edac_thread)) {
 		/* remove the sysfs entries */
 		edac_sysfs_memctrl_teardown();
 		edac_sysfs_pci_teardown();
-		return -ENOMEM;
+		return PTR_ERR(edac_thread);
 	}
 
-	/* wait for our kernel theard ack that it is up and running */
-	wait_for_completion(&event);
-
 	return 0;
 }
 
-
 /*
  * edac_mc_exit()
  *      module exit/termination functioni
  */
 static void __exit edac_mc_exit(void)
 {
-	struct completion event;
-
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
-
-	init_completion(&event);
-	bs_thread.event = &event;
-
-	/* As soon as ->run is set to NULL, the task could disappear,
-	 * so we need to hold tasklist_lock until we have sent the signal
-	 */
-	read_lock(&tasklist_lock);
-	bs_thread.run = NULL;
-	send_sig(SIGKILL, bs_thread.task, 1);
-	read_unlock(&tasklist_lock);
-	wait_for_completion(&event);
+	debugf0("%s()\n", __func__);
+	kthread_stop(edac_thread);
 
         /* tear down the sysfs device */
 	edac_sysfs_memctrl_teardown();
 	edac_sysfs_pci_teardown();
 }
 
-
-
-
 module_init(edac_mc_init);
 module_exit(edac_mc_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
-	      "Based on.work by Dan Hollis et al");
+	"Based on work by Dan Hollis et al");
 MODULE_DESCRIPTION("Core library routines for MC reporting");
 
 module_param(panic_on_ue, int, 0644);
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h
index 75ecf48..8d9e839 100644
--- a/drivers/edac/edac_mc.h
+++ b/drivers/edac/edac_mc.h
@@ -15,11 +15,9 @@
  *
  */
 
-
 #ifndef _EDAC_MC_H_
 #define _EDAC_MC_H_
 
-
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -33,7 +31,6 @@
 #include <linux/completion.h>
 #include <linux/kobject.h>
 
-
 #define EDAC_MC_LABEL_LEN	31
 #define MC_PROC_NAME_MAX_LEN 7
 
@@ -43,31 +40,53 @@
 #define PAGES_TO_MiB( pages )	( ( pages ) << ( PAGE_SHIFT - 20 ) )
 #endif
 
+#define edac_printk(level, prefix, fmt, arg...) \
+	printk(level "EDAC " prefix ": " fmt, ##arg)
+
+#define edac_mc_printk(mci, level, fmt, arg...) \
+	printk(level "EDAC MC%d: " fmt, mci->mc_idx, ##arg)
+
+#define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \
+	printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg)
+
+/* prefixes for edac_printk() and edac_mc_printk() */
+#define EDAC_MC "MC"
+#define EDAC_PCI "PCI"
+#define EDAC_DEBUG "DEBUG"
+
 #ifdef CONFIG_EDAC_DEBUG
 extern int edac_debug_level;
-#define edac_debug_printk(level, fmt, args...) \
-do { if (level <= edac_debug_level) printk(KERN_DEBUG fmt, ##args); } while(0)
+
+#define edac_debug_printk(level, fmt, arg...)                            \
+	do {                                                             \
+		if (level <= edac_debug_level)                           \
+			edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \
+	} while(0)
+
 #define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
 #define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ )
 #define debugf2( ... ) edac_debug_printk(2, __VA_ARGS__ )
 #define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ )
 #define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ )
-#else				/* !CONFIG_EDAC_DEBUG */
+
+#else  /* !CONFIG_EDAC_DEBUG */
+
 #define debugf0( ... )
 #define debugf1( ... )
 #define debugf2( ... )
 #define debugf3( ... )
 #define debugf4( ... )
-#endif				/* !CONFIG_EDAC_DEBUG */
 
+#endif  /* !CONFIG_EDAC_DEBUG */
 
-#define bs_xstr(s) bs_str(s)
-#define bs_str(s) #s
-#define BS_MOD_STR bs_xstr(KBUILD_BASENAME)
+#define edac_xstr(s) edac_str(s)
+#define edac_str(s) #s
+#define EDAC_MOD_STR edac_xstr(KBUILD_BASENAME)
 
 #define BIT(x) (1 << (x))
 
-#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, PCI_DEVICE_ID_ ## vend ## _ ## dev
+#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \
+	PCI_DEVICE_ID_ ## vend ## _ ## dev
 
 /* memory devices */
 enum dev_type {
@@ -117,7 +136,6 @@
 #define MEM_FLAG_RDDR		BIT(MEM_RDDR)
 #define MEM_FLAG_RMBS		BIT(MEM_RMBS)
 
-
 /* chipset Error Detection and Correction capabilities and mode */
 enum edac_type {
 	EDAC_UNKNOWN = 0,	/* Unknown if ECC is available */
@@ -142,7 +160,6 @@
 #define EDAC_FLAG_S8ECD8ED	BIT(EDAC_S8ECD8ED)
 #define EDAC_FLAG_S16ECD16ED	BIT(EDAC_S16ECD16ED)
 
-
 /* scrubbing capabilities */
 enum scrub_type {
 	SCRUB_UNKNOWN = 0,	/* Unknown if scrubber is available */
@@ -166,11 +183,6 @@
 #define SCRUB_FLAG_HW_PROG_SRC	BIT(SCRUB_HW_PROG_SRC_CORR)
 #define SCRUB_FLAG_HW_TUN	BIT(SCRUB_HW_TUNABLE)
 
-enum mci_sysfs_status {
-	MCI_SYSFS_INACTIVE = 0,	/* sysfs entries NOT registered */
-	MCI_SYSFS_ACTIVE	/* sysfs entries ARE registered */
-};
-
 /* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */
 
 /*
@@ -255,20 +267,19 @@
  * PS - I enjoyed writing all that about as much as you enjoyed reading it.
  */
 
-
 struct channel_info {
 	int chan_idx;		/* channel index */
 	u32 ce_count;		/* Correctable Errors for this CHANNEL */
-	char label[EDAC_MC_LABEL_LEN + 1];	/* DIMM label on motherboard */
+	char label[EDAC_MC_LABEL_LEN + 1];  /* DIMM label on motherboard */
 	struct csrow_info *csrow;	/* the parent */
 };
 
-
 struct csrow_info {
 	unsigned long first_page;	/* first page number in dimm */
 	unsigned long last_page;	/* last page number in dimm */
 	unsigned long page_mask;	/* used for interleaving -
-					   0UL for non intlv */
+					 * 0UL for non intlv
+					 */
 	u32 nr_pages;		/* number of pages in csrow */
 	u32 grain;		/* granularity of reported error in bytes */
 	int csrow_idx;		/* the chip-select row */
@@ -280,29 +291,28 @@
 	struct mem_ctl_info *mci;	/* the parent */
 
 	struct kobject kobj;	/* sysfs kobject for this csrow */
+	struct completion kobj_complete;
 
 	/* FIXME the number of CHANNELs might need to become dynamic */
 	u32 nr_channels;
 	struct channel_info *channels;
 };
 
-
 struct mem_ctl_info {
 	struct list_head link;  /* for global list of mem_ctl_info structs */
 	unsigned long mtype_cap;	/* memory types supported by mc */
 	unsigned long edac_ctl_cap;	/* Mem controller EDAC capabilities */
 	unsigned long edac_cap;	/* configuration capabilities - this is
-				   closely related to edac_ctl_cap.  The
-				   difference is that the controller
-				   may be capable of s4ecd4ed which would
-				   be listed in edac_ctl_cap, but if
-				   channels aren't capable of s4ecd4ed then the
-				   edac_cap would not have that capability. */
+				 * closely related to edac_ctl_cap.  The
+				 * difference is that the controller may be
+				 * capable of s4ecd4ed which would be listed
+				 * in edac_ctl_cap, but if channels aren't
+				 * capable of s4ecd4ed then the edac_cap would
+				 * not have that capability.
+				 */
 	unsigned long scrub_cap;	/* chipset scrub capabilities */
 	enum scrub_type scrub_mode;	/* current scrub mode */
 
-	enum mci_sysfs_status sysfs_active;	/* status of sysfs */
-
 	/* pointer to edac checking routine */
 	void (*edac_check) (struct mem_ctl_info * mci);
 	/*
@@ -311,7 +321,7 @@
 	 */
 	/* FIXME - why not send the phys page to begin with? */
 	unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci,
-					   unsigned long page);
+					unsigned long page);
 	int mc_idx;
 	int nr_csrows;
 	struct csrow_info *csrows;
@@ -340,72 +350,69 @@
 
 	/* edac sysfs device control */
 	struct kobject edac_mci_kobj;
+	struct completion kobj_complete;
 };
 
-
-
 /* write all or some bits in a byte-register*/
-static inline void pci_write_bits8(struct pci_dev *pdev, int offset,
-				   u8 value, u8 mask)
+static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
+		u8 mask)
 {
 	if (mask != 0xff) {
 		u8 buf;
+
 		pci_read_config_byte(pdev, offset, &buf);
 		value &= mask;
 		buf &= ~mask;
 		value |= buf;
 	}
+
 	pci_write_config_byte(pdev, offset, value);
 }
 
-
 /* write all or some bits in a word-register*/
 static inline void pci_write_bits16(struct pci_dev *pdev, int offset,
-				    u16 value, u16 mask)
+		u16 value, u16 mask)
 {
 	if (mask != 0xffff) {
 		u16 buf;
+
 		pci_read_config_word(pdev, offset, &buf);
 		value &= mask;
 		buf &= ~mask;
 		value |= buf;
 	}
+
 	pci_write_config_word(pdev, offset, value);
 }
 
-
 /* write all or some bits in a dword-register*/
 static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
-				    u32 value, u32 mask)
+		u32 value, u32 mask)
 {
 	if (mask != 0xffff) {
 		u32 buf;
+
 		pci_read_config_dword(pdev, offset, &buf);
 		value &= mask;
 		buf &= ~mask;
 		value |= buf;
 	}
+
 	pci_write_config_dword(pdev, offset, value);
 }
 
-
 #ifdef CONFIG_EDAC_DEBUG
 void edac_mc_dump_channel(struct channel_info *chan);
 void edac_mc_dump_mci(struct mem_ctl_info *mci);
 void edac_mc_dump_csrow(struct csrow_info *csrow);
-#endif				/* CONFIG_EDAC_DEBUG */
+#endif  /* CONFIG_EDAC_DEBUG */
 
 extern int edac_mc_add_mc(struct mem_ctl_info *mci);
-extern int edac_mc_del_mc(struct mem_ctl_info *mci);
-
+extern struct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev);
 extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
-					   unsigned long page);
-
-extern struct mem_ctl_info *edac_mc_find_mci_by_pdev(struct pci_dev
-							  *pdev);
-
-extern void edac_mc_scrub_block(unsigned long page,
-				     unsigned long offset, u32 size);
+					unsigned long page);
+extern void edac_mc_scrub_block(unsigned long page, unsigned long offset,
+		u32 size);
 
 /*
  * The no info errors are used when error overflows are reported.
@@ -418,31 +425,25 @@
  * statement clutter and extra function arguments.
  */
 extern void edac_mc_handle_ce(struct mem_ctl_info *mci,
-				   unsigned long page_frame_number,
-				   unsigned long offset_in_page,
-				   unsigned long syndrome,
-				   int row, int channel, const char *msg);
-
+		unsigned long page_frame_number, unsigned long offset_in_page,
+		unsigned long syndrome, int row, int channel,
+		const char *msg);
 extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci,
-					   const char *msg);
-
+		const char *msg);
 extern void edac_mc_handle_ue(struct mem_ctl_info *mci,
-				   unsigned long page_frame_number,
-				   unsigned long offset_in_page,
-				   int row, const char *msg);
-
+		unsigned long page_frame_number, unsigned long offset_in_page,
+		int row, const char *msg);
 extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci,
-					   const char *msg);
+		const char *msg);
 
 /*
  * This kmalloc's and initializes all the structures.
  * Can't be used if all structures don't have the same lifetime.
  */
-extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt,
-		unsigned nr_csrows, unsigned nr_chans);
+extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
+		unsigned nr_chans);
 
 /* Free an mc previously allocated by edac_mc_alloc() */
 extern void edac_mc_free(struct mem_ctl_info *mci);
 
-
 #endif				/* _EDAC_MC_H_ */
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index 52596e7..fd34216 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
@@ -9,7 +9,6 @@
  * by Thayne Harbaugh of Linux Networx. (http://lnxi.com)
  */
 
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -18,6 +17,11 @@
 #include <linux/slab.h>
 #include "edac_mc.h"
 
+#define i82860_printk(level, fmt, arg...) \
+	edac_printk(level, "i82860", fmt, ##arg)
+
+#define i82860_mc_printk(mci, level, fmt, arg...) \
+	edac_mc_chipset_printk(mci, level, "i82860", fmt, ##arg)
 
 #ifndef PCI_DEVICE_ID_INTEL_82860_0
 #define PCI_DEVICE_ID_INTEL_82860_0	0x2531
@@ -48,15 +52,15 @@
 
 static const struct i82860_dev_info i82860_devs[] = {
 	[I82860] = {
-		    .ctl_name = "i82860"},
+		.ctl_name = "i82860"
+	},
 };
 
 static struct pci_dev *mci_pdev = NULL;	/* init dev: in case that AGP code
-					   has already registered driver */
+					 * has already registered driver
+					 */
 
-static int i82860_registered = 1;
-
-static void i82860_get_error_info (struct mem_ctl_info *mci,
+static void i82860_get_error_info(struct mem_ctl_info *mci,
 		struct i82860_error_info *info)
 {
 	/*
@@ -78,14 +82,15 @@
 	 */
 	if (!(info->errsts2 & 0x0003))
 		return;
+
 	if ((info->errsts ^ info->errsts2) & 0x0003) {
 		pci_read_config_dword(mci->pdev, I82860_EAP, &info->eap);
 		pci_read_config_word(mci->pdev, I82860_DERRCTL_STS,
-		    &info->derrsyn);
+				&info->derrsyn);
 	}
 }
 
-static int i82860_process_error_info (struct mem_ctl_info *mci,
+static int i82860_process_error_info(struct mem_ctl_info *mci,
 		struct i82860_error_info *info, int handle_errors)
 {
 	int row;
@@ -107,8 +112,8 @@
 	if (info->errsts & 0x0002)
 		edac_mc_handle_ue(mci, info->eap, 0, row, "i82860 UE");
 	else
-		edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row,
-				       0, "i82860 UE");
+		edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, 0,
+				"i82860 UE");
 
 	return 1;
 }
@@ -117,7 +122,7 @@
 {
 	struct i82860_error_info info;
 
-	debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
 	i82860_get_error_info(mci, &info);
 	i82860_process_error_info(mci, &info, 1);
 }
@@ -128,6 +133,7 @@
 	int index;
 	struct mem_ctl_info *mci = NULL;
 	unsigned long last_cumul_size;
+	struct i82860_error_info discard;
 
 	u16 mchcfg_ddim;	/* DRAM Data Integrity Mode 0=none,2=edac */
 
@@ -140,21 +146,20 @@
 	   going to make 1 channel for group.
 	 */
 	mci = edac_mc_alloc(0, 16, 1);
+
 	if (!mci)
 		return -ENOMEM;
 
-	debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__);
-
+	debugf3("%s(): init mci\n", __func__);
 	mci->pdev = pdev;
 	mci->mtype_cap = MEM_FLAG_DDR;
 
-
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
 	/* I"m not sure about this but I think that all RDRAM is SECDED */
 	mci->edac_cap = EDAC_FLAG_SECDED;
 	/* adjust FLAGS */
 
-	mci->mod_name = BS_MOD_STR;
+	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = "$Revision: 1.1.2.6 $";
 	mci->ctl_name = i82860_devs[dev_idx].ctl_name;
 	mci->edac_check = i82860_check;
@@ -175,12 +180,13 @@
 		struct csrow_info *csrow = &mci->csrows[index];
 
 		pci_read_config_word(mci->pdev, I82860_GBA + index * 2,
-				     &value);
+				&value);
 
 		cumul_size = (value & I82860_GBA_MASK) <<
 		    (I82860_GBA_SHIFT - PAGE_SHIFT);
-		debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n",
-			__func__, index, cumul_size);
+		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
+			cumul_size);
+
 		if (cumul_size == last_cumul_size)
 			continue;	/* not populated */
 
@@ -188,42 +194,43 @@
 		csrow->last_page = cumul_size - 1;
 		csrow->nr_pages = cumul_size - last_cumul_size;
 		last_cumul_size = cumul_size;
-		csrow->grain = 1 << 12;	/* I82860_EAP has 4KiB reolution */
+		csrow->grain = 1 << 12;  /* I82860_EAP has 4KiB reolution */
 		csrow->mtype = MEM_RMBS;
 		csrow->dtype = DEV_UNKNOWN;
 		csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE;
 	}
 
-	/* clear counters */
-	pci_write_bits16(mci->pdev, I82860_ERRSTS, 0x0003, 0x0003);
+	i82860_get_error_info(mci, &discard);  /* clear counters */
 
 	if (edac_mc_add_mc(mci)) {
-		debugf3("MC: " __FILE__
-			": %s(): failed edac_mc_add_mc()\n",
-			__func__);
+		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
 		edac_mc_free(mci);
 	} else {
 		/* get this far and it's successful */
-		debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
+		debugf3("%s(): success\n", __func__);
 		rc = 0;
 	}
+
 	return rc;
 }
 
 /* returns count (>= 0), or negative on error */
 static int __devinit i82860_init_one(struct pci_dev *pdev,
-				     const struct pci_device_id *ent)
+		const struct pci_device_id *ent)
 {
 	int rc;
 
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
+	i82860_printk(KERN_INFO, "i82860 init one\n");
 
-	printk(KERN_INFO "i82860 init one\n");
-	if(pci_enable_device(pdev) < 0)
+	if (pci_enable_device(pdev) < 0)
 		return -EIO;
+
 	rc = i82860_probe1(pdev, ent->driver_data);
-	if(rc == 0)
+
+	if (rc == 0)
 		mci_pdev = pci_dev_get(pdev);
+
 	return rc;
 }
 
@@ -231,23 +238,28 @@
 {
 	struct mem_ctl_info *mci;
 
-	debugf0(__FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
 
-	mci = edac_mc_find_mci_by_pdev(pdev);
-	if ((mci != NULL) && (edac_mc_del_mc(mci) == 0))
-		edac_mc_free(mci);
+	if ((mci = edac_mc_del_mc(pdev)) == NULL)
+		return;
+
+	edac_mc_free(mci);
 }
 
 static const struct pci_device_id i82860_pci_tbl[] __devinitdata = {
-	{PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	 I82860},
-	{0,}			/* 0 terminated list. */
+	{
+		PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		I82860
+	},
+	{
+		0,
+	}	/* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, i82860_pci_tbl);
 
 static struct pci_driver i82860_driver = {
-	.name = BS_MOD_STR,
+	.name = EDAC_MOD_STR,
 	.probe = i82860_init_one,
 	.remove = __devexit_p(i82860_remove_one),
 	.id_table = i82860_pci_tbl,
@@ -257,43 +269,56 @@
 {
 	int pci_rc;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
+
 	if ((pci_rc = pci_register_driver(&i82860_driver)) < 0)
-		return pci_rc;
+		goto fail0;
 
 	if (!mci_pdev) {
-		i82860_registered = 0;
 		mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
-					  PCI_DEVICE_ID_INTEL_82860_0, NULL);
+					PCI_DEVICE_ID_INTEL_82860_0, NULL);
+
 		if (mci_pdev == NULL) {
 			debugf0("860 pci_get_device fail\n");
-			return -ENODEV;
+			pci_rc = -ENODEV;
+			goto fail1;
 		}
+
 		pci_rc = i82860_init_one(mci_pdev, i82860_pci_tbl);
+
 		if (pci_rc < 0) {
 			debugf0("860 init fail\n");
-			pci_dev_put(mci_pdev);
-			return -ENODEV;
+			pci_rc = -ENODEV;
+			goto fail1;
 		}
 	}
+
 	return 0;
+
+fail1:
+	pci_unregister_driver(&i82860_driver);
+
+fail0:
+	if (mci_pdev != NULL)
+		pci_dev_put(mci_pdev);
+
+	return pci_rc;
 }
 
 static void __exit i82860_exit(void)
 {
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 
 	pci_unregister_driver(&i82860_driver);
-	if (!i82860_registered) {
-		i82860_remove_one(mci_pdev);
+
+	if (mci_pdev != NULL)
 		pci_dev_put(mci_pdev);
-	}
 }
 
 module_init(i82860_init);
 module_exit(i82860_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR
-    ("Red Hat Inc. (http://www.redhat.com.com) Ben Woodard <woodard@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) "
+	"Ben Woodard <woodard@redhat.com>");
 MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers");
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 1991f94..0aec926 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -13,18 +13,19 @@
  * Note: E7210 appears same as D82875P - zhenyu.z.wang at intel.com
  */
 
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
-
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
-
 #include <linux/slab.h>
-
 #include "edac_mc.h"
 
+#define i82875p_printk(level, fmt, arg...) \
+	edac_printk(level, "i82875p", fmt, ##arg)
+
+#define i82875p_mc_printk(mci, level, fmt, arg...) \
+	edac_mc_chipset_printk(mci, level, "i82875p", fmt, ##arg)
 
 #ifndef PCI_DEVICE_ID_INTEL_82875_0
 #define PCI_DEVICE_ID_INTEL_82875_0	0x2578
@@ -34,11 +35,9 @@
 #define PCI_DEVICE_ID_INTEL_82875_6	0x257e
 #endif				/* PCI_DEVICE_ID_INTEL_82875_6 */
 
-
 /* four csrows in dual channel, eight in single channel */
 #define I82875P_NR_CSROWS(nr_chans) (8/(nr_chans))
 
-
 /* Intel 82875p register addresses - device 0 function 0 - DRAM Controller */
 #define I82875P_EAP		0x58	/* Error Address Pointer (32b)
 					 *
@@ -87,7 +86,6 @@
 					 *  0    reserved
 					 */
 
-
 /* Intel 82875p register addresses - device 6 function 0 - DRAM Controller */
 #define I82875P_PCICMD6		0x04	/* PCI Command Register (16b)
 					 *
@@ -151,23 +149,19 @@
 					 *  1:0  DRAM type 01=DDR
 					 */
 
-
 enum i82875p_chips {
 	I82875P = 0,
 };
 
-
 struct i82875p_pvt {
 	struct pci_dev *ovrfl_pdev;
 	void __iomem *ovrfl_window;
 };
 
-
 struct i82875p_dev_info {
 	const char *ctl_name;
 };
 
-
 struct i82875p_error_info {
 	u16 errsts;
 	u32 eap;
@@ -176,17 +170,19 @@
 	u16 errsts2;
 };
 
-
 static const struct i82875p_dev_info i82875p_devs[] = {
 	[I82875P] = {
-		     .ctl_name = "i82875p"},
+		.ctl_name = "i82875p"
+	},
 };
 
-static struct pci_dev *mci_pdev = NULL;	/* init dev: in case that AGP code
-					   has already registered driver */
+static struct pci_dev *mci_pdev = NULL;	/* init dev: in case that AGP code has
+					 * already registered driver
+					 */
+
 static int i82875p_registered = 1;
 
-static void i82875p_get_error_info (struct mem_ctl_info *mci,
+static void i82875p_get_error_info(struct mem_ctl_info *mci,
 		struct i82875p_error_info *info)
 {
 	/*
@@ -210,15 +206,16 @@
 	 */
 	if (!(info->errsts2 & 0x0081))
 		return;
+
 	if ((info->errsts ^ info->errsts2) & 0x0081) {
 		pci_read_config_dword(mci->pdev, I82875P_EAP, &info->eap);
 		pci_read_config_byte(mci->pdev, I82875P_DES, &info->des);
 		pci_read_config_byte(mci->pdev, I82875P_DERRSYN,
-		    &info->derrsyn);
+				&info->derrsyn);
 	}
 }
 
-static int i82875p_process_error_info (struct mem_ctl_info *mci,
+static int i82875p_process_error_info(struct mem_ctl_info *mci,
 		struct i82875p_error_info *info, int handle_errors)
 {
 	int row, multi_chan;
@@ -243,23 +240,21 @@
 		edac_mc_handle_ue(mci, info->eap, 0, row, "i82875p UE");
 	else
 		edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row,
-				       multi_chan ? (info->des & 0x1) : 0,
-				       "i82875p CE");
+				multi_chan ? (info->des & 0x1) : 0,
+				"i82875p CE");
 
 	return 1;
 }
 
-
 static void i82875p_check(struct mem_ctl_info *mci)
 {
 	struct i82875p_error_info info;
 
-	debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
 	i82875p_get_error_info(mci, &info);
 	i82875p_process_error_info(mci, &info, 1);
 }
 
-
 #ifdef CONFIG_PROC_FS
 extern int pci_proc_attach_device(struct pci_dev *);
 #endif
@@ -273,15 +268,14 @@
 	unsigned long last_cumul_size;
 	struct pci_dev *ovrfl_pdev;
 	void __iomem *ovrfl_window = NULL;
-
 	u32 drc;
 	u32 drc_chan;		/* Number of channels 0=1chan,1=2chan */
 	u32 nr_chans;
 	u32 drc_ddim;		/* DRAM Data Integrity Mode 0=none,2=edac */
+	struct i82875p_error_info discard;
 
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
-
-	ovrfl_pdev = pci_find_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
+	debugf0("%s()\n", __func__);
+	ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
 
 	if (!ovrfl_pdev) {
 		/*
@@ -292,71 +286,69 @@
 		 */
 		pci_write_bits8(pdev, 0xf4, 0x2, 0x2);
 		ovrfl_pdev =
-		    pci_scan_single_device(pdev->bus, PCI_DEVFN(6, 0));
+			pci_scan_single_device(pdev->bus, PCI_DEVFN(6, 0));
+
 		if (!ovrfl_pdev)
-			goto fail;
+			return -ENODEV;
 	}
+
 #ifdef CONFIG_PROC_FS
 	if (!ovrfl_pdev->procent && pci_proc_attach_device(ovrfl_pdev)) {
-		printk(KERN_ERR "MC: " __FILE__
-		       ": %s(): Failed to attach overflow device\n",
-		       __func__);
-		goto fail;
+		i82875p_printk(KERN_ERR,
+			"%s(): Failed to attach overflow device\n", __func__);
+		return -ENODEV;
 	}
-#endif				/* CONFIG_PROC_FS */
+#endif
+				/* CONFIG_PROC_FS */
 	if (pci_enable_device(ovrfl_pdev)) {
-		printk(KERN_ERR "MC: " __FILE__
-		       ": %s(): Failed to enable overflow device\n",
-		       __func__);
-		goto fail;
+		i82875p_printk(KERN_ERR,
+			"%s(): Failed to enable overflow device\n", __func__);
+		return -ENODEV;
 	}
 
 	if (pci_request_regions(ovrfl_pdev, pci_name(ovrfl_pdev))) {
 #ifdef CORRECT_BIOS
-		goto fail;
+		goto fail0;
 #endif
 	}
+
 	/* cache is irrelevant for PCI bus reads/writes */
 	ovrfl_window = ioremap_nocache(pci_resource_start(ovrfl_pdev, 0),
-				       pci_resource_len(ovrfl_pdev, 0));
+				pci_resource_len(ovrfl_pdev, 0));
 
 	if (!ovrfl_window) {
-		printk(KERN_ERR "MC: " __FILE__
-		       ": %s(): Failed to ioremap bar6\n", __func__);
-		goto fail;
+		i82875p_printk(KERN_ERR, "%s(): Failed to ioremap bar6\n",
+			__func__);
+		goto fail1;
 	}
 
 	/* need to find out the number of channels */
 	drc = readl(ovrfl_window + I82875P_DRC);
 	drc_chan = ((drc >> 21) & 0x1);
 	nr_chans = drc_chan + 1;
-	drc_ddim = (drc >> 18) & 0x1;
 
+	drc_ddim = (drc >> 18) & 0x1;
 	mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans),
-				 nr_chans);
+				nr_chans);
 
 	if (!mci) {
 		rc = -ENOMEM;
-		goto fail;
+		goto fail2;
 	}
 
-	debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__);
-
+	debugf3("%s(): init mci\n", __func__);
 	mci->pdev = pdev;
 	mci->mtype_cap = MEM_FLAG_DDR;
-
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
 	mci->edac_cap = EDAC_FLAG_UNKNOWN;
 	/* adjust FLAGS */
 
-	mci->mod_name = BS_MOD_STR;
+	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = "$Revision: 1.5.2.11 $";
 	mci->ctl_name = i82875p_devs[dev_idx].ctl_name;
 	mci->edac_check = i82875p_check;
 	mci->ctl_page_to_phys = NULL;
-
-	debugf3("MC: " __FILE__ ": %s(): init pvt\n", __func__);
-
+	debugf3("%s(): init pvt\n", __func__);
 	pvt = (struct i82875p_pvt *) mci->pvt_info;
 	pvt->ovrfl_pdev = ovrfl_pdev;
 	pvt->ovrfl_window = ovrfl_window;
@@ -374,8 +366,9 @@
 
 		value = readb(ovrfl_window + I82875P_DRB + index);
 		cumul_size = value << (I82875P_DRB_SHIFT - PAGE_SHIFT);
-		debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n",
-			__func__, index, cumul_size);
+		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
+			cumul_size);
+
 		if (cumul_size == last_cumul_size)
 			continue;	/* not populated */
 
@@ -383,71 +376,72 @@
 		csrow->last_page = cumul_size - 1;
 		csrow->nr_pages = cumul_size - last_cumul_size;
 		last_cumul_size = cumul_size;
-		csrow->grain = 1 << 12;	/* I82875P_EAP has 4KiB reolution */
+		csrow->grain = 1 << 12;  /* I82875P_EAP has 4KiB reolution */
 		csrow->mtype = MEM_DDR;
 		csrow->dtype = DEV_UNKNOWN;
 		csrow->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE;
 	}
 
-	/* clear counters */
-	pci_write_bits16(mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081);
+	i82875p_get_error_info(mci, &discard);  /* clear counters */
 
 	if (edac_mc_add_mc(mci)) {
-		debugf3("MC: " __FILE__
-			": %s(): failed edac_mc_add_mc()\n", __func__);
-		goto fail;
+		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		goto fail3;
 	}
 
 	/* get this far and it's successful */
-	debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
+	debugf3("%s(): success\n", __func__);
 	return 0;
 
-      fail:
-	if (mci)
-		edac_mc_free(mci);
+fail3:
+	edac_mc_free(mci);
 
-	if (ovrfl_window)
-		iounmap(ovrfl_window);
+fail2:
+	iounmap(ovrfl_window);
 
-	if (ovrfl_pdev) {
-		pci_release_regions(ovrfl_pdev);
-		pci_disable_device(ovrfl_pdev);
-	}
+fail1:
+	pci_release_regions(ovrfl_pdev);
 
+#ifdef CORRECT_BIOS
+fail0:
+#endif
+	pci_disable_device(ovrfl_pdev);
 	/* NOTE: the ovrfl proc entry and pci_dev are intentionally left */
 	return rc;
 }
 
-
 /* returns count (>= 0), or negative on error */
 static int __devinit i82875p_init_one(struct pci_dev *pdev,
-				      const struct pci_device_id *ent)
+		const struct pci_device_id *ent)
 {
 	int rc;
 
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
+	i82875p_printk(KERN_INFO, "i82875p init one\n");
 
-	printk(KERN_INFO "i82875p init one\n");
-	if(pci_enable_device(pdev) < 0)
+	if (pci_enable_device(pdev) < 0)
 		return -EIO;
+
 	rc = i82875p_probe1(pdev, ent->driver_data);
+
 	if (mci_pdev == NULL)
 		mci_pdev = pci_dev_get(pdev);
+
 	return rc;
 }
 
-
 static void __devexit i82875p_remove_one(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 	struct i82875p_pvt *pvt = NULL;
 
-	debugf0(__FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
 
-	if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL)
+	if ((mci = edac_mc_del_mc(pdev)) == NULL)
 		return;
 
 	pvt = (struct i82875p_pvt *) mci->pvt_info;
+
 	if (pvt->ovrfl_window)
 		iounmap(pvt->ovrfl_window);
 
@@ -459,74 +453,84 @@
 		pci_dev_put(pvt->ovrfl_pdev);
 	}
 
-	if (edac_mc_del_mc(mci))
-		return;
-
 	edac_mc_free(mci);
 }
 
-
 static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = {
-	{PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	 I82875P},
-	{0,}			/* 0 terminated list. */
+	{
+		PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		I82875P
+	},
+	{
+		0,
+	}	/* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl);
 
-
 static struct pci_driver i82875p_driver = {
-	.name = BS_MOD_STR,
+	.name = EDAC_MOD_STR,
 	.probe = i82875p_init_one,
 	.remove = __devexit_p(i82875p_remove_one),
 	.id_table = i82875p_pci_tbl,
 };
 
-
 static int __init i82875p_init(void)
 {
 	int pci_rc;
 
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 	pci_rc = pci_register_driver(&i82875p_driver);
+
 	if (pci_rc < 0)
-		return pci_rc;
+		goto fail0;
+
 	if (mci_pdev == NULL) {
-		i82875p_registered = 0;
-		mci_pdev =
-		    pci_get_device(PCI_VENDOR_ID_INTEL,
-				   PCI_DEVICE_ID_INTEL_82875_0, NULL);
+		mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+				PCI_DEVICE_ID_INTEL_82875_0, NULL);
+
 		if (!mci_pdev) {
 			debugf0("875p pci_get_device fail\n");
-			return -ENODEV;
+			pci_rc = -ENODEV;
+			goto fail1;
 		}
+
 		pci_rc = i82875p_init_one(mci_pdev, i82875p_pci_tbl);
+
 		if (pci_rc < 0) {
 			debugf0("875p init fail\n");
-			pci_dev_put(mci_pdev);
-			return -ENODEV;
+			pci_rc = -ENODEV;
+			goto fail1;
 		}
 	}
-	return 0;
-}
 
+	return 0;
+
+fail1:
+	pci_unregister_driver(&i82875p_driver);
+
+fail0:
+	if (mci_pdev != NULL)
+		pci_dev_put(mci_pdev);
+
+	return pci_rc;
+}
 
 static void __exit i82875p_exit(void)
 {
-	debugf3("MC: " __FILE__ ": %s()\n", __func__);
+	debugf3("%s()\n", __func__);
 
 	pci_unregister_driver(&i82875p_driver);
+
 	if (!i82875p_registered) {
 		i82875p_remove_one(mci_pdev);
 		pci_dev_put(mci_pdev);
 	}
 }
 
-
 module_init(i82875p_init);
 module_exit(i82875p_exit);
 
-
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
 MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers");
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c
index e908928..2c29faf 100644
--- a/drivers/edac/r82600_edac.c
+++ b/drivers/edac/r82600_edac.c
@@ -18,14 +18,17 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
-
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
-
 #include <linux/slab.h>
-
 #include "edac_mc.h"
 
+#define r82600_printk(level, fmt, arg...) \
+	edac_printk(level, "r82600", fmt, ##arg)
+
+#define r82600_mc_printk(mci, level, fmt, arg...) \
+	edac_mc_chipset_printk(mci, level, "r82600", fmt, ##arg)
+
 /* Radisys say "The 82600 integrates a main memory SDRAM controller that
  * supports up to four banks of memory. The four banks can support a mix of
  * sizes of 64 bit wide (72 bits with ECC) Synchronous DRAM (SDRAM) DIMMs,
@@ -126,10 +129,8 @@
 	u32 eapr;
 };
 
-
 static unsigned int disable_hardware_scrub = 0;
 
-
 static void r82600_get_error_info (struct mem_ctl_info *mci,
 		struct r82600_error_info *info)
 {
@@ -138,17 +139,16 @@
 	if (info->eapr & BIT(0))
 		/* Clear error to allow next error to be reported [p.62] */
 		pci_write_bits32(mci->pdev, R82600_EAP,
-				   ((u32) BIT(0) & (u32) BIT(1)),
-				   ((u32) BIT(0) & (u32) BIT(1)));
+				((u32) BIT(0) & (u32) BIT(1)),
+				((u32) BIT(0) & (u32) BIT(1)));
 
 	if (info->eapr & BIT(1))
 		/* Clear error to allow next error to be reported [p.62] */
 		pci_write_bits32(mci->pdev, R82600_EAP,
-				   ((u32) BIT(0) & (u32) BIT(1)),
-				   ((u32) BIT(0) & (u32) BIT(1)));
+				((u32) BIT(0) & (u32) BIT(1)),
+				((u32) BIT(0) & (u32) BIT(1)));
 }
 
-
 static int r82600_process_error_info (struct mem_ctl_info *mci,
 		struct r82600_error_info *info, int handle_errors)
 {
@@ -167,26 +167,25 @@
 	 * granularity (upper 19 bits only)     */
 	page = eapaddr >> PAGE_SHIFT;
 
-	if (info->eapr & BIT(0)) { 	/* CE? */
+	if (info->eapr & BIT(0)) {  /* CE? */
 		error_found = 1;
 
 		if (handle_errors)
-			edac_mc_handle_ce(
-			    mci, page, 0,	/* not avail */
-			    syndrome,
-			    edac_mc_find_csrow_by_page(mci, page),
-			    0,	/* channel */
-			    mci->ctl_name);
+			edac_mc_handle_ce(mci, page, 0,  /* not avail */
+					syndrome,
+					edac_mc_find_csrow_by_page(mci, page),
+					0,  /* channel */
+					mci->ctl_name);
 	}
 
-	if (info->eapr & BIT(1)) { 	/* UE? */
+	if (info->eapr & BIT(1)) {  /* UE? */
 		error_found = 1;
 
 		if (handle_errors)
 			/* 82600 doesn't give enough info */
 			edac_mc_handle_ue(mci, page, 0,
-			    edac_mc_find_csrow_by_page(mci, page),
-			    mci->ctl_name);
+				edac_mc_find_csrow_by_page(mci, page),
+				mci->ctl_name);
 	}
 
 	return error_found;
@@ -196,7 +195,7 @@
 {
 	struct r82600_error_info info;
 
-	debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
 	r82600_get_error_info(mci, &info);
 	r82600_process_error_info(mci, &info, 1);
 }
@@ -213,25 +212,18 @@
 	u32 scrub_disabled;
 	u32 sdram_refresh_rate;
 	u32 row_high_limit_last = 0;
-	u32 eap_init_bits;
+	struct r82600_error_info discard;
 
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
-
-
+	debugf0("%s()\n", __func__);
 	pci_read_config_byte(pdev, R82600_DRAMC, &dramcr);
 	pci_read_config_dword(pdev, R82600_EAP, &eapr);
-
 	ecc_on = dramcr & BIT(5);
 	reg_sdram = dramcr & BIT(4);
 	scrub_disabled = eapr & BIT(31);
 	sdram_refresh_rate = dramcr & (BIT(0) | BIT(1));
-
-	debugf2("MC: " __FILE__ ": %s(): sdram refresh rate = %#0x\n",
-		__func__, sdram_refresh_rate);
-
-	debugf2("MC: " __FILE__ ": %s(): DRAMC register = %#0x\n", __func__,
-		dramcr);
-
+	debugf2("%s(): sdram refresh rate = %#0x\n", __func__,
+		sdram_refresh_rate);
+	debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr);
 	mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS);
 
 	if (mci == NULL) {
@@ -239,29 +231,28 @@
 		goto fail;
 	}
 
-	debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
-
+	debugf0("%s(): mci = %p\n", __func__, mci);
 	mci->pdev = pdev;
 	mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
-
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
-	/* FIXME try to work out if the chip leads have been                 *
-	 * used for COM2 instead on this board? [MA6?]       MAYBE:          */
+	/* FIXME try to work out if the chip leads have been used for COM2
+	 * instead on this board? [MA6?] MAYBE:
+	 */
 
 	/* On the R82600, the pins for memory bits 72:65 - i.e. the   *
 	 * EC bits are shared with the pins for COM2 (!), so if COM2  *
 	 * is enabled, we assume COM2 is wired up, and thus no EDAC   *
 	 * is possible.                                               */
 	mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
+
 	if (ecc_on) {
 		if (scrub_disabled)
-			debugf3("MC: " __FILE__ ": %s(): mci = %p - "
-				"Scrubbing disabled! EAP: %#0x\n", __func__,
-				mci, eapr);
+			debugf3("%s(): mci = %p - Scrubbing disabled! EAP: "
+				"%#0x\n", __func__, mci, eapr);
 	} else
 		mci->edac_cap = EDAC_FLAG_NONE;
 
-	mci->mod_name = BS_MOD_STR;
+	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = "$Revision: 1.1.2.6 $";
 	mci->ctl_name = "R82600";
 	mci->edac_check = r82600_check;
@@ -276,23 +267,21 @@
 		/* find the DRAM Chip Select Base address and mask */
 		pci_read_config_byte(mci->pdev, R82600_DRBA + index, &drbar);
 
-		debugf1("MC%d: " __FILE__ ": %s() Row=%d DRBA = %#0x\n",
-			mci->mc_idx, __func__, index, drbar);
+		debugf1("MC%d: %s() Row=%d DRBA = %#0x\n", mci->mc_idx,
+			__func__, index, drbar);
 
 		row_high_limit = ((u32) drbar << 24);
 /*		row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */
 
-		debugf1("MC%d: " __FILE__ ": %s() Row=%d, "
-			"Boundry Address=%#0x, Last = %#0x \n",
-			mci->mc_idx, __func__, index, row_high_limit,
-			row_high_limit_last);
+		debugf1("MC%d: %s() Row=%d, Boundry Address=%#0x, Last = "
+			"%#0x \n", mci->mc_idx, __func__, index,
+			row_high_limit, row_high_limit_last);
 
 		/* Empty row [p.57] */
 		if (row_high_limit == row_high_limit_last)
 			continue;
 
 		row_base = row_high_limit_last;
-
 		csrow->first_page = row_base >> PAGE_SHIFT;
 		csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
 		csrow->nr_pages = csrow->last_page - csrow->first_page + 1;
@@ -308,31 +297,22 @@
 		row_high_limit_last = row_high_limit;
 	}
 
-	/* clear counters */
-	/* FIXME should we? */
+	r82600_get_error_info(mci, &discard);  /* clear counters */
 
 	if (edac_mc_add_mc(mci)) {
-		debugf3("MC: " __FILE__
-			": %s(): failed edac_mc_add_mc()\n", __func__);
+		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
 		goto fail;
 	}
 
 	/* get this far and it's successful */
 
-	/* Clear error flags to allow next error to be reported [p.62] */
-	/* Test systems seem to always have the UE flag raised on boot */
-
-	eap_init_bits = BIT(0) & BIT(1);
 	if (disable_hardware_scrub) {
-		eap_init_bits |= BIT(31);
-		debugf3("MC: " __FILE__ ": %s(): Disabling Hardware Scrub "
-			"(scrub on error)\n", __func__);
+		debugf3("%s(): Disabling Hardware Scrub (scrub on error)\n",
+			__func__);
+		pci_write_bits32(mci->pdev, R82600_EAP, BIT(31), BIT(31));
 	}
 
-	pci_write_bits32(mci->pdev, R82600_EAP, eap_init_bits,
-			 eap_init_bits);
-
-	debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
+	debugf3("%s(): success\n", __func__);
 	return 0;
 
 fail:
@@ -344,62 +324,60 @@
 
 /* returns count (>= 0), or negative on error */
 static int __devinit r82600_init_one(struct pci_dev *pdev,
-				     const struct pci_device_id *ent)
+		const struct pci_device_id *ent)
 {
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
 
 	/* don't need to call pci_device_enable() */
 	return r82600_probe1(pdev, ent->driver_data);
 }
 
-
 static void __devexit r82600_remove_one(struct pci_dev *pdev)
 {
 	struct mem_ctl_info *mci;
 
-	debugf0(__FILE__ ": %s()\n", __func__);
+	debugf0("%s()\n", __func__);
 
-	if (((mci = edac_mc_find_mci_by_pdev(pdev)) != NULL) &&
-	    !edac_mc_del_mc(mci))
-		edac_mc_free(mci);
+	if ((mci = edac_mc_del_mc(pdev)) == NULL)
+		return;
+
+	edac_mc_free(mci);
 }
 
-
 static const struct pci_device_id r82600_pci_tbl[] __devinitdata = {
-	{PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)},
-	{0,}			/* 0 terminated list. */
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
+	},
+	{
+		0,
+	}	/* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, r82600_pci_tbl);
 
-
 static struct pci_driver r82600_driver = {
-	.name = BS_MOD_STR,
+	.name = EDAC_MOD_STR,
 	.probe = r82600_init_one,
 	.remove = __devexit_p(r82600_remove_one),
 	.id_table = r82600_pci_tbl,
 };
 
-
 static int __init r82600_init(void)
 {
 	return pci_register_driver(&r82600_driver);
 }
 
-
 static void __exit r82600_exit(void)
 {
 	pci_unregister_driver(&r82600_driver);
 }
 
-
 module_init(r82600_init);
 module_exit(r82600_exit);
 
-
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. "
-	      "on behalf of EADS Astrium");
+	"on behalf of EADS Astrium");
 MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers");
 
 module_param(disable_hardware_scrub, bool, 0644);
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index d6543fc..339f405 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -484,26 +484,15 @@
 static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code,
 				void *unused)
 {
-	static unsigned int notify_cnt = 0;
-
 	switch (code) {
 	case SYS_DOWN:
 	case SYS_HALT:
 	case SYS_POWER_OFF:
 		if (host_control_on_shutdown) {
 			/* firmware is going to perform host control action */
-			if (++notify_cnt == 2) {
-				printk(KERN_WARNING
-				       "Please wait for shutdown "
-				       "action to complete...\n");
-				dcdbas_host_control();
-			}
-			/*
-			 * register again and initiate the host control
-			 * action on the second notification to allow
-			 * everyone that registered to be notified
-			 */
-			register_reboot_notifier(nb);
+			printk(KERN_WARNING "Please wait for shutdown "
+			       "action to complete...\n");
+			dcdbas_host_control();
 		}
 		break;
 	}
@@ -514,7 +503,7 @@
 static struct notifier_block dcdbas_reboot_nb = {
 	.notifier_call = dcdbas_reboot_notify,
 	.next = NULL,
-	.priority = 0
+	.priority = INT_MIN
 };
 
 static DCDBAS_BIN_ATTR_RW(smi_data);
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 343379f..9b7e4d5 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -568,20 +568,20 @@
 	if (!entry || !buf)
 		return -EINVAL;
 
-	if (efi.mps)
-		str += sprintf(str, "MPS=0x%lx\n", __pa(efi.mps));
-	if (efi.acpi20)
-		str += sprintf(str, "ACPI20=0x%lx\n", __pa(efi.acpi20));
-	if (efi.acpi)
-		str += sprintf(str, "ACPI=0x%lx\n", __pa(efi.acpi));
-	if (efi.smbios)
-		str += sprintf(str, "SMBIOS=0x%lx\n", __pa(efi.smbios));
-	if (efi.hcdp)
-		str += sprintf(str, "HCDP=0x%lx\n", __pa(efi.hcdp));
-	if (efi.boot_info)
-		str += sprintf(str, "BOOTINFO=0x%lx\n", __pa(efi.boot_info));
-	if (efi.uga)
-		str += sprintf(str, "UGA=0x%lx\n", __pa(efi.uga));
+	if (efi.mps != EFI_INVALID_TABLE_ADDR)
+		str += sprintf(str, "MPS=0x%lx\n", efi.mps);
+	if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
+		str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);
+	if (efi.acpi != EFI_INVALID_TABLE_ADDR)
+		str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
+	if (efi.smbios != EFI_INVALID_TABLE_ADDR)
+		str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
+	if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
+		str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
+	if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
+		str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info);
+	if (efi.uga != EFI_INVALID_TABLE_ADDR)
+		str += sprintf(str, "UGA=0x%lx\n", efi.uga);
 
 	return str - buf;
 }
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
index ae1fb45..c37baf9 100644
--- a/drivers/firmware/pcdp.c
+++ b/drivers/firmware/pcdp.c
@@ -89,19 +89,20 @@
 	struct pcdp_uart *uart;
 	struct pcdp_device *dev, *end;
 	int i, serial = 0;
+	int rc = -ENODEV;
 
-	pcdp = efi.hcdp;
-	if (!pcdp)
+	if (efi.hcdp == EFI_INVALID_TABLE_ADDR)
 		return -ENODEV;
 
-	printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, __pa(pcdp));
+	pcdp = ioremap(efi.hcdp, 4096);
+	printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, efi.hcdp);
 
 	if (strstr(cmdline, "console=hcdp")) {
 		if (pcdp->rev < 3)
 			serial = 1;
 	} else if (strstr(cmdline, "console=")) {
 		printk(KERN_INFO "Explicit \"console=\"; ignoring PCDP\n");
-		return -ENODEV;
+		goto out;
 	}
 
 	if (pcdp->rev < 3 && efi_uart_console_only())
@@ -110,7 +111,8 @@
 	for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
 		if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) {
 			if (uart->type == PCDP_CONSOLE_UART) {
-				return setup_serial_console(uart);
+				rc = setup_serial_console(uart);
+				goto out;
 			}
 		}
 	}
@@ -121,10 +123,13 @@
 	     dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) {
 		if (dev->flags & PCDP_PRIMARY_CONSOLE) {
 			if (dev->type == PCDP_CONSOLE_VGA) {
-				return setup_vga_console(dev);
+				rc = setup_vga_console(dev);
+				goto out;
 			}
 		}
 	}
 
-	return -ENODEV;
+out:
+	iounmap(pcdp);
+	return rc;
 }
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index f9fae28..7aa5c38 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -65,15 +65,6 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called pcf8591.
 
-config SENSORS_RTC8564
-	tristate "Epson 8564 RTC chip"
-	depends on I2C && EXPERIMENTAL
-	help
-	  If you say yes here you get support for the Epson 8564 RTC chip.
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called i2c-rtc8564.
-
 config ISP1301_OMAP
 	tristate "Philips ISP1301 with OMAP OTG"
 	depends on I2C && ARCH_OMAP_OTG
@@ -126,13 +117,4 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called max6875.
 
-config RTC_X1205_I2C
-	tristate "Xicor X1205 RTC chip"
-	depends on I2C && EXPERIMENTAL
-	help
-	  If you say yes here you get support for the Xicor X1205 RTC chip.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called x1205.
-
 endmenu
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index 46178b5..779868e 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -10,10 +10,8 @@
 obj-$(CONFIG_SENSORS_PCA9539)	+= pca9539.o
 obj-$(CONFIG_SENSORS_PCF8574)	+= pcf8574.o
 obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
-obj-$(CONFIG_SENSORS_RTC8564)	+= rtc8564.o
 obj-$(CONFIG_ISP1301_OMAP)	+= isp1301_omap.o
 obj-$(CONFIG_TPS65010)		+= tps65010.o
-obj-$(CONFIG_RTC_X1205_I2C)	+= x1205.o
 
 ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c
deleted file mode 100644
index 0d8699b..0000000
--- a/drivers/i2c/chips/rtc8564.c
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- *  linux/drivers/i2c/chips/rtc8564.c
- *
- *  Copyright (C) 2002-2004 Stefan Eletzhofer
- *
- *	based on linux/drivers/acron/char/pcf8583.c
- *  Copyright (C) 2000 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Driver for system3's EPSON RTC 8564 chip
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/bcd.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/rtc.h>		/* get the user-level API */
-#include <linux/init.h>
-
-#include "rtc8564.h"
-
-#ifdef DEBUG
-# define _DBG(x, fmt, args...) do{ if (debug>=x) printk(KERN_DEBUG"%s: " fmt "\n", __FUNCTION__, ##args); } while(0);
-#else
-# define _DBG(x, fmt, args...) do { } while(0);
-#endif
-
-#define _DBGRTCTM(x, rtctm) if (debug>=x) printk("%s: secs=%d, mins=%d, hours=%d, mday=%d, " \
-			"mon=%d, year=%d, wday=%d VL=%d\n", __FUNCTION__, \
-			(rtctm).secs, (rtctm).mins, (rtctm).hours, (rtctm).mday, \
-			(rtctm).mon, (rtctm).year, (rtctm).wday, (rtctm).vl);
-
-struct rtc8564_data {
-	struct i2c_client client;
-	u16 ctrl;
-};
-
-static inline u8 _rtc8564_ctrl1(struct i2c_client *client)
-{
-	struct rtc8564_data *data = i2c_get_clientdata(client);
-	return data->ctrl & 0xff;
-}
-static inline u8 _rtc8564_ctrl2(struct i2c_client *client)
-{
-	struct rtc8564_data *data = i2c_get_clientdata(client);
-	return (data->ctrl & 0xff00) >> 8;
-}
-
-#define CTRL1(c) _rtc8564_ctrl1(c)
-#define CTRL2(c) _rtc8564_ctrl2(c)
-
-static int debug;
-module_param(debug, int, S_IRUGO | S_IWUSR);
-
-static struct i2c_driver rtc8564_driver;
-
-static unsigned short ignore[] = { I2C_CLIENT_END };
-static unsigned short normal_addr[] = { 0x51, I2C_CLIENT_END };
-
-static struct i2c_client_address_data addr_data = {
-	.normal_i2c		= normal_addr,
-	.probe			= ignore,
-	.ignore			= ignore,
-};
-
-static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem);
-static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem);
-
-static int rtc8564_read(struct i2c_client *client, unsigned char adr,
-			unsigned char *buf, unsigned char len)
-{
-	int ret = -EIO;
-	unsigned char addr[1] = { adr };
-	struct i2c_msg msgs[2] = {
-		{client->addr, 0, 1, addr},
-		{client->addr, I2C_M_RD, len, buf}
-	};
-
-	_DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, buf, len);
-
-	if (!buf) {
-		ret = -EINVAL;
-		goto done;
-	}
-
-	ret = i2c_transfer(client->adapter, msgs, 2);
-	if (ret == 2) {
-		ret = 0;
-	}
-
-done:
-	return ret;
-}
-
-static int rtc8564_write(struct i2c_client *client, unsigned char adr,
-			 unsigned char *data, unsigned char len)
-{
-	int ret = 0;
-	unsigned char _data[16];
-	struct i2c_msg wr;
-	int i;
-
-	if (!data || len > 15) {
-		ret = -EINVAL;
-		goto done;
-	}
-
-	_DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, data, len);
-
-	_data[0] = adr;
-	for (i = 0; i < len; i++) {
-		_data[i + 1] = data[i];
-		_DBG(5, "data[%d] = 0x%02x (%d)", i, data[i], data[i]);
-	}
-
-	wr.addr = client->addr;
-	wr.flags = 0;
-	wr.len = len + 1;
-	wr.buf = _data;
-
-	ret = i2c_transfer(client->adapter, &wr, 1);
-	if (ret == 1) {
-		ret = 0;
-	}
-
-done:
-	return ret;
-}
-
-static int rtc8564_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-	int ret;
-	struct i2c_client *new_client;
-	struct rtc8564_data *d;
-	unsigned char data[10];
-	unsigned char ad[1] = { 0 };
-	struct i2c_msg ctrl_wr[1] = {
-		{addr, 0, 2, data}
-	};
-	struct i2c_msg ctrl_rd[2] = {
-		{addr, 0, 1, ad},
-		{addr, I2C_M_RD, 2, data}
-	};
-
-	d = kzalloc(sizeof(struct rtc8564_data), GFP_KERNEL);
-	if (!d) {
-		ret = -ENOMEM;
-		goto done;
-	}
-	new_client = &d->client;
-
-	strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE);
-	i2c_set_clientdata(new_client, d);
-	new_client->addr = addr;
-	new_client->adapter = adap;
-	new_client->driver = &rtc8564_driver;
-
-	_DBG(1, "client=%p", new_client);
-
-	/* init ctrl1 reg */
-	data[0] = 0;
-	data[1] = 0;
-	ret = i2c_transfer(new_client->adapter, ctrl_wr, 1);
-	if (ret != 1) {
-		printk(KERN_INFO "rtc8564: cant init ctrl1\n");
-		ret = -ENODEV;
-		goto done;
-	}
-
-	/* read back ctrl1 and ctrl2 */
-	ret = i2c_transfer(new_client->adapter, ctrl_rd, 2);
-	if (ret != 2) {
-		printk(KERN_INFO "rtc8564: cant read ctrl\n");
-		ret = -ENODEV;
-		goto done;
-	}
-
-	d->ctrl = data[0] | (data[1] << 8);
-
-	_DBG(1, "RTC8564_REG_CTRL1=%02x, RTC8564_REG_CTRL2=%02x",
-	     data[0], data[1]);
-
-	ret = i2c_attach_client(new_client);
-done:
-	if (ret) {
-		kfree(d);
-	}
-	return ret;
-}
-
-static int rtc8564_probe(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, rtc8564_attach);
-}
-
-static int rtc8564_detach(struct i2c_client *client)
-{
-	i2c_detach_client(client);
-	kfree(i2c_get_clientdata(client));
-	return 0;
-}
-
-static int rtc8564_get_datetime(struct i2c_client *client, struct rtc_tm *dt)
-{
-	int ret = -EIO;
-	unsigned char buf[15];
-
-	_DBG(1, "client=%p, dt=%p", client, dt);
-
-	if (!dt)
-		return -EINVAL;
-
-	memset(buf, 0, sizeof(buf));
-
-	ret = rtc8564_read(client, 0, buf, 15);
-	if (ret)
-		return ret;
-
-	/* century stored in minute alarm reg */
-	dt->year = BCD2BIN(buf[RTC8564_REG_YEAR]);
-	dt->year += 100 * BCD2BIN(buf[RTC8564_REG_AL_MIN] & 0x3f);
-	dt->mday = BCD2BIN(buf[RTC8564_REG_DAY] & 0x3f);
-	dt->wday = BCD2BIN(buf[RTC8564_REG_WDAY] & 7);
-	dt->mon = BCD2BIN(buf[RTC8564_REG_MON_CENT] & 0x1f);
-
-	dt->secs = BCD2BIN(buf[RTC8564_REG_SEC] & 0x7f);
-	dt->vl = (buf[RTC8564_REG_SEC] & 0x80) == 0x80;
-	dt->mins = BCD2BIN(buf[RTC8564_REG_MIN] & 0x7f);
-	dt->hours = BCD2BIN(buf[RTC8564_REG_HR] & 0x3f);
-
-	_DBGRTCTM(2, *dt);
-
-	return 0;
-}
-
-static int
-rtc8564_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo)
-{
-	int ret, len = 5;
-	unsigned char buf[15];
-
-	_DBG(1, "client=%p, dt=%p", client, dt);
-
-	if (!dt)
-		return -EINVAL;
-
-	_DBGRTCTM(2, *dt);
-
-	buf[RTC8564_REG_CTRL1] = CTRL1(client) | RTC8564_CTRL1_STOP;
-	buf[RTC8564_REG_CTRL2] = CTRL2(client);
-	buf[RTC8564_REG_SEC] = BIN2BCD(dt->secs);
-	buf[RTC8564_REG_MIN] = BIN2BCD(dt->mins);
-	buf[RTC8564_REG_HR] = BIN2BCD(dt->hours);
-
-	if (datetoo) {
-		len += 5;
-		buf[RTC8564_REG_DAY] = BIN2BCD(dt->mday);
-		buf[RTC8564_REG_WDAY] = BIN2BCD(dt->wday);
-		buf[RTC8564_REG_MON_CENT] = BIN2BCD(dt->mon) & 0x1f;
-		/* century stored in minute alarm reg */
-		buf[RTC8564_REG_YEAR] = BIN2BCD(dt->year % 100);
-		buf[RTC8564_REG_AL_MIN] = BIN2BCD(dt->year / 100);
-	}
-
-	ret = rtc8564_write(client, 0, buf, len);
-	if (ret) {
-		_DBG(1, "error writing data! %d", ret);
-	}
-
-	buf[RTC8564_REG_CTRL1] = CTRL1(client);
-	ret = rtc8564_write(client, 0, buf, 1);
-	if (ret) {
-		_DBG(1, "error writing data! %d", ret);
-	}
-
-	return ret;
-}
-
-static int rtc8564_get_ctrl(struct i2c_client *client, unsigned int *ctrl)
-{
-	struct rtc8564_data *data = i2c_get_clientdata(client);
-
-	if (!ctrl)
-		return -1;
-
-	*ctrl = data->ctrl;
-	return 0;
-}
-
-static int rtc8564_set_ctrl(struct i2c_client *client, unsigned int *ctrl)
-{
-	struct rtc8564_data *data = i2c_get_clientdata(client);
-	unsigned char buf[2];
-
-	if (!ctrl)
-		return -1;
-
-	buf[0] = *ctrl & 0xff;
-	buf[1] = (*ctrl & 0xff00) >> 8;
-	data->ctrl = *ctrl;
-
-	return rtc8564_write(client, 0, buf, 2);
-}
-
-static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem)
-{
-
-	if (!mem)
-		return -EINVAL;
-
-	return rtc8564_read(client, mem->loc, mem->data, mem->nr);
-}
-
-static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem)
-{
-
-	if (!mem)
-		return -EINVAL;
-
-	return rtc8564_write(client, mem->loc, mem->data, mem->nr);
-}
-
-static int
-rtc8564_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-
-	_DBG(1, "cmd=%d", cmd);
-
-	switch (cmd) {
-	case RTC_GETDATETIME:
-		return rtc8564_get_datetime(client, arg);
-
-	case RTC_SETTIME:
-		return rtc8564_set_datetime(client, arg, 0);
-
-	case RTC_SETDATETIME:
-		return rtc8564_set_datetime(client, arg, 1);
-
-	case RTC_GETCTRL:
-		return rtc8564_get_ctrl(client, arg);
-
-	case RTC_SETCTRL:
-		return rtc8564_set_ctrl(client, arg);
-
-	case MEM_READ:
-		return rtc8564_read_mem(client, arg);
-
-	case MEM_WRITE:
-		return rtc8564_write_mem(client, arg);
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static struct i2c_driver rtc8564_driver = {
-	.driver = {
-		.name	= "RTC8564",
-	},
-	.id		= I2C_DRIVERID_RTC8564,
-	.attach_adapter = rtc8564_probe,
-	.detach_client	= rtc8564_detach,
-	.command	= rtc8564_command
-};
-
-static __init int rtc8564_init(void)
-{
-	return i2c_add_driver(&rtc8564_driver);
-}
-
-static __exit void rtc8564_exit(void)
-{
-	i2c_del_driver(&rtc8564_driver);
-}
-
-MODULE_AUTHOR("Stefan Eletzhofer <Stefan.Eletzhofer@eletztrick.de>");
-MODULE_DESCRIPTION("EPSON RTC8564 Driver");
-MODULE_LICENSE("GPL");
-
-module_init(rtc8564_init);
-module_exit(rtc8564_exit);
diff --git a/drivers/i2c/chips/rtc8564.h b/drivers/i2c/chips/rtc8564.h
deleted file mode 100644
index e5342d1..0000000
--- a/drivers/i2c/chips/rtc8564.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *  linux/drivers/i2c/chips/rtc8564.h
- *
- *  Copyright (C) 2002-2004 Stefan Eletzhofer
- *
- *	based on linux/drivers/acron/char/pcf8583.h
- *  Copyright (C) 2000 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-struct rtc_tm {
-	unsigned char	secs;
-	unsigned char	mins;
-	unsigned char	hours;
-	unsigned char	mday;
-	unsigned char	mon;
-	unsigned short	year; /* xxxx 4 digits :) */
-	unsigned char	wday;
-	unsigned char	vl;
-};
-
-struct mem {
-	unsigned int	loc;
-	unsigned int	nr;
-	unsigned char	*data;
-};
-
-#define RTC_GETDATETIME	0
-#define RTC_SETTIME	1
-#define RTC_SETDATETIME	2
-#define RTC_GETCTRL	3
-#define RTC_SETCTRL	4
-#define MEM_READ	5
-#define MEM_WRITE	6
-
-#define RTC8564_REG_CTRL1		0x0 /* T  0 S 0 | T 0 0 0 */
-#define RTC8564_REG_CTRL2		0x1 /* 0  0 0 TI/TP | AF TF AIE TIE */
-#define RTC8564_REG_SEC			0x2 /* VL 4 2 1 | 8 4 2 1 */
-#define RTC8564_REG_MIN			0x3 /* x  4 2 1 | 8 4 2 1 */
-#define RTC8564_REG_HR			0x4 /* x  x 2 1 | 8 4 2 1 */
-#define RTC8564_REG_DAY			0x5 /* x  x 2 1 | 8 4 2 1 */
-#define RTC8564_REG_WDAY		0x6 /* x  x x x | x 4 2 1 */
-#define RTC8564_REG_MON_CENT	0x7 /* C  x x 1 | 8 4 2 1 */
-#define RTC8564_REG_YEAR		0x8 /* 8  4 2 1 | 8 4 2 1 */
-#define RTC8564_REG_AL_MIN		0x9 /* AE 4 2 1 | 8 4 2 1 */
-#define RTC8564_REG_AL_HR		0xa /* AE 4 2 1 | 8 4 2 1 */
-#define RTC8564_REG_AL_DAY		0xb /* AE x 2 1 | 8 4 2 1 */
-#define RTC8564_REG_AL_WDAY		0xc /* AE x x x | x 4 2 1 */
-#define RTC8564_REG_CLKOUT		0xd /* FE x x x | x x FD1 FD0 */
-#define RTC8564_REG_TCTL		0xe /* TE x x x | x x FD1 FD0 */
-#define RTC8564_REG_TIMER		0xf /* 8 bit binary */
-
-/* Control reg */
-#define RTC8564_CTRL1_TEST1		(1<<3)
-#define RTC8564_CTRL1_STOP		(1<<5)
-#define RTC8564_CTRL1_TEST2		(1<<7)
-
-#define RTC8564_CTRL2_TIE		(1<<0)
-#define RTC8564_CTRL2_AIE		(1<<1)
-#define RTC8564_CTRL2_TF		(1<<2)
-#define RTC8564_CTRL2_AF		(1<<3)
-#define RTC8564_CTRL2_TI_TP		(1<<4)
-
-/* CLKOUT frequencies */
-#define RTC8564_FD_32768HZ		(0x0)
-#define RTC8564_FD_1024HZ		(0x1)
-#define RTC8564_FD_32			(0x2)
-#define RTC8564_FD_1HZ			(0x3)
-
-/* Timer CTRL */
-#define RTC8564_TD_4096HZ		(0x0)
-#define RTC8564_TD_64HZ			(0x1)
-#define RTC8564_TD_1HZ			(0x2)
-#define RTC8564_TD_1_60HZ		(0x3)
-
-#define I2C_DRIVERID_RTC8564 0xf000
diff --git a/drivers/i2c/chips/x1205.c b/drivers/i2c/chips/x1205.c
deleted file mode 100644
index 245fffa..0000000
--- a/drivers/i2c/chips/x1205.c
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
- *  x1205.c - An i2c driver for the Xicor X1205 RTC
- *  Copyright 2004 Karen Spearel
- *  Copyright 2005 Alessandro Zummo
- *
- *  please send all reports to:
- *	kas11 at tampabay dot rr dot com
- *      a dot zummo at towertech dot it
- *
- *  based on the other drivers in this same directory.
- *
- *  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/init.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/string.h>
-#include <linux/bcd.h>
-#include <linux/rtc.h>
-#include <linux/list.h>
-
-#include <linux/x1205.h>
-
-#define DRV_VERSION "0.9.9"
-
-/* Addresses to scan: none. This chip is located at
- * 0x6f and uses a two bytes register addressing.
- * Two bytes need to be written to read a single register,
- * while most other chips just require one and take the second
- * one as the data to be written. To prevent corrupting
- * unknown chips, the user must explicitely set the probe parameter.
- */
-
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-
-/* Insmod parameters */
-I2C_CLIENT_INSMOD;
-I2C_CLIENT_MODULE_PARM(hctosys,
-	"Set the system time from the hardware clock upon initialization");
-
-/* offsets into CCR area */
-
-#define CCR_SEC			0
-#define CCR_MIN			1
-#define CCR_HOUR		2
-#define CCR_MDAY		3
-#define CCR_MONTH		4
-#define CCR_YEAR		5
-#define CCR_WDAY		6
-#define CCR_Y2K			7
-
-#define X1205_REG_SR		0x3F	/* status register */
-#define X1205_REG_Y2K		0x37
-#define X1205_REG_DW		0x36
-#define X1205_REG_YR		0x35
-#define X1205_REG_MO		0x34
-#define X1205_REG_DT		0x33
-#define X1205_REG_HR		0x32
-#define X1205_REG_MN		0x31
-#define X1205_REG_SC		0x30
-#define X1205_REG_DTR		0x13
-#define X1205_REG_ATR		0x12
-#define X1205_REG_INT		0x11
-#define X1205_REG_0		0x10
-#define X1205_REG_Y2K1		0x0F
-#define X1205_REG_DWA1		0x0E
-#define X1205_REG_YRA1		0x0D
-#define X1205_REG_MOA1		0x0C
-#define X1205_REG_DTA1		0x0B
-#define X1205_REG_HRA1		0x0A
-#define X1205_REG_MNA1		0x09
-#define X1205_REG_SCA1		0x08
-#define X1205_REG_Y2K0		0x07
-#define X1205_REG_DWA0		0x06
-#define X1205_REG_YRA0		0x05
-#define X1205_REG_MOA0		0x04
-#define X1205_REG_DTA0		0x03
-#define X1205_REG_HRA0		0x02
-#define X1205_REG_MNA0		0x01
-#define X1205_REG_SCA0		0x00
-
-#define X1205_CCR_BASE		0x30	/* Base address of CCR */
-#define X1205_ALM0_BASE		0x00	/* Base address of ALARM0 */
-
-#define X1205_SR_RTCF		0x01	/* Clock failure */
-#define X1205_SR_WEL		0x02	/* Write Enable Latch */
-#define X1205_SR_RWEL		0x04	/* Register Write Enable */
-
-#define X1205_DTR_DTR0		0x01
-#define X1205_DTR_DTR1		0x02
-#define X1205_DTR_DTR2		0x04
-
-#define X1205_HR_MIL		0x80	/* Set in ccr.hour for 24 hr mode */
-
-/* Prototypes */
-static int x1205_attach(struct i2c_adapter *adapter);
-static int x1205_detach(struct i2c_client *client);
-static int x1205_probe(struct i2c_adapter *adapter, int address, int kind);
-static int x1205_command(struct i2c_client *client, unsigned int cmd,
-	void *arg);
-
-static struct i2c_driver x1205_driver = {
-	.driver = {
-		.name	= "x1205",
-	},
-	.attach_adapter = &x1205_attach,
-	.detach_client	= &x1205_detach,
-};
-
-struct x1205_data {
-	struct i2c_client client;
-	struct list_head list;
-	unsigned int epoch;
-};
-
-static const unsigned char days_in_mo[] =
-	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
-static LIST_HEAD(x1205_clients);
-
-/* Workaround until the I2C subsytem will allow to send
- * commands to a specific client. This function will send the command
- * to the first client.
- */
-int x1205_do_command(unsigned int cmd, void *arg)
-{
-	struct list_head *walk;
-	struct list_head *tmp;
-	struct x1205_data *data;
-
-	list_for_each_safe(walk, tmp, &x1205_clients) {
-		data = list_entry(walk, struct x1205_data, list);
-		return x1205_command(&data->client, cmd, arg);
-	}
-
-	return -ENODEV;
-}
-
-#define is_leap(year) \
-	((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
-
-/* make sure the rtc_time values are in bounds */
-static int x1205_validate_tm(struct rtc_time *tm)
-{
-	int year = tm->tm_year + 1900;
-
-	if ((tm->tm_year < 70) || (tm->tm_year > 255))
-		return -EINVAL;
-
-	if ((tm->tm_mon > 11) || (tm->tm_mday == 0))
-		return -EINVAL;
-
-	if (tm->tm_mday > days_in_mo[tm->tm_mon]
-		+ ((tm->tm_mon == 1) && is_leap(year)))
-		return -EINVAL;
-
-	if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) || (tm->tm_sec >= 60))
-		return -EINVAL;
-
-	return 0;
-}
-
-/*
- * In the routines that deal directly with the x1205 hardware, we use
- * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
- * Epoch is initialized as 2000. Time is set to UTC.
- */
-static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
-				u8 reg_base)
-{
-	unsigned char dt_addr[2] = { 0, reg_base };
-	static unsigned char sr_addr[2] = { 0, X1205_REG_SR };
-
-	unsigned char buf[8], sr;
-
-	struct i2c_msg msgs[] = {
-		{ client->addr, 0, 2, sr_addr },	/* setup read ptr */
-		{ client->addr, I2C_M_RD, 1, &sr }, 	/* read status */
-		{ client->addr, 0, 2, dt_addr },	/* setup read ptr */
-		{ client->addr, I2C_M_RD, 8, buf },	/* read date */
-	};
-
-	struct x1205_data *data = i2c_get_clientdata(client);
-
-	/* read status register */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
-		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
-		return -EIO;
-	}
-
-	/* check for battery failure */
-	if (sr & X1205_SR_RTCF) {
-		dev_warn(&client->dev,
-			"Clock had a power failure, you must set the date.\n");
-		return -EINVAL;
-	}
-
-	/* read date registers */
-	if ((i2c_transfer(client->adapter, &msgs[2], 2)) != 2) {
-		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
-		return -EIO;
-	}
-
-	dev_dbg(&client->dev,
-		"%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
-		"mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
-		__FUNCTION__,
-		buf[0], buf[1], buf[2], buf[3],
-		buf[4], buf[5], buf[6], buf[7]);
-
-	tm->tm_sec = BCD2BIN(buf[CCR_SEC]);
-	tm->tm_min = BCD2BIN(buf[CCR_MIN]);
-	tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
-	tm->tm_mday = BCD2BIN(buf[CCR_MDAY]);
-	tm->tm_mon = BCD2BIN(buf[CCR_MONTH]);
-	data->epoch = BCD2BIN(buf[CCR_Y2K]) * 100;
-	tm->tm_year = BCD2BIN(buf[CCR_YEAR]) + data->epoch - 1900;
-	tm->tm_wday = buf[CCR_WDAY];
-
-	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
-		"mday=%d, mon=%d, year=%d, wday=%d\n",
-		__FUNCTION__,
-		tm->tm_sec, tm->tm_min, tm->tm_hour,
-		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
-
-	return 0;
-}
-
-static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
-				int datetoo, u8 reg_base)
-{
-	int i, err, xfer;
-
-	unsigned char buf[8];
-
-	static const unsigned char wel[3] = { 0, X1205_REG_SR,
-						X1205_SR_WEL };
-
-	static const unsigned char rwel[3] = { 0, X1205_REG_SR,
-						X1205_SR_WEL | X1205_SR_RWEL };
-
-	static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 };
-
-	struct x1205_data *data = i2c_get_clientdata(client);
-
-	/* check if all values in the tm struct are correct */
-	if ((err = x1205_validate_tm(tm)) < 0)
-		return err;
-
-	dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
-		"mday=%d, mon=%d, year=%d, wday=%d\n",
-		__FUNCTION__,
-		tm->tm_sec, tm->tm_min, tm->tm_hour,
-		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
-
-	buf[CCR_SEC] = BIN2BCD(tm->tm_sec);
-	buf[CCR_MIN] = BIN2BCD(tm->tm_min);
-
-	/* set hour and 24hr bit */
-	buf[CCR_HOUR] = BIN2BCD(tm->tm_hour) | X1205_HR_MIL;
-
-	/* should we also set the date? */
-	if (datetoo) {
-		buf[CCR_MDAY] = BIN2BCD(tm->tm_mday);
-
-		/* month, 0 - 11 */
-		buf[CCR_MONTH] = BIN2BCD(tm->tm_mon);
-
-		/* year, since 1900 */
-		buf[CCR_YEAR] = BIN2BCD(tm->tm_year + 1900 - data->epoch);
-		buf[CCR_WDAY] = tm->tm_wday & 0x07;
-		buf[CCR_Y2K] = BIN2BCD(data->epoch / 100);
-	}
-
-	/* this sequence is required to unlock the chip */
-	xfer = i2c_master_send(client, wel, 3);
-	if (xfer != 3) {
-		dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer);
-		return -EIO;
-	}
-
-	xfer = i2c_master_send(client, rwel, 3);
-	if (xfer != 3) {
-		dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer);
-		return -EIO;
-	}
-
-	/* write register's data */
-	for (i = 0; i < (datetoo ? 8 : 3); i++) {
-		unsigned char rdata[3] = { 0, reg_base + i, buf[i] };
-
-		xfer = i2c_master_send(client, rdata, 3);
-		if (xfer != 3) {
-			dev_err(&client->dev,
-				"%s: xfer=%d addr=%02x, data=%02x\n",
-				__FUNCTION__,
-				 xfer, rdata[1], rdata[2]);
-			return -EIO;
-		}
-	};
-
-	/* disable further writes */
-	xfer = i2c_master_send(client, diswe, 3);
-	if (xfer != 3) {
-		dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int x1205_get_dtrim(struct i2c_client *client, int *trim)
-{
-	unsigned char dtr;
-	static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR };
-
-	struct i2c_msg msgs[] = {
-		{ client->addr, 0, 2, dtr_addr },	/* setup read ptr */
-		{ client->addr, I2C_M_RD, 1, &dtr }, 	/* read dtr */
-	};
-
-	/* read dtr register */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
-		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
-		return -EIO;
-	}
-
-	dev_dbg(&client->dev, "%s: raw dtr=%x\n", __FUNCTION__, dtr);
-
-	*trim = 0;
-
-	if (dtr & X1205_DTR_DTR0)
-		*trim += 20;
-
-	if (dtr & X1205_DTR_DTR1)
-		*trim += 10;
-
-	if (dtr & X1205_DTR_DTR2)
-		*trim = -*trim;
-
-	return 0;
-}
-
-static int x1205_get_atrim(struct i2c_client *client, int *trim)
-{
-	s8 atr;
-	static unsigned char atr_addr[2] = { 0, X1205_REG_ATR };
-
-	struct i2c_msg msgs[] = {
-		{ client->addr, 0, 2, atr_addr },	/* setup read ptr */
-		{ client->addr, I2C_M_RD, 1, &atr }, 	/* read atr */
-	};
-
-	/* read atr register */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
-		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
-		return -EIO;
-	}
-
-	dev_dbg(&client->dev, "%s: raw atr=%x\n", __FUNCTION__, atr);
-
-	/* atr is a two's complement value on 6 bits,
-	 * perform sign extension. The formula is
-	 * Catr = (atr * 0.25pF) + 11.00pF.
-	 */
-	if (atr & 0x20)
-		atr |= 0xC0;
-
-	dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __FUNCTION__, atr, atr);
-
-	*trim = (atr * 250) + 11000;
-
-	dev_dbg(&client->dev, "%s: real=%d\n", __FUNCTION__, *trim);
-
-	return 0;
-}
-
-static int x1205_hctosys(struct i2c_client *client)
-{
-	int err;
-
-	struct rtc_time tm;
-	struct timespec tv;
-
-	err = x1205_command(client, X1205_CMD_GETDATETIME, &tm);
-
-	if (err) {
-		dev_err(&client->dev,
-			"Unable to set the system clock\n");
-		return err;
-	}
-
-	/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
-	 * whether it stores the most close value or the value with partial
-	 * seconds truncated. However, it is important that we use it to store
-	 * the truncated value. This is because otherwise it is necessary,
-	 * in an rtc sync function, to read both xtime.tv_sec and
-	 * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
-	 * of >32bits is not possible. So storing the most close value would
-	 * slow down the sync API. So here we have the truncated value and
-	 * the best guess is to add 0.5s.
-	 */
-
-	tv.tv_nsec = NSEC_PER_SEC >> 1;
-
-	/* WARNING: this is not the C library 'mktime' call, it is a built in
-	 * inline function from include/linux/time.h.  It expects (requires)
-	 * the month to be in the range 1-12
-	 */
-
-	tv.tv_sec  = mktime(tm.tm_year + 1900, tm.tm_mon + 1,
-				tm.tm_mday, tm.tm_hour,
-				tm.tm_min, tm.tm_sec);
-
-	do_settimeofday(&tv);
-
-	dev_info(&client->dev,
-		"setting the system clock to %d-%d-%d %d:%d:%d\n",
-		tm.tm_year + 1900, tm.tm_mon + 1,
-		tm.tm_mday, tm.tm_hour, tm.tm_min,
-		tm.tm_sec);
-
-	return 0;
-}
-
-struct x1205_limit
-{
-	unsigned char reg;
-	unsigned char mask;
-	unsigned char min;
-	unsigned char max;
-};
-
-static int x1205_validate_client(struct i2c_client *client)
-{
-	int i, xfer;
-
-	/* Probe array. We will read the register at the specified
-	 * address and check if the given bits are zero.
-	 */
-	static const unsigned char probe_zero_pattern[] = {
-		/* register, mask */
-		X1205_REG_SR,	0x18,
-		X1205_REG_DTR,	0xF8,
-		X1205_REG_ATR,	0xC0,
-		X1205_REG_INT,	0x18,
-		X1205_REG_0,	0xFF,
-	};
-
-	static const struct x1205_limit probe_limits_pattern[] = {
-		/* register, mask, min, max */
-		{ X1205_REG_Y2K,	0xFF,	19,	20	},
-		{ X1205_REG_DW,		0xFF,	0,	6	},
-		{ X1205_REG_YR,		0xFF,	0,	99	},
-		{ X1205_REG_MO,		0xFF,	0,	12	},
-		{ X1205_REG_DT,		0xFF,	0,	31	},
-		{ X1205_REG_HR,		0x7F,	0,	23	},
-		{ X1205_REG_MN,		0xFF,	0,	59	},
-		{ X1205_REG_SC,		0xFF,	0,	59	},
-		{ X1205_REG_Y2K1,	0xFF,	19,	20	},
-		{ X1205_REG_Y2K0,	0xFF,	19,	20	},
-	};
-
-	/* check that registers have bits a 0 where expected */
-	for (i = 0; i < ARRAY_SIZE(probe_zero_pattern); i += 2) {
-		unsigned char buf;
-
-		unsigned char addr[2] = { 0, probe_zero_pattern[i] };
-
-		struct i2c_msg msgs[2] = {
-			{ client->addr, 0, 2, addr },
-			{ client->addr, I2C_M_RD, 1, &buf },
-		};
-
-		xfer = i2c_transfer(client->adapter, msgs, 2);
-		if (xfer != 2) {
-			dev_err(&client->adapter->dev,
-				"%s: could not read register %x\n",
-				__FUNCTION__, addr[1]);
-
-			return -EIO;
-		}
-
-		if ((buf & probe_zero_pattern[i+1]) != 0) {
-			dev_err(&client->adapter->dev,
-				"%s: register=%02x, zero pattern=%d, value=%x\n",
-				__FUNCTION__, addr[1], i, buf);
-
-			return -ENODEV;
-		}
-	}
-
-	/* check limits (only registers with bcd values) */
-	for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) {
-		unsigned char reg, value;
-
-		unsigned char addr[2] = { 0, probe_limits_pattern[i].reg };
-
-		struct i2c_msg msgs[2] = {
-			{ client->addr, 0, 2, addr },
-			{ client->addr, I2C_M_RD, 1, &reg },
-		};
-
-		xfer = i2c_transfer(client->adapter, msgs, 2);
-
-		if (xfer != 2) {
-			dev_err(&client->adapter->dev,
-				"%s: could not read register %x\n",
-				__FUNCTION__, addr[1]);
-
-			return -EIO;
-		}
-
-		value = BCD2BIN(reg & probe_limits_pattern[i].mask);
-
-		if (value > probe_limits_pattern[i].max ||
-			value < probe_limits_pattern[i].min) {
-			dev_dbg(&client->adapter->dev,
-				"%s: register=%x, lim pattern=%d, value=%d\n",
-				__FUNCTION__, addr[1], i, value);
-
-			return -ENODEV;
-		}
-	}
-
-	return 0;
-}
-
-static int x1205_attach(struct i2c_adapter *adapter)
-{
-	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
-
-	return i2c_probe(adapter, &addr_data, x1205_probe);
-}
-
-int x1205_direct_attach(int adapter_id,
-	struct i2c_client_address_data *address_data)
-{
-	int err;
-	struct i2c_adapter *adapter = i2c_get_adapter(adapter_id);
-
-	if (adapter) {
-		err = i2c_probe(adapter,
-			address_data, x1205_probe);
-
-		i2c_put_adapter(adapter);
-
-		return err;
-	}
-
-	return -ENODEV;
-}
-
-static int x1205_probe(struct i2c_adapter *adapter, int address, int kind)
-{
-	struct i2c_client *client;
-	struct x1205_data *data;
-
-	int err = 0;
-
-	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
-
-	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
-		err = -ENODEV;
-		goto exit;
-	}
-
-	if (!(data = kzalloc(sizeof(struct x1205_data), GFP_KERNEL))) {
-		err = -ENOMEM;
-		goto exit;
-	}
-
-	/* Initialize our structures */
-	data->epoch = 2000;
-
-	client = &data->client;
-	client->addr = address;
-	client->driver = &x1205_driver;
-	client->adapter	= adapter;
-
-	strlcpy(client->name, "x1205", I2C_NAME_SIZE);
-
-	i2c_set_clientdata(client, data);
-
-	/* Verify the chip is really an X1205 */
-	if (kind < 0) {
-		if (x1205_validate_client(client) < 0) {
-			err = -ENODEV;
-			goto exit_kfree;
-		}
-	}
-
-	/* Inform the i2c layer */
-	if ((err = i2c_attach_client(client)))
-		goto exit_kfree;
-
-	list_add(&data->list, &x1205_clients);
-
-	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
-
-	/* If requested, set the system time */
-	if (hctosys)
-		x1205_hctosys(client);
-
-	return 0;
-
-exit_kfree:
-	kfree(data);
-
-exit:
-	return err;
-}
-
-static int x1205_detach(struct i2c_client *client)
-{
-	int err;
-	struct x1205_data *data = i2c_get_clientdata(client);
-
-	dev_dbg(&client->dev, "%s\n", __FUNCTION__);
-
-	if ((err = i2c_detach_client(client)))
-		return err;
-
-	list_del(&data->list);
-
-	kfree(data);
-
-	return 0;
-}
-
-static int x1205_command(struct i2c_client *client, unsigned int cmd,
-	void *param)
-{
-	if (param == NULL)
-		return -EINVAL;
-
-	if (!capable(CAP_SYS_TIME))
-		return -EACCES;
-
-	dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
-
-	switch (cmd) {
-	case X1205_CMD_GETDATETIME:
-		return x1205_get_datetime(client, param, X1205_CCR_BASE);
-
-	case X1205_CMD_SETTIME:
-		return x1205_set_datetime(client, param, 0,
-				X1205_CCR_BASE);
-
-	case X1205_CMD_SETDATETIME:
-		return x1205_set_datetime(client, param, 1,
-				X1205_CCR_BASE);
-
-	case X1205_CMD_GETALARM:
-		return x1205_get_datetime(client, param, X1205_ALM0_BASE);
-
-	case X1205_CMD_SETALARM:
-		return x1205_set_datetime(client, param, 1,
-				X1205_ALM0_BASE);
-
-	case X1205_CMD_GETDTRIM:
-		return x1205_get_dtrim(client, param);
-
-	case X1205_CMD_GETATRIM:
-		return x1205_get_atrim(client, param);
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static int __init x1205_init(void)
-{
-	return i2c_add_driver(&x1205_driver);
-}
-
-static void __exit x1205_exit(void)
-{
-	i2c_del_driver(&x1205_driver);
-}
-
-MODULE_AUTHOR(
-	"Karen Spearel <kas11@tampabay.rr.com>, "
-	"Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("Xicor X1205 RTC driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
-EXPORT_SYMBOL_GPL(x1205_do_command);
-EXPORT_SYMBOL_GPL(x1205_direct_attach);
-
-module_init(x1205_init);
-module_exit(x1205_exit);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index c7671e1..b4a41d6 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -2143,6 +2143,7 @@
 	req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
 	req.data = (char *)&capbuf;
 	req.data_len = sizeof(capbuf);
+	req.flags |= REQ_QUIET;
 
 	stat = cdrom_queue_packet_command(drive, &req);
 	if (stat == 0) {
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index ccf528d..a5017de 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -61,6 +61,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
+#include <linux/leds.h>
 
 #define _IDE_DISK
 
@@ -317,6 +318,8 @@
 		return ide_stopped;
 	}
 
+	ledtrig_ide_activity();
+
 	pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n",
 		 drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
 		 (unsigned long long)block, rq->nr_sectors,
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index ebc5906..f04791a 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -433,6 +433,7 @@
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
+#include <linux/jiffies.h>
 #include <linux/major.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/errno.h>
@@ -2336,7 +2337,7 @@
 	}
 	if (time_after(jiffies, tape->insert_time))
 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
-	if (jiffies - tape->avg_time >= HZ) {
+	if (time_after_eq(jiffies, tape->avg_time + HZ)) {
 		tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024;
 		tape->avg_size = 0;
 		tape->avg_time = jiffies;
@@ -2497,7 +2498,7 @@
 			} else {
 				return ide_do_reset(drive);
 			}
-		} else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
+		} else if (time_after(jiffies, tape->dsc_polling_start + IDETAPE_DSC_MA_THRESHOLD))
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
 		idetape_postpone_request(drive);
 		return ide_stopped;
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 0606bd2..9233b81 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -375,7 +375,13 @@
 		}
 	}
 
-	ide_end_request(drive, 1, rq->hard_nr_sectors);
+	if (rq->rq_disk) {
+		ide_driver_t *drv;
+
+		drv = *(ide_driver_t **)rq->rq_disk->private_data;;
+		drv->end_request(drive, 1, rq->hard_nr_sectors);
+	} else
+		ide_end_request(drive, 1, rq->hard_nr_sectors);
 }
 
 /*
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 21965e5..b22ee54 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -347,10 +347,8 @@
 			break;
 
 		case AMD_UDMA_66:
-			pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
-			for (i = 24; i >= 0; i -= 8)
-				if ((u >> i) & 4)
-					amd_80w |= (1 << (1 - (i >> 4)));
+			/* no host side cable detection */
+			amd_80w = 0x03;
 			break;
 	}
 
@@ -386,8 +384,6 @@
 	if (amd_clock < 20000 || amd_clock > 50000) {
 		printk(KERN_WARNING "%s: User given PCI clock speed impossible (%d), using 33 MHz instead.\n",
 			amd_chipset->name, amd_clock);
-		printk(KERN_WARNING "%s: Use ide0=ata66 if you want to assume 80-wire cable\n",
-			amd_chipset->name);
 		amd_clock = 33333;
 	}
 
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index 6e3ab0c..f82e821 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -41,14 +41,15 @@
 
 static int ide_generic_all;		/* Set to claim all devices */
 
+#ifndef MODULE
 static int __init ide_generic_all_on(char *unused)
 {
 	ide_generic_all = 1;
 	printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n");
 	return 1;
 }
-
 __setup("all-generic-ide", ide_generic_all_on);
+#endif
 
 static void __devinit init_hwif_generic (ide_hwif_t *hwif)
 {
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 75a2253..8e9d877 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -112,6 +112,7 @@
 
 	{ "SiS5596",	PCI_DEVICE_ID_SI_5596,	ATA_16   },
 	{ "SiS5571",	PCI_DEVICE_ID_SI_5571,	ATA_16   },
+	{ "SiS5517",	PCI_DEVICE_ID_SI_5517,	ATA_16   },
 	{ "SiS551x",	PCI_DEVICE_ID_SI_5511,	ATA_16   },
 };
 
@@ -524,6 +525,7 @@
 			case 3:		test1 = 0x30|0x03; break;
 			case 2:		test1 = 0x40|0x04; break;
 			case 1:		test1 = 0x60|0x07; break;
+			case 0:		test1 = 0x00; break;
 			default:	break;
 		}
 		pci_write_config_byte(dev, drive_pci, test1);
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index c85b87c..3e677c4 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -440,7 +440,7 @@
 
 
 #if defined(CONFIG_PPC_CHRP) && defined(CONFIG_PPC32)
-	if(_machine == _MACH_chrp && _chrp_type == _CHRP_Pegasos) {
+	if(machine_is(chrp) && _chrp_type == _CHRP_Pegasos) {
 		hwif->irq = hwif->channel ? 15 : 14;
 	}
 #endif
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 5013b12..78e30f8 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1677,7 +1677,7 @@
 void __init
 pmac_ide_probe(void)
 {
-	if (_machine != _MACH_Pmac)
+	if (!machine_is(powermac))
 		return;
 
 #ifdef CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index efeaa94..85c2d4c 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -73,7 +73,7 @@
   - fix all XXX showstoppers
   - disable IR/IT DMA interrupts on shutdown
   - flush pci writes to the card by issuing a read
-  - devfs and character device dispatching (* needs testing with Linux 2.2.x)
+  - character device dispatching
   - switch over to the new kernel DMA API (pci_map_*()) (* needs testing on platforms with IOMMU!)
   - keep all video_cards in a list (for open() via chardev), set file->private_data = video
   - dv1394_poll should indicate POLLIN when receiving buffers are available
@@ -1096,7 +1096,6 @@
 
 	init.api_version = DV1394_API_VERSION;
 	init.n_frames = DV1394_MAX_FRAMES / 4;
-	/* the following are now set via devfs */
 	init.channel = video->channel;
 	init.format = video->pal_or_ntsc;
 	init.cip_n = video->cip_n;
@@ -1791,8 +1790,6 @@
 {
 	struct video_card *video = NULL;
 
-	/* if the device was opened through devfs, then file->private_data
-	   has already been set to video by devfs */
 	if (file->private_data) {
 		video = (struct video_card*) file->private_data;
 
@@ -2211,7 +2208,7 @@
 	video = kzalloc(sizeof(*video), GFP_KERNEL);
 	if (!video) {
 		printk(KERN_ERR "dv1394: cannot allocate video_card\n");
-		goto err;
+		return -1;
 	}
 
 	video->ohci = ohci;
@@ -2266,37 +2263,14 @@
 	list_add_tail(&video->list, &dv1394_cards);
 	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
 
-	if (devfs_mk_cdev(MKDEV(IEEE1394_MAJOR,
-				IEEE1394_MINOR_BLOCK_DV1394*16 + video->id),
-			S_IFCHR|S_IRUGO|S_IWUGO,
-			 "ieee1394/dv/host%d/%s/%s",
-			 (video->id>>2),
-			 (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
-			 (video->mode == MODE_RECEIVE ? "in" : "out")) < 0)
-			goto err_free;
-
 	debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id);
-
 	return 0;
-
- err_free:
-	kfree(video);
- err:
-	return -1;
 }
 
 static void dv1394_un_init(struct video_card *video)
 {
-	char buf[32];
-
 	/* obviously nobody has the driver open at this point */
 	do_dv1394_shutdown(video, 1);
-	snprintf(buf, sizeof(buf), "dv/host%d/%s/%s", (video->id >> 2),
-		(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
-		(video->mode == MODE_RECEIVE ? "in" : "out")
-		);
-
-	devfs_remove("ieee1394/%s", buf);
 	kfree(video);
 }
 
@@ -2333,9 +2307,6 @@
 
 	class_device_destroy(hpsb_protocol_class,
 		MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)));
-	devfs_remove("ieee1394/dv/host%d/NTSC", id);
-	devfs_remove("ieee1394/dv/host%d/PAL", id);
-	devfs_remove("ieee1394/dv/host%d", id);
 }
 
 static void dv1394_add_host (struct hpsb_host *host)
@@ -2352,9 +2323,6 @@
 	class_device_create(hpsb_protocol_class, NULL, MKDEV(
 		IEEE1394_MAJOR,	IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)), 
 		NULL, "dv1394-%d", id);
-	devfs_mk_dir("ieee1394/dv/host%d", id);
-	devfs_mk_dir("ieee1394/dv/host%d/NTSC", id);
-	devfs_mk_dir("ieee1394/dv/host%d/PAL", id);
 
 	dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
 	dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT);
@@ -2611,10 +2579,8 @@
 static void __exit dv1394_exit_module(void)
 {
 	hpsb_unregister_protocol(&dv1394_driver);
-
 	hpsb_unregister_highlevel(&dv1394_highlevel);
 	cdev_del(&dv1394_cdev);
-	devfs_remove("ieee1394/dv");
 }
 
 static int __init dv1394_init_module(void)
@@ -2630,15 +2596,12 @@
 		return ret;
 	}
 
-	devfs_mk_dir("ieee1394/dv");
-
 	hpsb_register_highlevel(&dv1394_highlevel);
 
 	ret = hpsb_register_protocol(&dv1394_driver);
 	if (ret) {
 		printk(KERN_ERR "dv1394: failed to register protocol\n");
 		hpsb_unregister_highlevel(&dv1394_highlevel);
-		devfs_remove("ieee1394/dv");
 		cdev_del(&dv1394_cdev);
 		return ret;
 	}
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
index 734b121..491e603 100644
--- a/drivers/ieee1394/highlevel.c
+++ b/drivers/ieee1394/highlevel.c
@@ -306,8 +306,7 @@
 	u64 align_mask = ~(alignment - 1);
 
 	if ((alignment & 3) || (alignment > 0x800000000000ULL) ||
-	    ((hweight32(alignment >> 32) +
-	      hweight32(alignment & 0xffffffff) != 1))) {
+	    (hweight64(alignment) != 1)) {
 		HPSB_ERR("%s called with invalid alignment: 0x%048llx",
 			 __FUNCTION__, (unsigned long long)alignment);
 		return retval;
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index 25ef5a8..be6854e 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -58,7 +58,7 @@
 
 /* Disable Isochronous Resource Manager functionality */
 int hpsb_disable_irm = 0;
-module_param_named(disable_irm, hpsb_disable_irm, bool, 0);
+module_param_named(disable_irm, hpsb_disable_irm, bool, 0444);
 MODULE_PARM_DESC(disable_irm,
 		 "Disable Isochronous Resource Manager functionality.");
 
@@ -1078,17 +1078,10 @@
 		goto exit_release_kernel_thread;
 	}
 
-	/* actually this is a non-fatal error */
-	ret = devfs_mk_dir("ieee1394");
-	if (ret < 0) {
-		HPSB_ERR("unable to make devfs dir for device major %d!\n", IEEE1394_MAJOR);
-		goto release_chrdev;
-	}
-
 	ret = bus_register(&ieee1394_bus_type);
 	if (ret < 0) {
 		HPSB_INFO("bus register failed");
-		goto release_devfs;
+		goto release_chrdev;
 	}
 
 	for (i = 0; fw_bus_attrs[i]; i++) {
@@ -1099,7 +1092,7 @@
 						fw_bus_attrs[i--]);
 			}
 			bus_unregister(&ieee1394_bus_type);
-			goto release_devfs;
+			goto release_chrdev;
 		}
 	}
 
@@ -1152,8 +1145,6 @@
 	for (i = 0; fw_bus_attrs[i]; i++)
 		bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
 	bus_unregister(&ieee1394_bus_type);
-release_devfs:
-	devfs_remove("ieee1394");
 release_chrdev:
 	unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
 exit_release_kernel_thread:
@@ -1191,7 +1182,6 @@
 	hpsb_cleanup_config_roms();
 
 	unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
-	devfs_remove("ieee1394");
 }
 
 module_init(ieee1394_init);
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index b354660..e7b55e8 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -3,7 +3,6 @@
 #define _IEEE1394_CORE_H
 
 #include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
 #include "hosts.h"
@@ -202,14 +201,12 @@
 #define IEEE1394_MINOR_BLOCK_RAW1394	   0
 #define IEEE1394_MINOR_BLOCK_VIDEO1394	   1
 #define IEEE1394_MINOR_BLOCK_DV1394	   2
-#define IEEE1394_MINOR_BLOCK_AMDTP	   3
 #define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
 
 #define IEEE1394_CORE_DEV	  MKDEV(IEEE1394_MAJOR, 0)
 #define IEEE1394_RAW1394_DEV	  MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16)
 #define IEEE1394_VIDEO1394_DEV	  MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_VIDEO1394 * 16)
 #define IEEE1394_DV1394_DEV	  MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16)
-#define IEEE1394_AMDTP_DEV	  MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_AMDTP * 16)
 #define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
 
 /* return the index (within a minor number block) of a file */
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index b6b96fa..1922287 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -544,12 +544,19 @@
 	/* Initialize IR Legacy DMA channel mask */
 	ohci->ir_legacy_channels = 0;
 
-	/*
-	 * Accept AT requests from all nodes. This probably
-	 * will have to be controlled from the subsystem
-	 * on a per node basis.
-	 */
-	reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);
+	/* Accept AR requests from all nodes */
+	reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
+
+	/* Set the address range of the physical response unit.
+	 * Most controllers do not implement it as a writable register though.
+	 * They will keep a hardwired offset of 0x00010000 and show 0x0 as
+	 * register content.
+	 * To actually enable physical responses is the job of our interrupt
+	 * handler which programs the physical request filter. */
+	reg_write(ohci, OHCI1394_PhyUpperBound, 0xffff0000);
+
+	DBGMSG("physUpperBoundOffset=%08x",
+	       reg_read(ohci, OHCI1394_PhyUpperBound));
 
 	/* Specify AT retries */
 	reg_write(ohci, OHCI1394_ATRetries,
@@ -572,6 +579,7 @@
 		  OHCI1394_reqTxComplete |
 		  OHCI1394_isochRx |
 		  OHCI1394_isochTx |
+		  OHCI1394_postedWriteErr |
 		  OHCI1394_cycleInconsistent);
 
 	/* Enable link */
@@ -2374,7 +2382,10 @@
 
 		event &= ~OHCI1394_unrecoverableError;
 	}
-
+	if (event & OHCI1394_postedWriteErr) {
+		PRINT(KERN_ERR, "physical posted write error");
+		/* no recovery strategy yet, had to involve protocol drivers */
+	}
 	if (event & OHCI1394_cycleInconsistent) {
 		/* We subscribe to the cycleInconsistent event only to
 		 * clear the corresponding event bit... otherwise,
@@ -2382,7 +2393,6 @@
 		DBGMSG("OHCI1394_cycleInconsistent");
 		event &= ~OHCI1394_cycleInconsistent;
 	}
-
 	if (event & OHCI1394_busReset) {
 		/* The busReset event bit can't be cleared during the
 		 * selfID phase, so we disable busReset interrupts, to
@@ -2426,7 +2436,6 @@
 		}
 		event &= ~OHCI1394_busReset;
 	}
-
 	if (event & OHCI1394_reqTxComplete) {
 		struct dma_trm_ctx *d = &ohci->at_req_context;
 		DBGMSG("Got reqTxComplete interrupt "
@@ -2514,26 +2523,20 @@
 			reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
 			spin_unlock_irqrestore(&ohci->event_lock, flags);
 
-			/* Accept Physical requests from all nodes. */
-			reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0xffffffff);
-			reg_write(ohci,OHCI1394_AsReqFilterLoSet, 0xffffffff);
-
 			/* Turn on phys dma reception.
 			 *
 			 * TODO: Enable some sort of filtering management.
 			 */
 			if (phys_dma) {
-				reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0xffffffff);
-				reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0xffffffff);
-				reg_write(ohci,OHCI1394_PhyUpperBound, 0xffff0000);
-			} else {
-				reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0x00000000);
-				reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0x00000000);
+				reg_write(ohci, OHCI1394_PhyReqFilterHiSet,
+					  0xffffffff);
+				reg_write(ohci, OHCI1394_PhyReqFilterLoSet,
+					  0xffffffff);
 			}
 
 			DBGMSG("PhyReqFilter=%08x%08x",
-			       reg_read(ohci,OHCI1394_PhyReqFilterHiSet),
-			       reg_read(ohci,OHCI1394_PhyReqFilterLoSet));
+			       reg_read(ohci, OHCI1394_PhyReqFilterHiSet),
+			       reg_read(ohci, OHCI1394_PhyReqFilterLoSet));
 
 			hpsb_selfid_complete(host, phyid, isroot);
 		} else
@@ -3259,8 +3262,8 @@
 	 * fail to report the right length.  Anyway, the ohci spec
 	 * clearly says it's 2kb, so this shouldn't be a problem. */
 	ohci_base = pci_resource_start(dev, 0);
-	if (pci_resource_len(dev, 0) != OHCI1394_REGISTER_SIZE)
-		PRINT(KERN_WARNING, "Unexpected PCI resource length of %lx!",
+	if (pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE)
+		PRINT(KERN_WARNING, "PCI resource length of %lx too small!",
 		      pci_resource_len(dev, 0));
 
 	/* Seems PCMCIA handles this internally. Not sure why. Seems
@@ -3526,7 +3529,7 @@
 static int ohci1394_pci_resume (struct pci_dev *pdev)
 {
 #ifdef CONFIG_PPC_PMAC
-	if (_machine == _MACH_Pmac) {
+	if (machine_is(powermac)) {
 		struct device_node *of_node;
 
 		/* Re-enable 1394 */
@@ -3545,7 +3548,7 @@
 static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 #ifdef CONFIG_PPC_PMAC
-	if (_machine == _MACH_Pmac) {
+	if (machine_is(powermac)) {
 		struct device_node *of_node;
 
 		/* Disable 1394 */
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 19f26c5..f7de546 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -41,7 +41,6 @@
 #include <linux/cdev.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/compat.h>
 
 #include "csr1212.h"
@@ -2999,9 +2998,6 @@
 		goto out_unreg;
 	}
 
-	devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16),
-		      S_IFCHR | S_IRUSR | S_IWUSR, RAW1394_DEVICE_NAME);
-
 	cdev_init(&raw1394_cdev, &raw1394_fops);
 	raw1394_cdev.owner = THIS_MODULE;
 	kobject_set_name(&raw1394_cdev.kobj, RAW1394_DEVICE_NAME);
@@ -3023,7 +3019,6 @@
 	goto out;
 
       out_dev:
-	devfs_remove(RAW1394_DEVICE_NAME);
 	class_device_destroy(hpsb_protocol_class,
 			     MKDEV(IEEE1394_MAJOR,
 				   IEEE1394_MINOR_BLOCK_RAW1394 * 16));
@@ -3039,7 +3034,6 @@
 			     MKDEV(IEEE1394_MAJOR,
 				   IEEE1394_MINOR_BLOCK_RAW1394 * 16));
 	cdev_del(&raw1394_cdev);
-	devfs_remove(RAW1394_DEVICE_NAME);
 	hpsb_unregister_highlevel(&raw1394_highlevel);
 	hpsb_unregister_protocol(&raw1394_driver);
 }
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index eca92eb..2c765ca 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -214,6 +214,7 @@
 #endif
 
 #define SBP2_ERR(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
+#define SBP2_DEBUG_ENTER()		SBP2_DEBUG("%s", __FUNCTION__)
 
 /*
  * Globals
@@ -535,7 +536,7 @@
 		command->Current_SCpnt = Current_SCpnt;
 		list_add_tail(&command->list, &scsi_id->sbp2_command_orb_inuse);
 	} else {
-		SBP2_ERR("sbp2util_allocate_command_orb - No orbs available!");
+		SBP2_ERR("%s: no orbs available", __FUNCTION__);
 	}
 	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 	return command;
@@ -549,7 +550,7 @@
 	struct hpsb_host *host;
 
 	if (!scsi_id) {
-		printk(KERN_ERR "%s: scsi_id == NULL\n", __FUNCTION__);
+		SBP2_ERR("%s: scsi_id == NULL", __FUNCTION__);
 		return;
 	}
 
@@ -610,7 +611,7 @@
 	struct unit_directory *ud;
 	struct scsi_id_instance_data *scsi_id;
 
-	SBP2_DEBUG("sbp2_probe");
+	SBP2_DEBUG_ENTER();
 
 	ud = container_of(dev, struct unit_directory, device);
 
@@ -635,7 +636,7 @@
 	struct scsi_id_instance_data *scsi_id;
 	struct scsi_device *sdev;
 
-	SBP2_DEBUG("sbp2_remove");
+	SBP2_DEBUG_ENTER();
 
 	ud = container_of(dev, struct unit_directory, device);
 	scsi_id = ud->device.driver_data;
@@ -667,7 +668,7 @@
 {
 	struct scsi_id_instance_data *scsi_id = ud->device.driver_data;
 
-	SBP2_DEBUG("sbp2_update");
+	SBP2_DEBUG_ENTER();
 
 	if (sbp2_reconnect_device(scsi_id)) {
 
@@ -715,7 +716,7 @@
 	struct Scsi_Host *scsi_host = NULL;
 	struct scsi_id_instance_data *scsi_id = NULL;
 
-	SBP2_DEBUG("sbp2_alloc_device");
+	SBP2_DEBUG_ENTER();
 
 	scsi_id = kzalloc(sizeof(*scsi_id), GFP_KERNEL);
 	if (!scsi_id) {
@@ -749,12 +750,22 @@
 
 #ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
 		/* Handle data movement if physical dma is not
-		 * enabled/supportedon host controller */
-		hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host, &sbp2_physdma_ops,
-					0x0ULL, 0xfffffffcULL);
+		 * enabled or not supported on host controller */
+		if (!hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host,
+					     &sbp2_physdma_ops,
+					     0x0ULL, 0xfffffffcULL)) {
+			SBP2_ERR("failed to register lower 4GB address range");
+			goto failed_alloc;
+		}
 #endif
 	}
 
+	/* Prevent unloading of the 1394 host */
+	if (!try_module_get(hi->host->driver->owner)) {
+		SBP2_ERR("failed to get a reference on 1394 host driver");
+		goto failed_alloc;
+	}
+
 	scsi_id->hi = hi;
 
 	list_add_tail(&scsi_id->scsi_list, &hi->scsi_ids);
@@ -816,7 +827,7 @@
 	struct sbp2scsi_host_info *hi = scsi_id->hi;
 	int error;
 
-	SBP2_DEBUG("sbp2_start_device");
+	SBP2_DEBUG_ENTER();
 
 	/* Login FIFO DMA */
 	scsi_id->login_response =
@@ -891,7 +902,6 @@
 	 * allows someone else to login instead. One second makes sense. */
 	msleep_interruptible(1000);
 	if (signal_pending(current)) {
-		SBP2_WARN("aborting sbp2_start_device due to event");
 		sbp2_remove_device(scsi_id);
 		return -EINTR;
 	}
@@ -944,7 +954,7 @@
 {
 	struct sbp2scsi_host_info *hi;
 
-	SBP2_DEBUG("sbp2_remove_device");
+	SBP2_DEBUG_ENTER();
 
 	if (!scsi_id)
 		return;
@@ -1015,6 +1025,9 @@
 
 	scsi_id->ud->device.driver_data = NULL;
 
+	if (hi)
+		module_put(hi->host->driver->owner);
+
 	SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->ud->id);
 
 	kfree(scsi_id);
@@ -1073,23 +1086,20 @@
 	int max_logins;
 	int active_logins;
 
-	SBP2_DEBUG("sbp2_query_logins");
+	SBP2_DEBUG_ENTER();
 
 	scsi_id->query_logins_orb->reserved1 = 0x0;
 	scsi_id->query_logins_orb->reserved2 = 0x0;
 
 	scsi_id->query_logins_orb->query_response_lo = scsi_id->query_logins_response_dma;
 	scsi_id->query_logins_orb->query_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
-	SBP2_DEBUG("sbp2_query_logins: query_response_hi/lo initialized");
 
 	scsi_id->query_logins_orb->lun_misc = ORB_SET_FUNCTION(SBP2_QUERY_LOGINS_REQUEST);
 	scsi_id->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1);
 	scsi_id->query_logins_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_lun);
-	SBP2_DEBUG("sbp2_query_logins: lun_misc initialized");
 
 	scsi_id->query_logins_orb->reserved_resp_length =
 		ORB_SET_QUERY_LOGINS_RESP_LENGTH(sizeof(struct sbp2_query_logins_response));
-	SBP2_DEBUG("sbp2_query_logins: reserved_resp_length initialized");
 
 	scsi_id->query_logins_orb->status_fifo_hi =
 		ORB_SET_STATUS_FIFO_HI(scsi_id->status_fifo_addr, hi->host->node_id);
@@ -1098,25 +1108,19 @@
 
 	sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb));
 
-	SBP2_DEBUG("sbp2_query_logins: orb byte-swapped");
-
 	sbp2util_packet_dump(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb),
 			     "sbp2 query logins orb", scsi_id->query_logins_orb_dma);
 
 	memset(scsi_id->query_logins_response, 0, sizeof(struct sbp2_query_logins_response));
 	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
 
-	SBP2_DEBUG("sbp2_query_logins: query_logins_response/status FIFO memset");
-
 	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
 	data[1] = scsi_id->query_logins_orb_dma;
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
 	atomic_set(&scsi_id->sbp2_login_complete, 0);
 
-	SBP2_DEBUG("sbp2_query_logins: prepared to write");
 	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
-	SBP2_DEBUG("sbp2_query_logins: written");
 
 	if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 2*HZ)) {
 		SBP2_INFO("Error querying logins to SBP-2 device - timed out");
@@ -1165,10 +1169,10 @@
 	struct sbp2scsi_host_info *hi = scsi_id->hi;
 	quadlet_t data[2];
 
-	SBP2_DEBUG("sbp2_login_device");
+	SBP2_DEBUG_ENTER();
 
 	if (!scsi_id->login_orb) {
-		SBP2_DEBUG("sbp2_login_device: login_orb not alloc'd!");
+		SBP2_DEBUG("%s: login_orb not alloc'd!", __FUNCTION__);
 		return -EIO;
 	}
 
@@ -1182,59 +1186,39 @@
 	/* Set-up login ORB, assume no password */
 	scsi_id->login_orb->password_hi = 0;
 	scsi_id->login_orb->password_lo = 0;
-	SBP2_DEBUG("sbp2_login_device: password_hi/lo initialized");
 
 	scsi_id->login_orb->login_response_lo = scsi_id->login_response_dma;
 	scsi_id->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
-	SBP2_DEBUG("sbp2_login_device: login_response_hi/lo initialized");
 
 	scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(SBP2_LOGIN_REQUEST);
 	scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0);	/* One second reconnect time */
 	scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(exclusive_login);	/* Exclusive access to device */
 	scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1);	/* Notify us of login complete */
 	scsi_id->login_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_lun);
-	SBP2_DEBUG("sbp2_login_device: lun_misc initialized");
 
 	scsi_id->login_orb->passwd_resp_lengths =
 		ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));
-	SBP2_DEBUG("sbp2_login_device: passwd_resp_lengths initialized");
 
 	scsi_id->login_orb->status_fifo_hi =
 		ORB_SET_STATUS_FIFO_HI(scsi_id->status_fifo_addr, hi->host->node_id);
 	scsi_id->login_orb->status_fifo_lo =
 		ORB_SET_STATUS_FIFO_LO(scsi_id->status_fifo_addr);
 
-	/*
-	 * Byte swap ORB if necessary
-	 */
 	sbp2util_cpu_to_be32_buffer(scsi_id->login_orb, sizeof(struct sbp2_login_orb));
 
-	SBP2_DEBUG("sbp2_login_device: orb byte-swapped");
-
 	sbp2util_packet_dump(scsi_id->login_orb, sizeof(struct sbp2_login_orb),
 			     "sbp2 login orb", scsi_id->login_orb_dma);
 
-	/*
-	 * Initialize login response and status fifo
-	 */
 	memset(scsi_id->login_response, 0, sizeof(struct sbp2_login_response));
 	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
 
-	SBP2_DEBUG("sbp2_login_device: login_response/status FIFO memset");
-
-	/*
-	 * Ok, let's write to the target's management agent register
-	 */
 	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
 	data[1] = scsi_id->login_orb_dma;
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
 	atomic_set(&scsi_id->sbp2_login_complete, 0);
 
-	SBP2_DEBUG("sbp2_login_device: prepared to write to %08x",
-		   (unsigned int)scsi_id->sbp2_management_agent_addr);
 	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
-	SBP2_DEBUG("sbp2_login_device: written");
 
 	/*
 	 * Wait for login status (up to 20 seconds)...
@@ -1298,7 +1282,7 @@
 	quadlet_t data[2];
 	int error;
 
-	SBP2_DEBUG("sbp2_logout_device");
+	SBP2_DEBUG_ENTER();
 
 	/*
 	 * Set-up logout ORB
@@ -1362,7 +1346,7 @@
 	quadlet_t data[2];
 	int error;
 
-	SBP2_DEBUG("sbp2_reconnect_device");
+	SBP2_DEBUG_ENTER();
 
 	/*
 	 * Set-up reconnect ORB
@@ -1453,17 +1437,11 @@
 {
 	quadlet_t data;
 
-	SBP2_DEBUG("sbp2_set_busy_timeout");
+	SBP2_DEBUG_ENTER();
 
-	/*
-	 * Ok, let's write to the target's busy timeout register
-	 */
 	data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE);
-
-	if (hpsb_node_write(scsi_id->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) {
-		SBP2_ERR("sbp2_set_busy_timeout error");
-	}
-
+	if (hpsb_node_write(scsi_id->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4))
+		SBP2_ERR("%s error", __FUNCTION__);
 	return 0;
 }
 
@@ -1482,7 +1460,7 @@
 	    firmware_revision, workarounds;
 	int i;
 
-	SBP2_DEBUG("sbp2_parse_unit_directory");
+	SBP2_DEBUG_ENTER();
 
 	management_agent_addr = 0x0;
 	command_set_spec_id = 0x0;
@@ -1615,7 +1593,7 @@
 {
 	struct sbp2scsi_host_info *hi = scsi_id->hi;
 
-	SBP2_DEBUG("sbp2_max_speed_and_size");
+	SBP2_DEBUG_ENTER();
 
 	/* Initial setting comes from the hosts speed map */
 	scsi_id->speed_code =
@@ -1652,11 +1630,8 @@
 	u64 addr;
 	int retval;
 
-	SBP2_DEBUG("sbp2_agent_reset");
+	SBP2_DEBUG_ENTER();
 
-	/*
-	 * Ok, let's write to the target's management agent register
-	 */
 	data = ntohl(SBP2_AGENT_RESET_DATA);
 	addr = scsi_id->sbp2_command_block_agent_addr + SBP2_AGENT_RESET_OFFSET;
 
@@ -2004,11 +1979,7 @@
 	unsigned int request_bufflen = SCpnt->request_bufflen;
 	struct sbp2_command_info *command;
 
-	SBP2_DEBUG("sbp2_send_command");
-#if (CONFIG_IEEE1394_SBP2_DEBUG >= 2) || defined(CONFIG_IEEE1394_SBP2_PACKET_DUMP)
-	printk("[scsi command]\n   ");
-	scsi_print_command(SCpnt);
-#endif
+	SBP2_DEBUG_ENTER();
 	SBP2_DEBUG("SCSI transfer size = %x", request_bufflen);
 	SBP2_DEBUG("SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg);
 
@@ -2048,7 +2019,7 @@
  */
 static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data)
 {
-	SBP2_DEBUG("sbp2_status_to_sense_data");
+	SBP2_DEBUG_ENTER();
 
 	/*
 	 * Ok, it's pretty ugly...   ;-)
@@ -2082,7 +2053,7 @@
 {
 	u8 *scsi_buf = SCpnt->request_buffer;
 
-	SBP2_DEBUG("sbp2_check_sbp2_response");
+	SBP2_DEBUG_ENTER();
 
 	if (SCpnt->cmnd[0] == INQUIRY && (SCpnt->cmnd[1] & 3) == 0) {
 		/*
@@ -2113,7 +2084,7 @@
 	struct sbp2_command_info *command;
 	unsigned long flags;
 
-	SBP2_DEBUG("sbp2_handle_status_write");
+	SBP2_DEBUG_ENTER();
 
 	sbp2util_packet_dump(data, length, "sbp2 status write by device", (u32)addr);
 
@@ -2260,7 +2231,10 @@
 	struct sbp2scsi_host_info *hi;
 	int result = DID_NO_CONNECT << 16;
 
-	SBP2_DEBUG("sbp2scsi_queuecommand");
+	SBP2_DEBUG_ENTER();
+#if (CONFIG_IEEE1394_SBP2_DEBUG >= 2) || defined(CONFIG_IEEE1394_SBP2_PACKET_DUMP)
+	scsi_print_command(SCpnt);
+#endif
 
 	if (!sbp2util_node_is_available(scsi_id))
 		goto done;
@@ -2338,7 +2312,7 @@
 	struct sbp2_command_info *command;
 	unsigned long flags;
 
-	SBP2_DEBUG("sbp2scsi_complete_all_commands");
+	SBP2_DEBUG_ENTER();
 
 	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
 	while (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
@@ -2371,7 +2345,7 @@
 				      u32 scsi_status, struct scsi_cmnd *SCpnt,
 				      void (*done)(struct scsi_cmnd *))
 {
-	SBP2_DEBUG("sbp2scsi_complete_command");
+	SBP2_DEBUG_ENTER();
 
 	/*
 	 * Sanity
@@ -2397,7 +2371,7 @@
 	 */
 	switch (scsi_status) {
 	case SBP2_SCSI_STATUS_GOOD:
-		SCpnt->result = DID_OK;
+		SCpnt->result = DID_OK << 16;
 		break;
 
 	case SBP2_SCSI_STATUS_BUSY:
@@ -2407,16 +2381,11 @@
 
 	case SBP2_SCSI_STATUS_CHECK_CONDITION:
 		SBP2_DEBUG("SBP2_SCSI_STATUS_CHECK_CONDITION");
-		SCpnt->result = CHECK_CONDITION << 1;
-
-		/*
-		 * Debug stuff
-		 */
+		SCpnt->result = CHECK_CONDITION << 1 | DID_OK << 16;
 #if CONFIG_IEEE1394_SBP2_DEBUG >= 1
 		scsi_print_command(SCpnt);
-		scsi_print_sense("bh", SCpnt);
+		scsi_print_sense(SBP2_DEVICE_NAME, SCpnt);
 #endif
-
 		break;
 
 	case SBP2_SCSI_STATUS_SELECTION_TIMEOUT:
@@ -2441,7 +2410,7 @@
 	/*
 	 * Take care of any sbp2 response data mucking here (RBC stuff, etc.)
 	 */
-	if (SCpnt->result == DID_OK) {
+	if (SCpnt->result == DID_OK << 16) {
 		sbp2_check_sbp2_response(scsi_id, SCpnt);
 	}
 
@@ -2459,6 +2428,8 @@
 	 * If a unit attention occurs, return busy status so it gets
 	 * retried... it could have happened because of a 1394 bus reset
 	 * or hot-plug...
+	 * XXX  DID_BUS_BUSY is actually a bad idea because it will defy
+	 * the scsi layer's retry logic.
 	 */
 #if 0
 	if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) &&
@@ -2624,7 +2595,7 @@
 {
 	int ret;
 
-	SBP2_DEBUG("sbp2_module_init");
+	SBP2_DEBUG_ENTER();
 
 	/* Module load debug option to force one command at a time (serializing I/O) */
 	if (serialize_io) {
@@ -2652,7 +2623,7 @@
 
 static void __exit sbp2_module_exit(void)
 {
-	SBP2_DEBUG("sbp2_module_exit");
+	SBP2_DEBUG_ENTER();
 
 	hpsb_unregister_protocol(&sbp2_driver);
 
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index 216dbbf..4e3bd62 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -42,7 +42,6 @@
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
 #include <linux/delay.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/vmalloc.h>
@@ -1322,9 +1321,6 @@
 	class_device_create(hpsb_protocol_class, NULL, MKDEV(
 		IEEE1394_MAJOR,	minor), 
 		NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
-	devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, minor),
-		       S_IFCHR | S_IRUSR | S_IWUSR,
-		       "%s/%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
 }
 
 
@@ -1332,12 +1328,9 @@
 {
 	struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host);
 
-	if (ohci) {
+	if (ohci)
 		class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
 			IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id));
-		devfs_remove("%s/%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
-	}
-	
 	return;
 }
 
@@ -1478,12 +1471,8 @@
 static void __exit video1394_exit_module (void)
 {
 	hpsb_unregister_protocol(&video1394_driver);
-
 	hpsb_unregister_highlevel(&video1394_highlevel);
-
-	devfs_remove(VIDEO1394_DRIVER_NAME);
 	cdev_del(&video1394_cdev);
-
 	PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
 }
 
@@ -1500,15 +1489,12 @@
 		return ret;
         }
 
-	devfs_mk_dir(VIDEO1394_DRIVER_NAME);
-
 	hpsb_register_highlevel(&video1394_highlevel);
 
 	ret = hpsb_register_protocol(&video1394_driver);
 	if (ret) {
 		PRINT_G(KERN_ERR, "video1394: failed to register protocol");
 		hpsb_unregister_highlevel(&video1394_highlevel);
-		devfs_remove(VIDEO1394_DRIVER_NAME);
 		cdev_del(&video1394_cdev);
 		return ret;
 	}
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index f7854b6..ba54c85 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -227,6 +227,14 @@
 			if (!is_vendor_oui(mad_reg_req->oui))
 				goto error1;
 		}
+		/* Make sure class supplied is consistent with RMPP */
+		if (ib_is_mad_class_rmpp(mad_reg_req->mgmt_class)) {
+			if (!rmpp_version)
+				goto error1;
+		} else {
+			if (rmpp_version)
+				goto error1;
+		}
 		/* Make sure class supplied is consistent with QP type */
 		if (qp_type == IB_QPT_SMI) {
 			if ((mad_reg_req->mgmt_class !=
@@ -890,6 +898,35 @@
 }
 EXPORT_SYMBOL(ib_create_send_mad);
 
+int ib_get_mad_data_offset(u8 mgmt_class)
+{
+	if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
+		return IB_MGMT_SA_HDR;
+	else if ((mgmt_class == IB_MGMT_CLASS_DEVICE_MGMT) ||
+		 (mgmt_class == IB_MGMT_CLASS_DEVICE_ADM) ||
+		 (mgmt_class == IB_MGMT_CLASS_BIS))
+		return IB_MGMT_DEVICE_HDR;
+	else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
+		 (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
+		return IB_MGMT_VENDOR_HDR;
+	else
+		return IB_MGMT_MAD_HDR;
+}
+EXPORT_SYMBOL(ib_get_mad_data_offset);
+
+int ib_is_mad_class_rmpp(u8 mgmt_class)
+{
+	if ((mgmt_class == IB_MGMT_CLASS_SUBN_ADM) ||
+	    (mgmt_class == IB_MGMT_CLASS_DEVICE_MGMT) ||
+	    (mgmt_class == IB_MGMT_CLASS_DEVICE_ADM) ||
+	    (mgmt_class == IB_MGMT_CLASS_BIS) ||
+	    ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
+	     (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)))
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(ib_is_mad_class_rmpp);
+
 void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num)
 {
 	struct ib_mad_send_wr_private *mad_send_wr;
@@ -1022,6 +1059,13 @@
 			goto error;
 		}
 
+		if (!ib_is_mad_class_rmpp(((struct ib_mad_hdr *) send_buf->mad)->mgmt_class)) {
+			if (mad_agent_priv->agent.rmpp_version) {
+				ret = -EINVAL;
+				goto error;
+			}
+		}
+
 		/*
 		 * Save pointer to next work request to post in case the
 		 * current one completes, and the user modifies the work
@@ -1618,14 +1662,59 @@
 		(rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA);
 }
 
+static inline int rcv_has_same_class(struct ib_mad_send_wr_private *wr,
+				     struct ib_mad_recv_wc *rwc)
+{
+	return ((struct ib_mad *)(wr->send_buf.mad))->mad_hdr.mgmt_class ==
+		rwc->recv_buf.mad->mad_hdr.mgmt_class;
+}
+
+static inline int rcv_has_same_gid(struct ib_mad_send_wr_private *wr,
+				   struct ib_mad_recv_wc *rwc )
+{
+	struct ib_ah_attr attr;
+	u8 send_resp, rcv_resp;
+
+	send_resp = ((struct ib_mad *)(wr->send_buf.mad))->
+		     mad_hdr.method & IB_MGMT_METHOD_RESP;
+	rcv_resp = rwc->recv_buf.mad->mad_hdr.method & IB_MGMT_METHOD_RESP;
+
+	if (!send_resp && rcv_resp)
+		/* is request/response. GID/LIDs are both local (same). */
+		return 1;
+
+	if (send_resp == rcv_resp)
+		/* both requests, or both responses. GIDs different */
+		return 0;
+
+	if (ib_query_ah(wr->send_buf.ah, &attr))
+		/* Assume not equal, to avoid false positives. */
+		return 0;
+
+	if (!(attr.ah_flags & IB_AH_GRH) && !(rwc->wc->wc_flags & IB_WC_GRH))
+		return attr.dlid == rwc->wc->slid;
+	else if ((attr.ah_flags & IB_AH_GRH) &&
+		 (rwc->wc->wc_flags & IB_WC_GRH))
+		return memcmp(attr.grh.dgid.raw,
+			      rwc->recv_buf.grh->sgid.raw, 16) == 0;
+	else
+		/* one has GID, other does not.  Assume different */
+		return 0;
+}
 struct ib_mad_send_wr_private*
-ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid)
+ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv,
+		 struct ib_mad_recv_wc *mad_recv_wc)
 {
 	struct ib_mad_send_wr_private *mad_send_wr;
+	struct ib_mad *mad;
+
+	mad = (struct ib_mad *)mad_recv_wc->recv_buf.mad;
 
 	list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list,
 			    agent_list) {
-		if (mad_send_wr->tid == tid)
+		if ((mad_send_wr->tid == mad->mad_hdr.tid) &&
+		    rcv_has_same_class(mad_send_wr, mad_recv_wc) &&
+		    rcv_has_same_gid(mad_send_wr, mad_recv_wc))
 			return mad_send_wr;
 	}
 
@@ -1636,7 +1725,10 @@
 	list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list,
 			    agent_list) {
 		if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) &&
-		    mad_send_wr->tid == tid && mad_send_wr->timeout) {
+		    mad_send_wr->tid == mad->mad_hdr.tid &&
+		    mad_send_wr->timeout &&
+		    rcv_has_same_class(mad_send_wr, mad_recv_wc) &&
+		    rcv_has_same_gid(mad_send_wr, mad_recv_wc)) {
 			/* Verify request has not been canceled */
 			return (mad_send_wr->status == IB_WC_SUCCESS) ?
 				mad_send_wr : NULL;
@@ -1661,7 +1753,6 @@
 	struct ib_mad_send_wr_private *mad_send_wr;
 	struct ib_mad_send_wc mad_send_wc;
 	unsigned long flags;
-	__be64 tid;
 
 	INIT_LIST_HEAD(&mad_recv_wc->rmpp_list);
 	list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list);
@@ -1677,9 +1768,8 @@
 
 	/* Complete corresponding request */
 	if (response_mad(mad_recv_wc->recv_buf.mad)) {
-		tid = mad_recv_wc->recv_buf.mad->mad_hdr.tid;
 		spin_lock_irqsave(&mad_agent_priv->lock, flags);
-		mad_send_wr = ib_find_send_mad(mad_agent_priv, tid);
+		mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc);
 		if (!mad_send_wr) {
 			spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
 			ib_free_recv_mad(mad_recv_wc);
@@ -2408,11 +2498,11 @@
 			}
 		}
 		sg_list.addr = dma_map_single(qp_info->port_priv->
-						device->dma_device,
-					&mad_priv->grh,
-					sizeof *mad_priv -
-						sizeof mad_priv->header,
-					DMA_FROM_DEVICE);
+					      	device->dma_device,
+					      &mad_priv->grh,
+					      sizeof *mad_priv -
+					      	sizeof mad_priv->header,
+					      DMA_FROM_DEVICE);
 		pci_unmap_addr_set(&mad_priv->header, mapping, sg_list.addr);
 		recv_wr.wr_id = (unsigned long)&mad_priv->header.mad_list;
 		mad_priv->header.mad_list.mad_queue = recv_queue;
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
index a7125d4..6c9c133 100644
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -216,7 +216,8 @@
 int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr);
 
 struct ib_mad_send_wr_private *
-ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid);
+ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv,
+		 struct ib_mad_recv_wc *mad_recv_wc);
 
 void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr,
 			     struct ib_mad_send_wc *mad_send_wc);
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c
index bacfdd5..dfd4e58 100644
--- a/drivers/infiniband/core/mad_rmpp.c
+++ b/drivers/infiniband/core/mad_rmpp.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 Intel Inc. All rights reserved.
- * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005-2006 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -100,17 +100,6 @@
 	}
 }
 
-static int data_offset(u8 mgmt_class)
-{
-	if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
-		return IB_MGMT_SA_HDR;
-	else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
-		 (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
-		return IB_MGMT_VENDOR_HDR;
-	else
-		return IB_MGMT_RMPP_HDR;
-}
-
 static void format_ack(struct ib_mad_send_buf *msg,
 		       struct ib_rmpp_mad *data,
 		       struct mad_rmpp_recv *rmpp_recv)
@@ -137,7 +126,7 @@
 	struct ib_mad_send_buf *msg;
 	int ret, hdr_len;
 
-	hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
+	hdr_len = ib_get_mad_data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
 	msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp,
 				 recv_wc->wc->pkey_index, 1, hdr_len,
 				 0, GFP_KERNEL);
@@ -163,7 +152,7 @@
 	if (IS_ERR(ah))
 		return (void *) ah;
 
-	hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
+	hdr_len = ib_get_mad_data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
 	msg = ib_create_send_mad(agent, recv_wc->wc->src_qp,
 				 recv_wc->wc->pkey_index, 1,
 				 hdr_len, 0, GFP_KERNEL);
@@ -408,7 +397,7 @@
 
 	rmpp_mad = (struct ib_rmpp_mad *)rmpp_recv->cur_seg_buf->mad;
 
-	hdr_size = data_offset(rmpp_mad->mad_hdr.mgmt_class);
+	hdr_size = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class);
 	data_size = sizeof(struct ib_rmpp_mad) - hdr_size;
 	pad = IB_MGMT_RMPP_DATA - be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
 	if (pad > IB_MGMT_RMPP_DATA || pad < 0)
@@ -562,15 +551,15 @@
 	return ib_send_mad(mad_send_wr);
 }
 
-static void abort_send(struct ib_mad_agent_private *agent, __be64 tid,
-		       u8 rmpp_status)
+static void abort_send(struct ib_mad_agent_private *agent,
+		       struct ib_mad_recv_wc *mad_recv_wc, u8 rmpp_status)
 {
 	struct ib_mad_send_wr_private *mad_send_wr;
 	struct ib_mad_send_wc wc;
 	unsigned long flags;
 
 	spin_lock_irqsave(&agent->lock, flags);
-	mad_send_wr = ib_find_send_mad(agent, tid);
+	mad_send_wr = ib_find_send_mad(agent, mad_recv_wc);
 	if (!mad_send_wr)
 		goto out;	/* Unmatched send */
 
@@ -612,8 +601,7 @@
 
 	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
 	if (rmpp_mad->rmpp_hdr.rmpp_status) {
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_BAD_STATUS);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 		return;
 	}
@@ -621,14 +609,13 @@
 	seg_num = be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num);
 	newwin = be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
 	if (newwin < seg_num) {
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_W2S);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S);
 		return;
 	}
 
 	spin_lock_irqsave(&agent->lock, flags);
-	mad_send_wr = ib_find_send_mad(agent, rmpp_mad->mad_hdr.tid);
+	mad_send_wr = ib_find_send_mad(agent, mad_recv_wc);
 	if (!mad_send_wr)
 		goto out;	/* Unmatched ACK */
 
@@ -639,8 +626,7 @@
 	if (seg_num > mad_send_wr->send_buf.seg_count ||
 	    seg_num > mad_send_wr->newwin) {
 		spin_unlock_irqrestore(&agent->lock, flags);
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_S2B);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B);
 		return;
 	}
@@ -728,12 +714,10 @@
 	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
 
 	if (rmpp_mad->rmpp_hdr.rmpp_status != IB_MGMT_RMPP_STATUS_RESX) {
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_BAD_STATUS);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 	} else
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   rmpp_mad->rmpp_hdr.rmpp_status);
+		abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status);
 }
 
 static void process_rmpp_abort(struct ib_mad_agent_private *agent,
@@ -745,12 +729,10 @@
 
 	if (rmpp_mad->rmpp_hdr.rmpp_status < IB_MGMT_RMPP_STATUS_ABORT_MIN ||
 	    rmpp_mad->rmpp_hdr.rmpp_status > IB_MGMT_RMPP_STATUS_ABORT_MAX) {
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_BAD_STATUS);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 	} else
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   rmpp_mad->rmpp_hdr.rmpp_status);
+		abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status);
 }
 
 struct ib_mad_recv_wc *
@@ -764,8 +746,7 @@
 		return mad_recv_wc;
 
 	if (rmpp_mad->rmpp_hdr.rmpp_version != IB_MGMT_RMPP_VERSION) {
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_UNV);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV);
 		goto out;
 	}
@@ -783,8 +764,7 @@
 		process_rmpp_abort(agent, mad_recv_wc);
 		break;
 	default:
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_BADT);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT);
 		break;
 	}
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index fb6cd42..afe70a5 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -177,17 +177,6 @@
 	return ret;
 }
 
-static int data_offset(u8 mgmt_class)
-{
-	if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
-		return IB_MGMT_SA_HDR;
-	else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
-		 (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
-		return IB_MGMT_VENDOR_HDR;
-	else
-		return IB_MGMT_RMPP_HDR;
-}
-
 static void send_handler(struct ib_mad_agent *agent,
 			 struct ib_mad_send_wc *send_wc)
 {
@@ -283,7 +272,7 @@
 			 */
 			return -ENOSPC;
 		}
-		offset = data_offset(recv_buf->mad->mad_hdr.mgmt_class);
+		offset = ib_get_mad_data_offset(recv_buf->mad->mad_hdr.mgmt_class);
 		max_seg_payload = sizeof (struct ib_mad) - offset;
 
 		for (left = packet->length - seg_payload, buf += seg_payload;
@@ -441,21 +430,14 @@
 	}
 
 	rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data;
-	if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) {
-		hdr_len = IB_MGMT_SA_HDR;
-		copy_offset = IB_MGMT_RMPP_HDR;
-		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
-			      IB_MGMT_RMPP_FLAG_ACTIVE;
-	} else if (rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START &&
-		   rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END) {
-		hdr_len = IB_MGMT_VENDOR_HDR;
-		copy_offset = IB_MGMT_RMPP_HDR;
-		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
-			      IB_MGMT_RMPP_FLAG_ACTIVE;
-	} else {
-		hdr_len = IB_MGMT_MAD_HDR;
+	hdr_len = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class);
+	if (!ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class)) {
 		copy_offset = IB_MGMT_MAD_HDR;
 		rmpp_active = 0;
+	} else {
+		copy_offset = IB_MGMT_RMPP_HDR;
+		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
+			      IB_MGMT_RMPP_FLAG_ACTIVE;
 	}
 
 	data_len = count - sizeof (struct ib_user_mad) - hdr_len;
diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c
index f023d39..bc5bdcb 100644
--- a/drivers/infiniband/hw/mthca/mthca_av.c
+++ b/drivers/infiniband/hw/mthca/mthca_av.c
@@ -265,7 +265,7 @@
 	return -ENOMEM;
 }
 
-void __devexit mthca_cleanup_av_table(struct mthca_dev *dev)
+void mthca_cleanup_av_table(struct mthca_dev *dev)
 {
 	if (mthca_is_memfree(dev))
 		return;
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 76aabc5..312cf90 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -973,7 +973,7 @@
 	return err;
 }
 
-void __devexit mthca_cleanup_cq_table(struct mthca_dev *dev)
+void mthca_cleanup_cq_table(struct mthca_dev *dev)
 {
 	mthca_array_cleanup(&dev->cq_table.cq, dev->limits.num_cqs);
 	mthca_alloc_cleanup(&dev->cq_table.alloc);
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index cbdc348..99f109c 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -765,7 +765,7 @@
 
 }
 
-static void __devexit mthca_unmap_eq_regs(struct mthca_dev *dev)
+static void mthca_unmap_eq_regs(struct mthca_dev *dev)
 {
 	if (mthca_is_memfree(dev)) {
 		mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
@@ -821,7 +821,7 @@
 	return ret;
 }
 
-void __devexit mthca_unmap_eq_icm(struct mthca_dev *dev)
+void mthca_unmap_eq_icm(struct mthca_dev *dev)
 {
 	u8 status;
 
@@ -954,7 +954,7 @@
 	return err;
 }
 
-void __devexit mthca_cleanup_eq_table(struct mthca_dev *dev)
+void mthca_cleanup_eq_table(struct mthca_dev *dev)
 {
 	u8 status;
 	int i;
diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c
index 4ace6a3..dfb482e 100644
--- a/drivers/infiniband/hw/mthca/mthca_mad.c
+++ b/drivers/infiniband/hw/mthca/mthca_mad.c
@@ -271,7 +271,7 @@
 	return PTR_ERR(agent);
 }
 
-void mthca_free_agents(struct mthca_dev *dev)
+void __devexit mthca_free_agents(struct mthca_dev *dev)
 {
 	struct ib_mad_agent *agent;
 	int p, q;
diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c
index 9965bda..47ca8a9 100644
--- a/drivers/infiniband/hw/mthca/mthca_mcg.c
+++ b/drivers/infiniband/hw/mthca/mthca_mcg.c
@@ -388,7 +388,7 @@
 	return 0;
 }
 
-void __devexit mthca_cleanup_mcg_table(struct mthca_dev *dev)
+void mthca_cleanup_mcg_table(struct mthca_dev *dev)
 {
 	mthca_alloc_cleanup(&dev->mcg_table.alloc);
 }
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index 698b621..25e1c1d 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -170,7 +170,7 @@
 	return -ENOMEM;
 }
 
-static void __devexit mthca_buddy_cleanup(struct mthca_buddy *buddy)
+static void mthca_buddy_cleanup(struct mthca_buddy *buddy)
 {
 	int i;
 
@@ -866,7 +866,7 @@
 	return err;
 }
 
-void __devexit mthca_cleanup_mr_table(struct mthca_dev *dev)
+void mthca_cleanup_mr_table(struct mthca_dev *dev)
 {
 	/* XXX check if any MRs are still allocated? */
 	if (dev->limits.fmr_reserved_mtts)
diff --git a/drivers/infiniband/hw/mthca/mthca_pd.c b/drivers/infiniband/hw/mthca/mthca_pd.c
index 105fc5f..59df516 100644
--- a/drivers/infiniband/hw/mthca/mthca_pd.c
+++ b/drivers/infiniband/hw/mthca/mthca_pd.c
@@ -77,7 +77,7 @@
 				dev->limits.reserved_pds);
 }
 
-void __devexit mthca_cleanup_pd_table(struct mthca_dev *dev)
+void mthca_cleanup_pd_table(struct mthca_dev *dev)
 {
 	/* XXX check if any PDs are still allocated? */
 	mthca_alloc_cleanup(&dev->pd_table.alloc);
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 1bc2678..057c8e6 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -2204,7 +2204,7 @@
 	return err;
 }
 
-void __devexit mthca_cleanup_qp_table(struct mthca_dev *dev)
+void mthca_cleanup_qp_table(struct mthca_dev *dev)
 {
 	int i;
 	u8 status;
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index 0cfd158..2dd3aea 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -206,7 +206,7 @@
 		 roundup_pow_of_two(sizeof (struct mthca_next_seg) +
 				    srq->max_gs * sizeof (struct mthca_data_seg)));
 
-	if (ds > dev->limits.max_desc_sz)
+	if (!mthca_is_memfree(dev) && (ds > dev->limits.max_desc_sz))
 		return -EINVAL;
 
 	srq->wqe_shift = long_log2(ds);
@@ -684,7 +684,7 @@
 	return err;
 }
 
-void __devexit mthca_cleanup_srq_table(struct mthca_dev *dev)
+void mthca_cleanup_srq_table(struct mthca_dev *dev)
 {
 	if (!(dev->mthca_flags & MTHCA_FLAG_SRQ))
 		return;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 53a32f6..9b0bd7c 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -723,7 +723,7 @@
 	 * destination address onto the front of the skb so we can
 	 * figure out where to send the packet later.
 	 */
-	if (!skb->dst || !skb->dst->neighbour) {
+	if ((!skb->dst || !skb->dst->neighbour) && daddr) {
 		struct ipoib_pseudoheader *phdr =
 			(struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr);
 		memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 61924cc..fd8a95a 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -607,10 +607,10 @@
 	 */
 	if (likely(scmnd->use_sg)) {
 		nents = scmnd->use_sg;
-		scat  = (struct scatterlist *) scmnd->request_buffer;
+		scat  = scmnd->request_buffer;
 	} else {
 		nents = 1;
-		scat  = (struct scatterlist *) scmnd->request_buffer;
+		scat  = &req->fake_sg;
 	}
 
 	dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents,
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 4fe3da3..f8af094 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -923,7 +923,7 @@
 static int input_open_file(struct inode *inode, struct file *file)
 {
 	struct input_handler *handler = input_table[iminor(inode) >> 5];
-	struct file_operations *old_fops, *new_fops = NULL;
+	const struct file_operations *old_fops, *new_fops = NULL;
 	int err;
 
 	/* No load-on-demand here? */
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index 0a90962..63f387e 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -66,7 +66,7 @@
 static char hil_language[][16] = { HIL_LOCALE_MAP };
 
 struct hil_kbd {
-	struct input_dev dev;
+	struct input_dev *dev;
 	struct serio *serio;
 
 	/* Input buffer and index for packets from HIL bus. */
@@ -86,7 +86,7 @@
 /* Process a complete packet after transfer from the HIL */
 static void hil_kbd_process_record(struct hil_kbd *kbd)
 {
-	struct input_dev *dev = &kbd->dev;
+	struct input_dev *dev = kbd->dev;
 	hil_packet *data = kbd->data;
 	hil_packet p;
 	int idx, i, cnt;
@@ -240,8 +240,8 @@
 		return;
 	}
 
-	input_unregister_device(&kbd->dev);
 	serio_close(serio);
+	input_unregister_device(kbd->dev);
 	kfree(kbd);
 }
 
@@ -251,16 +251,18 @@
 	uint8_t		did, *idd;
 	int		i;
 	
-	kbd = kmalloc(sizeof(*kbd), GFP_KERNEL);
+	kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
 	if (!kbd)
 		return -ENOMEM;
-	memset(kbd, 0, sizeof(struct hil_kbd));
+
+	kbd->dev = input_allocate_device();
+	if (!kbd->dev) goto bail1;
+	kbd->dev->private = kbd;
 
 	if (serio_open(serio, drv)) goto bail0;
 
 	serio_set_drvdata(serio, kbd);
 	kbd->serio = serio;
-	kbd->dev.private = kbd;
 
 	init_MUTEX_LOCKED(&(kbd->sem));
 
@@ -302,38 +304,38 @@
 			did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]);
 		break;
 	default:
-		goto bail1;
+		goto bail2;
 	}
 
 	if(HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
 		printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n");
-		goto bail1;
+		goto bail2;
 	}
 
 
-	kbd->dev.evbit[0]	= BIT(EV_KEY) | BIT(EV_REP);
-	kbd->dev.ledbit[0]	= BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
-	kbd->dev.keycodemax	= HIL_KEYCODES_SET1_TBLSIZE;
-	kbd->dev.keycodesize	= sizeof(hil_kbd_set1[0]);
-	kbd->dev.keycode	= hil_kbd_set1;
-	kbd->dev.name		= strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME;
-	kbd->dev.phys		= "hpkbd/input0";	/* XXX */
+	kbd->dev->evbit[0]	= BIT(EV_KEY) | BIT(EV_REP);
+	kbd->dev->ledbit[0]	= BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+	kbd->dev->keycodemax	= HIL_KEYCODES_SET1_TBLSIZE;
+	kbd->dev->keycodesize	= sizeof(hil_kbd_set1[0]);
+	kbd->dev->keycode	= hil_kbd_set1;
+	kbd->dev->name		= strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME;
+	kbd->dev->phys		= "hpkbd/input0";	/* XXX */
 
-	kbd->dev.id.bustype	= BUS_HIL;
-	kbd->dev.id.vendor	= PCI_VENDOR_ID_HP;
-	kbd->dev.id.product	= 0x0001; /* TODO: get from kbd->rsc */
-	kbd->dev.id.version	= 0x0100; /* TODO: get from kbd->rsc */
-	kbd->dev.dev		= &serio->dev;
+	kbd->dev->id.bustype	= BUS_HIL;
+	kbd->dev->id.vendor	= PCI_VENDOR_ID_HP;
+	kbd->dev->id.product	= 0x0001; /* TODO: get from kbd->rsc */
+	kbd->dev->id.version	= 0x0100; /* TODO: get from kbd->rsc */
+	kbd->dev->dev		= &serio->dev;
 
 	for (i = 0; i < 128; i++) {
-		set_bit(hil_kbd_set1[i], kbd->dev.keybit);
-		set_bit(hil_kbd_set3[i], kbd->dev.keybit);
+		set_bit(hil_kbd_set1[i], kbd->dev->keybit);
+		set_bit(hil_kbd_set3[i], kbd->dev->keybit);
 	}
-	clear_bit(0, kbd->dev.keybit);
+	clear_bit(0, kbd->dev->keybit);
 
-	input_register_device(&kbd->dev);
+	input_register_device(kbd->dev);
 	printk(KERN_INFO "input: %s, ID: %d\n",
-		kbd->dev.name, did);
+		kbd->dev->name, did);
 
 	serio->write(serio, 0);
 	serio->write(serio, 0);
@@ -343,8 +345,10 @@
 	up(&(kbd->sem));
 
 	return 0;
- bail1:
+ bail2:
 	serio_close(serio);
+ bail1:
+	input_free_device(kbd->dev);
  bail0:
 	kfree(kbd);
 	serio_set_drvdata(serio, NULL);
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index e95bc05..33edd03 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
  *  Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
- *  Copyright (C) 1999-2003 Helge Deller <deller@gmx.de>
+ *  Copyright (C) 1999-2006 Helge Deller <deller@gmx.de>
  *
  *  Very basic HP Human Interface Loop (HIL) driver.
  *  This driver handles the keyboard on HP300 (m68k) and on some 
@@ -90,7 +90,7 @@
 
 /* HIL structure */
 static struct {
-	struct input_dev dev;
+	struct input_dev *dev;
 
 	unsigned int curdev;
 	
@@ -117,7 +117,7 @@
 		down = (hil_dev.data[1] & 1) == 0;
 		scode = hil_dev.data[1] >> 1;
 		key = hphilkeyb_keycode[scode];
-		input_report_key(&hil_dev.dev, key, down);
+		input_report_key(hil_dev.dev, key, down);
 		break;
 	}
 	hil_dev.curdev = 0;
@@ -207,9 +207,14 @@
 	unsigned int i, kbid;
 	wait_queue_head_t hil_wait;
 
-	if (hil_dev.dev.id.bustype) {
+	if (hil_dev.dev) {
 		return -ENODEV; /* already initialized */
 	}
+
+	hil_dev.dev = input_allocate_device();
+	if (!hil_dev.dev)
+		return -ENOMEM;
+	hil_dev.dev->private = &hil_dev;
 	
 #if defined(CONFIG_HP300)
 	if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
@@ -247,28 +252,26 @@
 	c = 0;
 	hil_do(HIL_WRITEKBDSADR, &c, 1);
 	
-	init_input_dev(&hil_dev.dev);
-
 	for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++)
 		if (hphilkeyb_keycode[i] != KEY_RESERVED)
-			set_bit(hphilkeyb_keycode[i], hil_dev.dev.keybit);
+			set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit);
 
-	hil_dev.dev.evbit[0]    = BIT(EV_KEY) | BIT(EV_REP);
-	hil_dev.dev.ledbit[0]   = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
-	hil_dev.dev.keycodemax  = HIL_KEYCODES_SET1_TBLSIZE;
-        hil_dev.dev.keycodesize = sizeof(hphilkeyb_keycode[0]);
-	hil_dev.dev.keycode     = hphilkeyb_keycode;
-	hil_dev.dev.name 	= "HIL keyboard";
-	hil_dev.dev.phys 	= "hpkbd/input0";
+	hil_dev.dev->evbit[0]    = BIT(EV_KEY) | BIT(EV_REP);
+	hil_dev.dev->ledbit[0]   = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+	hil_dev.dev->keycodemax  = HIL_KEYCODES_SET1_TBLSIZE;
+	hil_dev.dev->keycodesize = sizeof(hphilkeyb_keycode[0]);
+	hil_dev.dev->keycode     = hphilkeyb_keycode;
+	hil_dev.dev->name 	= "HIL keyboard";
+	hil_dev.dev->phys 	= "hpkbd/input0";
 
-	hil_dev.dev.id.bustype	= BUS_HIL;
-	hil_dev.dev.id.vendor	= PCI_VENDOR_ID_HP;
-	hil_dev.dev.id.product	= 0x0001;
-	hil_dev.dev.id.version	= 0x0010;
+	hil_dev.dev->id.bustype	= BUS_HIL;
+	hil_dev.dev->id.vendor	= PCI_VENDOR_ID_HP;
+	hil_dev.dev->id.product	= 0x0001;
+	hil_dev.dev->id.version	= 0x0010;
 
-	input_register_device(&hil_dev.dev);
+	input_register_device(hil_dev.dev);
 	printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n",
-		hil_dev.dev.name, kbid, HILBASE, HIL_IRQ);
+		hil_dev.dev->name, kbid, HILBASE, HIL_IRQ);
 
 	return 0;
 }
@@ -329,7 +332,9 @@
 	/* Turn off interrupts */
 	hil_do(HIL_INTOFF, NULL, 0);
 
-	input_unregister_device(&hil_dev.dev);
+	input_unregister_device(hil_dev.dev);
+
+	hil_dev.dev = NULL;
 
 #if defined(CONFIG_PARISC)
 	unregister_parisc_driver(&hil_driver);
diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c
index c2bf2ed..bfb564f 100644
--- a/drivers/input/mouse/hil_ptr.c
+++ b/drivers/input/mouse/hil_ptr.c
@@ -55,7 +55,7 @@
 #define HIL_PTR_MAX_LENGTH 16
 
 struct hil_ptr {
-	struct input_dev dev;
+	struct input_dev *dev;
 	struct serio *serio;
 
 	/* Input buffer and index for packets from HIL bus. */
@@ -79,7 +79,7 @@
 /* Process a complete packet after transfer from the HIL */
 static void hil_ptr_process_record(struct hil_ptr *ptr)
 {
-	struct input_dev *dev = &ptr->dev;
+	struct input_dev *dev = ptr->dev;
 	hil_packet *data = ptr->data;
 	hil_packet p;
 	int idx, i, cnt, laxis;
@@ -148,12 +148,12 @@
 		if (absdev) {
 			val = lo + (hi<<8);
 #ifdef TABLET_AUTOADJUST
-			if (val < ptr->dev.absmin[ABS_X + i])
-				ptr->dev.absmin[ABS_X + i] = val;
-			if (val > ptr->dev.absmax[ABS_X + i])
-				ptr->dev.absmax[ABS_X + i] = val;
+			if (val < dev->absmin[ABS_X + i])
+				dev->absmin[ABS_X + i] = val;
+			if (val > dev->absmax[ABS_X + i])
+				dev->absmax[ABS_X + i] = val;
 #endif
-			if (i%3) val = ptr->dev.absmax[ABS_X + i] - val;
+			if (i%3) val = dev->absmax[ABS_X + i] - val;
 			input_report_abs(dev, ABS_X + i, val);
 		} else {
 			val = (int) (((int8_t)lo) | ((int8_t)hi<<8));
@@ -233,26 +233,29 @@
 		return;
 	}
 
-	input_unregister_device(&ptr->dev);
 	serio_close(serio);
+	input_unregister_device(ptr->dev);
 	kfree(ptr);
 }
 
 static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
 {
-	struct hil_ptr	*ptr;
-	char		*txt;
-	unsigned int	i, naxsets, btntype;
-	uint8_t		did, *idd;
+	struct hil_ptr	 *ptr;
+	char		 *txt;
+	unsigned int	 i, naxsets, btntype;
+	uint8_t		 did, *idd;
 
-	if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return -ENOMEM;
-	memset(ptr, 0, sizeof(struct hil_ptr));
+	if (!(ptr = kzalloc(sizeof(struct hil_ptr), GFP_KERNEL)))
+		return -ENOMEM;
 
-	if (serio_open(serio, driver)) goto bail0;
+	ptr->dev = input_allocate_device();
+	if (!ptr->dev) goto bail0;
+	ptr->dev->private = ptr;
+
+	if (serio_open(serio, driver)) goto bail1;
 
 	serio_set_drvdata(serio, ptr);
 	ptr->serio = serio;
-	ptr->dev.private = ptr;
 
 	init_MUTEX_LOCKED(&(ptr->sem));
 
@@ -283,25 +286,24 @@
 
 	up(&(ptr->sem));
 
-	init_input_dev(&ptr->dev);
 	did = ptr->idd[0];
 	idd = ptr->idd + 1;
 	txt = "unknown";
 	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
-		ptr->dev.evbit[0] = BIT(EV_REL);
+		ptr->dev->evbit[0] = BIT(EV_REL);
 		txt = "relative";
 	}
 
 	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_ABS) {
-		ptr->dev.evbit[0] = BIT(EV_ABS);
+		ptr->dev->evbit[0] = BIT(EV_ABS);
 		txt = "absolute";
 	}
-	if (!ptr->dev.evbit[0]) {
-		goto bail1;
+	if (!ptr->dev->evbit[0]) {
+		goto bail2;
 	}
 
 	ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
-	if (ptr->nbtn) ptr->dev.evbit[0] |= BIT(EV_KEY);
+	if (ptr->nbtn) ptr->dev->evbit[0] |= BIT(EV_KEY);
 
 	naxsets = HIL_IDD_NUM_AXSETS(*idd);
 	ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
@@ -325,7 +327,7 @@
 		btntype = BTN_MOUSE;
 
 	for (i = 0; i < ptr->nbtn; i++) {
-		set_bit(btntype | i, ptr->dev.keybit);
+		set_bit(btntype | i, ptr->dev->keybit);
 		ptr->btnmap[i] = btntype | i;
 	}
 
@@ -337,50 +339,52 @@
 
 	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
 		for (i = 0; i < ptr->naxes; i++) {
-			set_bit(REL_X + i, ptr->dev.relbit);
+			set_bit(REL_X + i, ptr->dev->relbit);
 		}
 		for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
-			set_bit(REL_X + i, ptr->dev.relbit);
+			set_bit(REL_X + i, ptr->dev->relbit);
 		}
 	} else {
 		for (i = 0; i < ptr->naxes; i++) {
-	  		set_bit(ABS_X + i, ptr->dev.absbit);
-			ptr->dev.absmin[ABS_X + i] = 0;
-			ptr->dev.absmax[ABS_X + i] = 
+			set_bit(ABS_X + i, ptr->dev->absbit);
+			ptr->dev->absmin[ABS_X + i] = 0;
+			ptr->dev->absmax[ABS_X + i] =
 				HIL_IDD_AXIS_MAX((ptr->idd + 1), i);
 		}
 		for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
-			set_bit(ABS_X + i, ptr->dev.absbit);
-			ptr->dev.absmin[ABS_X + i] = 0;
-			ptr->dev.absmax[ABS_X + i] = 
+			set_bit(ABS_X + i, ptr->dev->absbit);
+			ptr->dev->absmin[ABS_X + i] = 0;
+			ptr->dev->absmax[ABS_X + i] =
 				HIL_IDD_AXIS_MAX((ptr->idd + 1), (i - 3));
 		}
 #ifdef TABLET_AUTOADJUST
 		for (i = 0; i < ABS_MAX; i++) {
-			int diff = ptr->dev.absmax[ABS_X + i] / 10;
-			ptr->dev.absmin[ABS_X + i] += diff;
-			ptr->dev.absmax[ABS_X + i] -= diff;
+			int diff = ptr->dev->absmax[ABS_X + i] / 10;
+			ptr->dev->absmin[ABS_X + i] += diff;
+			ptr->dev->absmax[ABS_X + i] -= diff;
 		}
 #endif
 	}
 
-	ptr->dev.name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME;
+	ptr->dev->name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME;
 
-	ptr->dev.id.bustype	= BUS_HIL;
-	ptr->dev.id.vendor	= PCI_VENDOR_ID_HP;
-	ptr->dev.id.product	= 0x0001; /* TODO: get from ptr->rsc */
-	ptr->dev.id.version	= 0x0100; /* TODO: get from ptr->rsc */
-	ptr->dev.dev		= &serio->dev;
+	ptr->dev->id.bustype	= BUS_HIL;
+	ptr->dev->id.vendor	= PCI_VENDOR_ID_HP;
+	ptr->dev->id.product	= 0x0001; /* TODO: get from ptr->rsc */
+	ptr->dev->id.version	= 0x0100; /* TODO: get from ptr->rsc */
+	ptr->dev->dev		= &serio->dev;
 
-	input_register_device(&ptr->dev);
+	input_register_device(ptr->dev);
 	printk(KERN_INFO "input: %s (%s), ID: %d\n",
-                ptr->dev.name, 
+		ptr->dev->name,
 		(btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad",
 		did);
 
 	return 0;
- bail1:
+ bail2:
 	serio_close(serio);
+ bail1:
+	input_free_device(ptr->dev);
  bail0:
 	kfree(ptr);
 	serio_set_drvdata(serio, NULL);
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index a7b0de0..c0b1e4b 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -1,7 +1,7 @@
 /*
  * drivers/input/serio/gscps2.c
  *
- * Copyright (c) 2004 Helge Deller <deller@gmx.de>
+ * Copyright (c) 2004-2006 Helge Deller <deller@gmx.de>
  * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
  * Copyright (c) 2002 Thibaut Varene <varenet@parisc-linux.org>
  *
@@ -354,7 +354,7 @@
 	memset(serio, 0, sizeof(struct serio));
 	ps2port->port = serio;
 	ps2port->padev = dev;
-	ps2port->addr = ioremap(hpa, GSC_STATUS + 4);
+	ps2port->addr = ioremap_nocache(hpa, GSC_STATUS + 4);
 	spin_lock_init(&ps2port->lock);
 
 	gscps2_reset(ps2port);
diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c
index 1c9426f..aa4a8a4 100644
--- a/drivers/input/serio/hp_sdc_mlc.c
+++ b/drivers/input/serio/hp_sdc_mlc.c
@@ -270,9 +270,10 @@
 
  do_control:
 	priv->emtestmode = mlc->opacket & HIL_CTRL_TEST;
-	if ((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE) {
-		BUG(); /* we cannot emulate this, it should not be used. */
-	}
+	
+	/* we cannot emulate this, it should not be used. */
+	BUG_ON((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE);
+	
 	if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY) goto control_only;
 	if (mlc->opacket & HIL_CTRL_APE) { 
 		BUG(); /* Should not send command/data after engaging APE */
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index a81f987..46d1fec 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -23,7 +23,7 @@
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
-#include <linux/interrupt.h>
+#include <asm/irq.h>
 
 #ifdef	CONFIG_ARM
 #include <asm/mach-types.h>
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile
index 03d8ccd..988142c 100644
--- a/drivers/isdn/Makefile
+++ b/drivers/isdn/Makefile
@@ -13,3 +13,4 @@
 obj-$(CONFIG_ISDN_DRV_LOOP)		+= isdnloop/
 obj-$(CONFIG_ISDN_DRV_ACT2000)		+= act2000/
 obj-$(CONFIG_HYSDN)			+= hysdn/
+obj-$(CONFIG_ISDN_DRV_GIGASET)		+= gigaset/
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 623adbb..9b493f0 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1485,6 +1485,7 @@
 {
 	char *p;
 	char *compileinfo;
+	int major_ret;
 
 	if ((p = strchr(revision, ':')) != 0 && p[1]) {
 		strlcpy(rev, p + 2, sizeof(rev));
@@ -1493,11 +1494,12 @@
 	} else
 		strcpy(rev, "1.0");
 
-	if (register_chrdev(capi_major, "capi20", &capi_fops)) {
+	major_ret = register_chrdev(capi_major, "capi20", &capi_fops);
+	if (major_ret < 0) {
 		printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
-		return -EIO;
+		return major_ret;
 	}
-
+	capi_major = major_ret;
 	capi_class = class_create(THIS_MODULE, "capi");
 	if (IS_ERR(capi_class)) {
 		unregister_chrdev(capi_major, "capi20");
diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c
index 2cc8b27..ca9dc00 100644
--- a/drivers/isdn/capi/kcapi_proc.c
+++ b/drivers/isdn/capi/kcapi_proc.c
@@ -233,7 +233,7 @@
 };
 
 static void
-create_seq_entry(char *name, mode_t mode, struct file_operations *f)
+create_seq_entry(char *name, mode_t mode, const struct file_operations *f)
 {
 	struct proc_dir_entry *entry;
 	entry = create_proc_entry(name, mode, NULL);
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig
new file mode 100644
index 0000000..53c4fb6
--- /dev/null
+++ b/drivers/isdn/gigaset/Kconfig
@@ -0,0 +1,42 @@
+menu "Siemens Gigaset"
+	depends on ISDN_I4L
+
+config ISDN_DRV_GIGASET
+	tristate "Siemens Gigaset support (isdn)"
+	depends on ISDN_I4L && m
+#	depends on ISDN_I4L && MODULES
+	help
+	  Say m here if you have a Gigaset or Sinus isdn device.
+
+if ISDN_DRV_GIGASET!=n
+
+config GIGASET_BASE
+	tristate "Gigaset base station support"
+	depends on ISDN_DRV_GIGASET && USB
+	help
+	  Say m here if you need to communicate with the base
+	  directly via USB.
+
+config GIGASET_M105
+	tristate "Gigaset M105 support"
+	depends on ISDN_DRV_GIGASET && USB
+	help
+	  Say m here if you need the driver for the Gigaset M105 device.
+
+config GIGASET_DEBUG
+	bool "Gigaset debugging"
+	help
+	  This enables debugging code in the Gigaset drivers.
+	  If in doubt, say yes.
+
+config GIGASET_UNDOCREQ
+	bool "Support for undocumented USB requests"
+	help
+	  This enables support for USB requests we only know from
+	  reverse engineering (currently M105 only). If you need
+	  features like configuration mode of M105, say yes. If you
+	  care about your device, say no.
+
+endif
+
+endmenu
diff --git a/drivers/isdn/gigaset/Makefile b/drivers/isdn/gigaset/Makefile
new file mode 100644
index 0000000..9b9acf1
--- /dev/null
+++ b/drivers/isdn/gigaset/Makefile
@@ -0,0 +1,6 @@
+gigaset-y := common.o interface.o proc.o ev-layer.o i4l.o
+usb_gigaset-y := usb-gigaset.o asyncdata.o
+bas_gigaset-y := bas-gigaset.o isocdata.o
+
+obj-$(CONFIG_GIGASET_M105) += usb_gigaset.o gigaset.o
+obj-$(CONFIG_GIGASET_BASE) += bas_gigaset.o gigaset.o
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c
new file mode 100644
index 0000000..171f8b7
--- /dev/null
+++ b/drivers/isdn/gigaset/asyncdata.c
@@ -0,0 +1,597 @@
+/*
+ * Common data handling layer for ser_gigaset and usb_gigaset
+ *
+ * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>,
+ *                       Hansjoerg Lipp <hjlipp@web.de>,
+ *                       Stefan Eilers <Eilers.Stefan@epost.de>.
+ *
+ * =====================================================================
+ *	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.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: asyncdata.c,v 1.2.2.7 2005/11/13 23:05:18 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+#include <linux/crc-ccitt.h>
+
+//#define GIG_M10x_STUFF_VOICE_DATA
+
+/* check if byte must be stuffed/escaped
+ * I'm not sure which data should be encoded.
+ * Therefore I will go the hard way and decode every value
+ * less than 0x20, the flag sequence and the control escape char.
+ */
+static inline int muststuff(unsigned char c)
+{
+	if (c < PPP_TRANS) return 1;
+	if (c == PPP_FLAG) return 1;
+	if (c == PPP_ESCAPE) return 1;
+	/* other possible candidates: */
+	/* 0x91: XON with parity set */
+	/* 0x93: XOFF with parity set */
+	return 0;
+}
+
+/* == data input =========================================================== */
+
+/* process a block of received bytes in command mode (modem response)
+ * Return value:
+ *	number of processed bytes
+ */
+static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes,
+                           struct inbuf_t *inbuf)
+{
+	struct cardstate *cs = inbuf->cs;
+	unsigned cbytes      = cs->cbytes;
+	int inputstate = inbuf->inputstate;
+	int startbytes = numbytes;
+
+	for (;;) {
+		cs->respdata[cbytes] = c;
+		if (c == 10 || c == 13) {
+			dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
+			    __func__, cbytes);
+			cs->cbytes = cbytes;
+			gigaset_handle_modem_response(cs); /* can change cs->dle */
+			cbytes = 0;
+
+			if (cs->dle &&
+			    !(inputstate & INS_DLE_command)) {
+				inputstate &= ~INS_command;
+				break;
+			}
+		} else {
+			/* advance in line buffer, checking for overflow */
+			if (cbytes < MAX_RESP_SIZE - 1)
+				cbytes++;
+			else
+				warn("response too large");
+		}
+
+		if (!numbytes)
+			break;
+		c = *src++;
+		--numbytes;
+		if (c == DLE_FLAG &&
+		    (cs->dle || inputstate & INS_DLE_command)) {
+			inputstate |= INS_DLE_char;
+			break;
+		}
+	}
+
+	cs->cbytes = cbytes;
+	inbuf->inputstate = inputstate;
+
+	return startbytes - numbytes;
+}
+
+/* process a block of received bytes in lock mode (tty i/f)
+ * Return value:
+ *	number of processed bytes
+ */
+static inline int lock_loop(unsigned char *src, int numbytes,
+                            struct inbuf_t *inbuf)
+{
+	struct cardstate *cs = inbuf->cs;
+
+	gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", numbytes, src, 0);
+	gigaset_if_receive(cs, src, numbytes);
+
+	return numbytes;
+}
+
+/* process a block of received bytes in HDLC data mode
+ * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes.
+ * When a frame is complete, check the FCS and pass valid frames to the LL.
+ * If DLE is encountered, return immediately to let the caller handle it.
+ * Return value:
+ *	number of processed bytes
+ *	numbytes (all bytes processed) on error --FIXME
+ */
+static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes,
+                            struct inbuf_t *inbuf)
+{
+	struct cardstate *cs = inbuf->cs;
+	struct bc_state *bcs = inbuf->bcs;
+	int inputstate;
+	__u16 fcs;
+	struct sk_buff *skb;
+	unsigned char error;
+	struct sk_buff *compskb;
+	int startbytes = numbytes;
+	int l;
+
+	IFNULLRETVAL(bcs, numbytes);
+	inputstate = bcs->inputstate;
+	fcs = bcs->fcs;
+	skb = bcs->skb;
+	IFNULLRETVAL(skb, numbytes);
+
+	if (unlikely(inputstate & INS_byte_stuff)) {
+		inputstate &= ~INS_byte_stuff;
+		goto byte_stuff;
+	}
+	for (;;) {
+		if (unlikely(c == PPP_ESCAPE)) {
+			if (unlikely(!numbytes)) {
+				inputstate |= INS_byte_stuff;
+				break;
+			}
+			c = *src++;
+			--numbytes;
+			if (unlikely(c == DLE_FLAG &&
+				     (cs->dle ||
+				      inbuf->inputstate & INS_DLE_command))) {
+				inbuf->inputstate |= INS_DLE_char;
+				inputstate |= INS_byte_stuff;
+				break;
+			}
+byte_stuff:
+			c ^= PPP_TRANS;
+#ifdef CONFIG_GIGASET_DEBUG
+			if (unlikely(!muststuff(c)))
+				dbg(DEBUG_HDLC,
+				    "byte stuffed: 0x%02x", c);
+#endif
+		} else if (unlikely(c == PPP_FLAG)) {
+			if (unlikely(inputstate & INS_skip_frame)) {
+				if (!(inputstate & INS_have_data)) { /* 7E 7E */
+					//dbg(DEBUG_HDLC, "(7e)7e------------------------");
+#ifdef CONFIG_GIGASET_DEBUG
+					++bcs->emptycount;
+#endif
+				} else
+					dbg(DEBUG_HDLC,
+					    "7e----------------------------");
+
+				/* end of frame */
+				error = 1;
+				gigaset_rcv_error(NULL, cs, bcs);
+			} else if (!(inputstate & INS_have_data)) { /* 7E 7E */
+				//dbg(DEBUG_HDLC, "(7e)7e------------------------");
+#ifdef CONFIG_GIGASET_DEBUG
+				++bcs->emptycount;
+#endif
+				break;
+			} else {
+				dbg(DEBUG_HDLC,
+				    "7e----------------------------");
+
+				/* end of frame */
+				error = 0;
+
+				if (unlikely(fcs != PPP_GOODFCS)) {
+					err("Packet checksum at %lu failed, "
+					    "packet is corrupted (%u bytes)!",
+					    bcs->rcvbytes, skb->len);
+					compskb = NULL;
+					gigaset_rcv_error(compskb, cs, bcs);
+					error = 1;
+				} else {
+					if (likely((l = skb->len) > 2)) {
+						skb->tail -= 2;
+						skb->len -= 2;
+					} else {
+						dev_kfree_skb(skb);
+						skb = NULL;
+						inputstate |= INS_skip_frame;
+						if (l == 1) {
+							err("invalid packet size (1)!");
+							error = 1;
+							gigaset_rcv_error(NULL, cs, bcs);
+						}
+					}
+					if (likely(!(error ||
+						     (inputstate &
+						      INS_skip_frame)))) {
+						gigaset_rcv_skb(skb, cs, bcs);
+					}
+				}
+			}
+
+			if (unlikely(error))
+				if (skb)
+					dev_kfree_skb(skb);
+
+			fcs = PPP_INITFCS;
+			inputstate &= ~(INS_have_data | INS_skip_frame);
+			if (unlikely(bcs->ignore)) {
+				inputstate |= INS_skip_frame;
+				skb = NULL;
+			} else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)) {
+				skb_reserve(skb, HW_HDR_LEN);
+			} else {
+				warn("could not allocate new skb");
+				inputstate |= INS_skip_frame;
+			}
+
+			break;
+#ifdef CONFIG_GIGASET_DEBUG
+		} else if (unlikely(muststuff(c))) {
+			/* Should not happen. Possible after ZDLE=1<CR><LF>. */
+			dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
+#endif
+		}
+
+		/* add character */
+
+#ifdef CONFIG_GIGASET_DEBUG
+		if (unlikely(!(inputstate & INS_have_data))) {
+			dbg(DEBUG_HDLC,
+			    "7e (%d x) ================", bcs->emptycount);
+			bcs->emptycount = 0;
+		}
+#endif
+
+		inputstate |= INS_have_data;
+
+		if (likely(!(inputstate & INS_skip_frame))) {
+			if (unlikely(skb->len == SBUFSIZE)) {
+				warn("received packet too long");
+				dev_kfree_skb_any(skb);
+				skb = NULL;
+				inputstate |= INS_skip_frame;
+				break;
+			}
+			*gigaset_skb_put_quick(skb, 1) = c;
+			/* *__skb_put (skb, 1) = c; */
+			fcs = crc_ccitt_byte(fcs, c);
+		}
+
+		if (unlikely(!numbytes))
+			break;
+		c = *src++;
+		--numbytes;
+		if (unlikely(c == DLE_FLAG &&
+			     (cs->dle ||
+			      inbuf->inputstate & INS_DLE_command))) {
+			inbuf->inputstate |= INS_DLE_char;
+			break;
+		}
+	}
+	bcs->inputstate = inputstate;
+	bcs->fcs = fcs;
+	bcs->skb = skb;
+	return startbytes - numbytes;
+}
+
+/* process a block of received bytes in transparent data mode
+ * Invert bytes, undoing byte stuffing and watching for DLE escapes.
+ * If DLE is encountered, return immediately to let the caller handle it.
+ * Return value:
+ *	number of processed bytes
+ *	numbytes (all bytes processed) on error --FIXME
+ */
+static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
+                            struct inbuf_t *inbuf)
+{
+	struct cardstate *cs = inbuf->cs;
+	struct bc_state *bcs = inbuf->bcs;
+	int inputstate;
+	struct sk_buff *skb;
+	int startbytes = numbytes;
+
+	IFNULLRETVAL(bcs, numbytes);
+	inputstate = bcs->inputstate;
+	skb = bcs->skb;
+	IFNULLRETVAL(skb, numbytes);
+
+	for (;;) {
+		/* add character */
+		inputstate |= INS_have_data;
+
+		if (likely(!(inputstate & INS_skip_frame))) {
+			if (unlikely(skb->len == SBUFSIZE)) {
+				//FIXME just pass skb up and allocate a new one
+				warn("received packet too long");
+				dev_kfree_skb_any(skb);
+				skb = NULL;
+				inputstate |= INS_skip_frame;
+				break;
+			}
+			*gigaset_skb_put_quick(skb, 1) = gigaset_invtab[c];
+		}
+
+		if (unlikely(!numbytes))
+			break;
+		c = *src++;
+		--numbytes;
+		if (unlikely(c == DLE_FLAG &&
+			     (cs->dle ||
+			      inbuf->inputstate & INS_DLE_command))) {
+			inbuf->inputstate |= INS_DLE_char;
+			break;
+		}
+	}
+
+	/* pass data up */
+	if (likely(inputstate & INS_have_data)) {
+		if (likely(!(inputstate & INS_skip_frame))) {
+			gigaset_rcv_skb(skb, cs, bcs);
+		}
+		inputstate &= ~(INS_have_data | INS_skip_frame);
+		if (unlikely(bcs->ignore)) {
+			inputstate |= INS_skip_frame;
+			skb = NULL;
+		} else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN))
+				  != NULL)) {
+			skb_reserve(skb, HW_HDR_LEN);
+		} else {
+			warn("could not allocate new skb");
+			inputstate |= INS_skip_frame;
+		}
+	}
+
+	bcs->inputstate = inputstate;
+	bcs->skb = skb;
+	return startbytes - numbytes;
+}
+
+/* process a block of data received from the device
+ */
+void gigaset_m10x_input(struct inbuf_t *inbuf)
+{
+	struct cardstate *cs;
+	unsigned tail, head, numbytes;
+	unsigned char *src, c;
+	int procbytes;
+
+	head = atomic_read(&inbuf->head);
+	tail = atomic_read(&inbuf->tail);
+	dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
+
+	if (head != tail) {
+		cs = inbuf->cs;
+		src = inbuf->data + head;
+		numbytes = (head > tail ? RBUFSIZE : tail) - head;
+		dbg(DEBUG_INTR, "processing %u bytes", numbytes);
+
+		while (numbytes) {
+			if (atomic_read(&cs->mstate) == MS_LOCKED) {
+				procbytes = lock_loop(src, numbytes, inbuf);
+				src += procbytes;
+				numbytes -= procbytes;
+			} else {
+				c = *src++;
+				--numbytes;
+				if (c == DLE_FLAG && (cs->dle ||
+				    inbuf->inputstate & INS_DLE_command)) {
+					if (!(inbuf->inputstate & INS_DLE_char)) {
+						inbuf->inputstate |= INS_DLE_char;
+						goto nextbyte;
+					}
+					/* <DLE> <DLE> => <DLE> in data stream */
+					inbuf->inputstate &= ~INS_DLE_char;
+				}
+
+				if (!(inbuf->inputstate & INS_DLE_char)) {
+
+					/* FIXME Einfach je nach Modus Funktionszeiger in cs setzen [hier+hdlc_loop]?  */
+					/* FIXME Spart folgendes "if" und ermoeglicht andere Protokolle */
+					if (inbuf->inputstate & INS_command)
+						procbytes = cmd_loop(c, src, numbytes, inbuf);
+					else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC)
+						procbytes = hdlc_loop(c, src, numbytes, inbuf);
+					else
+						procbytes = iraw_loop(c, src, numbytes, inbuf);
+
+					src += procbytes;
+					numbytes -= procbytes;
+				} else {  /* DLE-char */
+					inbuf->inputstate &= ~INS_DLE_char;
+					switch (c) {
+					case 'X': /*begin of command*/
+#ifdef CONFIG_GIGASET_DEBUG
+						if (inbuf->inputstate & INS_command)
+							err("received <DLE> 'X' in command mode");
+#endif
+						inbuf->inputstate |=
+							INS_command | INS_DLE_command;
+						break;
+					case '.': /*end of command*/
+#ifdef CONFIG_GIGASET_DEBUG
+						if (!(inbuf->inputstate & INS_command))
+							err("received <DLE> '.' in hdlc mode");
+#endif
+						inbuf->inputstate &= cs->dle ?
+							~(INS_DLE_command|INS_command)
+							: ~INS_DLE_command;
+						break;
+					//case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */
+					default:
+						err("received 0x10 0x%02x!", (int) c);
+						/* FIXME: reset driver?? */
+					}
+				}
+			}
+nextbyte:
+			if (!numbytes) {
+				/* end of buffer, check for wrap */
+				if (head > tail) {
+					head = 0;
+					src = inbuf->data;
+					numbytes = tail;
+				} else {
+					head = tail;
+					break;
+				}
+			}
+		}
+
+		dbg(DEBUG_INTR, "setting head to %u", head);
+		atomic_set(&inbuf->head, head);
+	}
+}
+
+
+/* == data output ========================================================== */
+
+/* Encoding of a PPP packet into an octet stuffed HDLC frame
+ * with FCS, opening and closing flags.
+ * parameters:
+ *	skb	skb containing original packet (freed upon return)
+ *	head	number of headroom bytes to allocate in result skb
+ *	tail	number of tailroom bytes to allocate in result skb
+ * Return value:
+ *	pointer to newly allocated skb containing the result frame
+ */
+static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
+{
+	struct sk_buff *hdlc_skb;
+	__u16 fcs;
+	unsigned char c;
+	unsigned char *cp;
+	int len;
+	unsigned int stuf_cnt;
+
+	stuf_cnt = 0;
+	fcs = PPP_INITFCS;
+	cp = skb->data;
+	len = skb->len;
+	while (len--) {
+		if (muststuff(*cp))
+			stuf_cnt++;
+		fcs = crc_ccitt_byte(fcs, *cp++);
+	}
+	fcs ^= 0xffff;                 /* complement */
+
+	/* size of new buffer: original size + number of stuffing bytes
+	 * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
+	 */
+	hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head);
+	if (!hdlc_skb) {
+		err("unable to allocate memory for HDLC encoding!");
+		dev_kfree_skb(skb);
+		return NULL;
+	}
+	skb_reserve(hdlc_skb, head);
+
+	/* Copy acknowledge request into new skb */
+	memcpy(hdlc_skb->head, skb->head, 2);
+
+	/* Add flag sequence in front of everything.. */
+	*(skb_put(hdlc_skb, 1)) = PPP_FLAG;
+
+	/* Perform byte stuffing while copying data. */
+	while (skb->len--) {
+		if (muststuff(*skb->data)) {
+			*(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
+			*(skb_put(hdlc_skb, 1)) = (*skb->data++) ^ PPP_TRANS;
+		} else
+			*(skb_put(hdlc_skb, 1)) = *skb->data++;
+	}
+
+	/* Finally add FCS (byte stuffed) and flag sequence */
+	c = (fcs & 0x00ff);      /* least significant byte first */
+	if (muststuff(c)) {
+		*(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
+		c ^= PPP_TRANS;
+	}
+	*(skb_put(hdlc_skb, 1)) = c;
+
+	c = ((fcs >> 8) & 0x00ff);
+	if (muststuff(c)) {
+		*(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
+		c ^= PPP_TRANS;
+	}
+	*(skb_put(hdlc_skb, 1)) = c;
+
+	*(skb_put(hdlc_skb, 1)) = PPP_FLAG;
+
+	dev_kfree_skb(skb);
+	return hdlc_skb;
+}
+
+/* Encoding of a raw packet into an octet stuffed bit inverted frame
+ * parameters:
+ *	skb	skb containing original packet (freed upon return)
+ *	head	number of headroom bytes to allocate in result skb
+ *	tail	number of tailroom bytes to allocate in result skb
+ * Return value:
+ *	pointer to newly allocated skb containing the result frame
+ */
+static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
+{
+	struct sk_buff *iraw_skb;
+	unsigned char c;
+	unsigned char *cp;
+	int len;
+
+	/* worst case: every byte must be stuffed */
+	iraw_skb = dev_alloc_skb(2*skb->len + tail + head);
+	if (!iraw_skb) {
+		err("unable to allocate memory for HDLC encoding!");
+		dev_kfree_skb(skb);
+		return NULL;
+	}
+	skb_reserve(iraw_skb, head);
+
+	cp = skb->data;
+	len = skb->len;
+	while (len--) {
+		c = gigaset_invtab[*cp++];
+		if (c == DLE_FLAG)
+			*(skb_put(iraw_skb, 1)) = c;
+		*(skb_put(iraw_skb, 1)) = c;
+	}
+	dev_kfree_skb(skb);
+	return iraw_skb;
+}
+
+/* gigaset_send_skb
+ * called by common.c to queue an skb for sending
+ * and start transmission if necessary
+ * parameters:
+ *	B Channel control structure
+ *	skb
+ * Return value:
+ *	number of bytes accepted for sending
+ *	(skb->len if ok, 0 if out of buffer space)
+ *	or error code (< 0, eg. -EINVAL)
+ */
+int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
+{
+	unsigned len;
+
+	IFNULLRETVAL(bcs, -EFAULT);
+	IFNULLRETVAL(skb, -EFAULT);
+	len = skb->len;
+
+	if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
+		skb = HDLC_Encode(skb, HW_HDR_LEN, 0);
+	else
+		skb = iraw_encode(skb, HW_HDR_LEN, 0);
+	if (!skb)
+		return -ENOMEM;
+
+	skb_queue_tail(&bcs->squeue, skb);
+	tasklet_schedule(&bcs->cs->write_tasklet);
+
+	return len;	/* ok so far */
+}
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
new file mode 100644
index 0000000..31f0f07
--- /dev/null
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -0,0 +1,2365 @@
+/*
+ * USB driver for Gigaset 307x base via direct USB connection.
+ *
+ * Copyright (c) 2001 by Hansjoerg Lipp <hjlipp@web.de>,
+ *                       Tilman Schmidt <tilman@imap.cc>,
+ *                       Stefan Eilers <Eilers.Stefan@epost.de>.
+ *
+ * Based on usb-gigaset.c.
+ *
+ * =====================================================================
+ *	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.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: bas-gigaset.c,v 1.52.4.19 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+/* Version Information */
+#define DRIVER_AUTHOR "Tilman Schmidt <tilman@imap.cc>, Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers <Eilers.Stefan@epost.de>"
+#define DRIVER_DESC "USB Driver for Gigaset 307x"
+
+
+/* Module parameters */
+
+static int startmode = SM_ISDN;
+static int cidmode = 1;
+
+module_param(startmode, int, S_IRUGO);
+module_param(cidmode, int, S_IRUGO);
+MODULE_PARM_DESC(startmode, "start in isdn4linux mode");
+MODULE_PARM_DESC(cidmode, "Call-ID mode");
+
+#define GIGASET_MINORS     1
+#define GIGASET_MINOR      16
+#define GIGASET_MODULENAME "bas_gigaset"
+#define GIGASET_DEVFSNAME  "gig/bas/"
+#define GIGASET_DEVNAME    "ttyGB"
+
+#define IF_WRITEBUF 256 //FIXME
+
+/* Values for the Gigaset 307x */
+#define USB_GIGA_VENDOR_ID      0x0681
+#define USB_GIGA_PRODUCT_ID     0x0001
+#define USB_4175_PRODUCT_ID     0x0002
+#define USB_SX303_PRODUCT_ID    0x0021
+#define USB_SX353_PRODUCT_ID    0x0022
+
+/* table of devices that work with this driver */
+static struct usb_device_id gigaset_table [] = {
+	{ USB_DEVICE(USB_GIGA_VENDOR_ID, USB_GIGA_PRODUCT_ID) },
+	{ USB_DEVICE(USB_GIGA_VENDOR_ID, USB_4175_PRODUCT_ID) },
+	{ USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX303_PRODUCT_ID) },
+	{ USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX353_PRODUCT_ID) },
+	{ } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, gigaset_table);
+
+/* Get a minor range for your devices from the usb maintainer */
+#define USB_SKEL_MINOR_BASE	200
+
+/*======================= local function prototypes =============================*/
+
+/* This function is called if a new device is connected to the USB port. It
+ * checks whether this new device belongs to this driver.
+ */
+static int gigaset_probe(struct usb_interface *interface,
+			 const struct usb_device_id *id);
+
+/* Function will be called if the device is unplugged */
+static void gigaset_disconnect(struct usb_interface *interface);
+
+
+/*==============================================================================*/
+
+struct bas_cardstate {
+	struct usb_device       *udev;		/* USB device pointer */
+	struct usb_interface    *interface;	/* interface for this device */
+	unsigned char		minor;		/* starting minor number */
+
+	struct urb              *urb_ctrl;	/* control pipe default URB */
+	struct usb_ctrlrequest	dr_ctrl;
+	struct timer_list	timer_ctrl;	/* control request timeout */
+
+	struct timer_list	timer_atrdy;	/* AT command ready timeout */
+	struct urb              *urb_cmd_out;	/* for sending AT commands */
+	struct usb_ctrlrequest	dr_cmd_out;
+	int			retry_cmd_out;
+
+	struct urb              *urb_cmd_in;	/* for receiving AT replies */
+	struct usb_ctrlrequest	dr_cmd_in;
+	struct timer_list	timer_cmd_in;	/* receive request timeout */
+	unsigned char           *rcvbuf;	/* AT reply receive buffer */
+
+	struct urb              *urb_int_in;	/* URB for interrupt pipe */
+	unsigned char		int_in_buf[3];
+
+	spinlock_t		lock;		/* locks all following */
+	atomic_t		basstate;	/* bitmap (BS_*) */
+	int			pending;	/* uncompleted base request */
+	int			rcvbuf_size;	/* size of AT receive buffer */
+						/* 0: no receive in progress */
+	int			retry_cmd_in;	/* receive req retry count */
+};
+
+/* status of direct USB connection to 307x base (bits in basstate) */
+#define BS_ATOPEN	0x001
+#define BS_B1OPEN	0x002
+#define BS_B2OPEN	0x004
+#define BS_ATREADY	0x008
+#define BS_INIT		0x010
+#define BS_ATTIMER	0x020
+
+
+static struct gigaset_driver *driver = NULL;
+static struct cardstate *cardstate = NULL;
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver gigaset_usb_driver = {
+	.name =         GIGASET_MODULENAME,
+	.probe =        gigaset_probe,
+	.disconnect =   gigaset_disconnect,
+	.id_table =     gigaset_table,
+};
+
+/* get message text for USB status code
+ */
+static char *get_usb_statmsg(int status)
+{
+	static char unkmsg[28];
+
+	switch (status) {
+	case 0:
+		return "success";
+	case -ENOENT:
+		return "canceled";
+	case -ECONNRESET:
+		return "canceled (async)";
+	case -EINPROGRESS:
+		return "pending";
+	case -EPROTO:
+		return "bit stuffing or unknown USB error";
+	case -EILSEQ:
+		return "Illegal byte sequence (CRC mismatch)";
+	case -EPIPE:
+		return "babble detect or endpoint stalled";
+	case -ENOSR:
+		return "buffer error";
+	case -ETIMEDOUT:
+		return "timed out";
+	case -ENODEV:
+		return "device not present";
+	case -EREMOTEIO:
+		return "short packet detected";
+	case -EXDEV:
+		return "partial isochronous transfer";
+	case -EINVAL:
+		return "invalid argument";
+	case -ENXIO:
+		return "URB already queued";
+	case -EAGAIN:
+		return "isochronous start frame too early or too much scheduled";
+	case -EFBIG:
+		return "too many isochronous frames requested";
+	case -EMSGSIZE:
+		return "endpoint message size zero";
+	case -ESHUTDOWN:
+		return "endpoint shutdown";
+	case -EBUSY:
+		return "another request pending";
+	default:
+		snprintf(unkmsg, sizeof(unkmsg), "unknown error %d", status);
+		return unkmsg;
+	}
+}
+
+/* usb_pipetype_str
+ * retrieve string representation of USB pipe type
+ */
+static inline char *usb_pipetype_str(int pipe)
+{
+	if (usb_pipeisoc(pipe))
+		return "Isoc";
+	if (usb_pipeint(pipe))
+		return "Int";
+	if (usb_pipecontrol(pipe))
+		return "Ctrl";
+	if (usb_pipebulk(pipe))
+		return "Bulk";
+	return "?";
+}
+
+/* dump_urb
+ * write content of URB to syslog for debugging
+ */
+static inline void dump_urb(enum debuglevel level, const char *tag,
+                            struct urb *urb)
+{
+#ifdef CONFIG_GIGASET_DEBUG
+	int i;
+	IFNULLRET(tag);
+	dbg(level, "%s urb(0x%08lx)->{", tag, (unsigned long) urb);
+	if (urb) {
+		dbg(level,
+		    "  dev=0x%08lx, pipe=%s:EP%d/DV%d:%s, "
+		    "status=%d, hcpriv=0x%08lx, transfer_flags=0x%x,",
+		    (unsigned long) urb->dev,
+		    usb_pipetype_str(urb->pipe),
+		    usb_pipeendpoint(urb->pipe), usb_pipedevice(urb->pipe),
+		    usb_pipein(urb->pipe) ? "in" : "out",
+		    urb->status, (unsigned long) urb->hcpriv,
+		    urb->transfer_flags);
+		dbg(level,
+		    "  transfer_buffer=0x%08lx[%d], actual_length=%d, "
+		    "bandwidth=%d, setup_packet=0x%08lx,",
+		    (unsigned long) urb->transfer_buffer,
+		    urb->transfer_buffer_length, urb->actual_length,
+		    urb->bandwidth, (unsigned long) urb->setup_packet);
+		dbg(level,
+		    "  start_frame=%d, number_of_packets=%d, interval=%d, "
+		    "error_count=%d,",
+		    urb->start_frame, urb->number_of_packets, urb->interval,
+		    urb->error_count);
+		dbg(level,
+		    "  context=0x%08lx, complete=0x%08lx, iso_frame_desc[]={",
+		    (unsigned long) urb->context,
+		    (unsigned long) urb->complete);
+		for (i = 0; i < urb->number_of_packets; i++) {
+			struct usb_iso_packet_descriptor *pifd = &urb->iso_frame_desc[i];
+			dbg(level,
+			    "    {offset=%u, length=%u, actual_length=%u, "
+			    "status=%u}",
+			    pifd->offset, pifd->length, pifd->actual_length,
+			    pifd->status);
+		}
+	}
+	dbg(level, "}}");
+#endif
+}
+
+/* read/set modem control bits etc. (m10x only) */
+static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
+                                  unsigned new_state)
+{
+	return -EINVAL;
+}
+
+static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
+{
+	return -EINVAL;
+}
+
+static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
+{
+	return -EINVAL;
+}
+
+/* error_hangup
+ * hang up any existing connection because of an unrecoverable error
+ * This function may be called from any context and takes care of scheduling
+ * the necessary actions for execution outside of interrupt context.
+ * argument:
+ *	B channel control structure
+ */
+static inline void error_hangup(struct bc_state *bcs)
+{
+	struct cardstate *cs = bcs->cs;
+
+	dbg(DEBUG_ANY,
+	    "%s: scheduling HUP for channel %d", __func__, bcs->channel);
+
+	if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) {
+		//FIXME what should we do?
+		return;
+	}
+
+	gigaset_schedule_event(cs);
+}
+
+/* error_reset
+ * reset Gigaset device because of an unrecoverable error
+ * This function may be called from any context and takes care of scheduling
+ * the necessary actions for execution outside of interrupt context.
+ * argument:
+ *	controller state structure
+ */
+static inline void error_reset(struct cardstate *cs)
+{
+	//FIXME try to recover without bothering the user
+	err("unrecoverable error - please disconnect the Gigaset base to reset");
+}
+
+/* check_pending
+ * check for completion of pending control request
+ * parameter:
+ *	urb	USB request block of completed request
+ *		urb->context = hardware specific controller state structure
+ */
+static void check_pending(struct bas_cardstate *ucs)
+{
+	unsigned long flags;
+
+	IFNULLRET(ucs);
+	IFNULLRET(cardstate);
+
+	spin_lock_irqsave(&ucs->lock, flags);
+	switch (ucs->pending) {
+	case 0:
+		break;
+	case HD_OPEN_ATCHANNEL:
+		if (atomic_read(&ucs->basstate) & BS_ATOPEN)
+			ucs->pending = 0;
+		break;
+	case HD_OPEN_B1CHANNEL:
+		if (atomic_read(&ucs->basstate) & BS_B1OPEN)
+			ucs->pending = 0;
+		break;
+	case HD_OPEN_B2CHANNEL:
+		if (atomic_read(&ucs->basstate) & BS_B2OPEN)
+			ucs->pending = 0;
+		break;
+	case HD_CLOSE_ATCHANNEL:
+		if (!(atomic_read(&ucs->basstate) & BS_ATOPEN))
+			ucs->pending = 0;
+		//wake_up_interruptible(cs->initwait);
+		//FIXME need own wait queue?
+		break;
+	case HD_CLOSE_B1CHANNEL:
+		if (!(atomic_read(&ucs->basstate) & BS_B1OPEN))
+			ucs->pending = 0;
+		break;
+	case HD_CLOSE_B2CHANNEL:
+		if (!(atomic_read(&ucs->basstate) & BS_B2OPEN))
+			ucs->pending = 0;
+		break;
+	case HD_DEVICE_INIT_ACK:		/* no reply expected */
+		ucs->pending = 0;
+		break;
+	/* HD_READ_ATMESSAGE, HD_WRITE_ATMESSAGE, HD_RESET_INTERRUPTPIPE
+	 * are handled separately and should never end up here
+	 */
+	default:
+		warn("unknown pending request 0x%02x cleared", ucs->pending);
+		ucs->pending = 0;
+	}
+
+	if (!ucs->pending)
+		del_timer(&ucs->timer_ctrl);
+
+	spin_unlock_irqrestore(&ucs->lock, flags);
+}
+
+/* cmd_in_timeout
+ * timeout routine for command input request
+ * argument:
+ *	controller state structure
+ */
+static void cmd_in_timeout(unsigned long data)
+{
+	struct cardstate *cs = (struct cardstate *) data;
+	struct bas_cardstate *ucs;
+	unsigned long flags;
+
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	spin_lock_irqsave(&cs->lock, flags);
+	if (!atomic_read(&cs->connected)) {
+		dbg(DEBUG_USBREQ, "%s: disconnected", __func__);
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return;
+	}
+	if (!ucs->rcvbuf_size) {
+		dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__);
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&cs->lock, flags);
+
+	err("timeout reading AT response");
+	error_reset(cs);	//FIXME retry?
+}
+
+
+static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs);
+
+/* atread_submit
+ * submit an HD_READ_ATMESSAGE command URB
+ * parameters:
+ *	cs	controller state structure
+ *	timeout	timeout in 1/10 sec., 0: none
+ * return value:
+ *	0 on success
+ *	-EINVAL if a NULL pointer is encountered somewhere
+ *	-EBUSY if another request is pending
+ *	any URB submission error code
+ */
+static int atread_submit(struct cardstate *cs, int timeout)
+{
+	struct bas_cardstate *ucs;
+	int ret;
+
+	IFNULLRETVAL(cs, -EINVAL);
+	ucs = cs->hw.bas;
+	IFNULLRETVAL(ucs, -EINVAL);
+	IFNULLRETVAL(ucs->urb_cmd_in, -EINVAL);
+
+	dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)", ucs->rcvbuf_size);
+
+	if (ucs->urb_cmd_in->status == -EINPROGRESS) {
+		err("could not submit HD_READ_ATMESSAGE: URB busy");
+		return -EBUSY;
+	}
+
+	ucs->dr_cmd_in.bRequestType = IN_VENDOR_REQ;
+	ucs->dr_cmd_in.bRequest = HD_READ_ATMESSAGE;
+	ucs->dr_cmd_in.wValue = 0;
+	ucs->dr_cmd_in.wIndex = 0;
+	ucs->dr_cmd_in.wLength = cpu_to_le16(ucs->rcvbuf_size);
+	usb_fill_control_urb(ucs->urb_cmd_in, ucs->udev,
+	                     usb_rcvctrlpipe(ucs->udev, 0),
+	                     (unsigned char*) & ucs->dr_cmd_in,
+	                     ucs->rcvbuf, ucs->rcvbuf_size,
+	                     read_ctrl_callback, cs->inbuf);
+
+	if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) {
+		err("could not submit HD_READ_ATMESSAGE: %s",
+		    get_usb_statmsg(ret));
+		return ret;
+	}
+
+	if (timeout > 0) {
+		dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout);
+		ucs->timer_cmd_in.expires = jiffies + timeout * HZ / 10;
+		ucs->timer_cmd_in.data = (unsigned long) cs;
+		ucs->timer_cmd_in.function = cmd_in_timeout;
+		add_timer(&ucs->timer_cmd_in);
+	}
+	return 0;
+}
+
+static void stopurbs(struct bas_bc_state *);
+static int start_cbsend(struct cardstate *);
+
+/* set/clear bits in base connection state
+ */
+inline static void update_basstate(struct bas_cardstate *ucs,
+				   int set, int clear)
+{
+	unsigned long flags;
+	int state;
+
+	spin_lock_irqsave(&ucs->lock, flags);
+	state = atomic_read(&ucs->basstate);
+	state &= ~clear;
+	state |= set;
+	atomic_set(&ucs->basstate, state);
+	spin_unlock_irqrestore(&ucs->lock, flags);
+}
+
+
+/* read_int_callback
+ * USB completion handler for interrupt pipe input
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ *	urb	USB request block
+ *		urb->context = controller state structure
+ */
+static void read_int_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct cardstate *cs;
+	struct bas_cardstate *ucs;
+	struct bc_state *bcs;
+	unsigned long flags;
+	int status;
+	unsigned l;
+	int channel;
+
+	IFNULLRET(urb);
+	cs = (struct cardstate *) urb->context;
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	if (unlikely(!atomic_read(&cs->connected))) {
+		warn("%s: disconnected", __func__);
+		return;
+	}
+
+	switch (urb->status) {
+	case 0:			/* success */
+		break;
+	case -ENOENT:			/* canceled */
+	case -ECONNRESET:		/* canceled (async) */
+	case -EINPROGRESS:		/* pending */
+		/* ignore silently */
+		dbg(DEBUG_USBREQ,
+		    "%s: %s", __func__, get_usb_statmsg(urb->status));
+		return;
+	default:		/* severe trouble */
+		warn("interrupt read: %s", get_usb_statmsg(urb->status));
+		//FIXME corrective action? resubmission always ok?
+		goto resubmit;
+	}
+
+	l = (unsigned) ucs->int_in_buf[1] +
+	    (((unsigned) ucs->int_in_buf[2]) << 8);
+
+	dbg(DEBUG_USBREQ,
+	    "<-------%d: 0x%02x (%u [0x%02x 0x%02x])", urb->actual_length,
+	    (int)ucs->int_in_buf[0], l,
+	    (int)ucs->int_in_buf[1], (int)ucs->int_in_buf[2]);
+
+	channel = 0;
+
+	switch (ucs->int_in_buf[0]) {
+	case HD_DEVICE_INIT_OK:
+		update_basstate(ucs, BS_INIT, 0);
+		break;
+
+	case HD_READY_SEND_ATDATA:
+		del_timer(&ucs->timer_atrdy);
+		update_basstate(ucs, BS_ATREADY, BS_ATTIMER);
+		start_cbsend(cs);
+		break;
+
+	case HD_OPEN_B2CHANNEL_ACK:
+		++channel;
+	case HD_OPEN_B1CHANNEL_ACK:
+		bcs = cs->bcs + channel;
+		update_basstate(ucs, BS_B1OPEN << channel, 0);
+		gigaset_bchannel_up(bcs);
+		break;
+
+	case HD_OPEN_ATCHANNEL_ACK:
+		update_basstate(ucs, BS_ATOPEN, 0);
+		start_cbsend(cs);
+		break;
+
+	case HD_CLOSE_B2CHANNEL_ACK:
+		++channel;
+	case HD_CLOSE_B1CHANNEL_ACK:
+		bcs = cs->bcs + channel;
+		update_basstate(ucs, 0, BS_B1OPEN << channel);
+		stopurbs(bcs->hw.bas);
+		gigaset_bchannel_down(bcs);
+		break;
+
+	case HD_CLOSE_ATCHANNEL_ACK:
+		update_basstate(ucs, 0, BS_ATOPEN);
+		break;
+
+	case HD_B2_FLOW_CONTROL:
+		++channel;
+	case HD_B1_FLOW_CONTROL:
+		bcs = cs->bcs + channel;
+		atomic_add((l - BAS_NORMFRAME) * BAS_CORRFRAMES,
+		           &bcs->hw.bas->corrbytes);
+		dbg(DEBUG_ISO,
+		    "Flow control (channel %d, sub %d): 0x%02x => %d",
+		    channel, bcs->hw.bas->numsub, l,
+		    atomic_read(&bcs->hw.bas->corrbytes));
+		break;
+
+	case HD_RECEIVEATDATA_ACK:	/* AT response ready to be received */
+		if (!l) {
+			warn("HD_RECEIVEATDATA_ACK with length 0 ignored");
+			break;
+		}
+		spin_lock_irqsave(&cs->lock, flags);
+		if (ucs->rcvbuf_size) {
+			spin_unlock_irqrestore(&cs->lock, flags);
+			err("receive AT data overrun, %d bytes lost", l);
+			error_reset(cs);	//FIXME reschedule
+			break;
+		}
+		if ((ucs->rcvbuf = kmalloc(l, GFP_ATOMIC)) == NULL) {
+			spin_unlock_irqrestore(&cs->lock, flags);
+			err("%s: out of memory, %d bytes lost", __func__, l);
+			error_reset(cs);	//FIXME reschedule
+			break;
+		}
+		ucs->rcvbuf_size = l;
+		ucs->retry_cmd_in = 0;
+		if ((status = atread_submit(cs, BAS_TIMEOUT)) < 0) {
+			kfree(ucs->rcvbuf);
+			ucs->rcvbuf = NULL;
+			ucs->rcvbuf_size = 0;
+			error_reset(cs);	//FIXME reschedule
+		}
+		spin_unlock_irqrestore(&cs->lock, flags);
+		break;
+
+	case HD_RESET_INTERRUPT_PIPE_ACK:
+		dbg(DEBUG_USBREQ, "HD_RESET_INTERRUPT_PIPE_ACK");
+		break;
+
+	case HD_SUSPEND_END:
+		dbg(DEBUG_USBREQ, "HD_SUSPEND_END");
+		break;
+
+	default:
+		warn("unknown Gigaset signal 0x%02x (%u) ignored",
+		     (int) ucs->int_in_buf[0], l);
+	}
+
+	check_pending(ucs);
+
+resubmit:
+	status = usb_submit_urb(urb, SLAB_ATOMIC);
+	if (unlikely(status)) {
+		err("could not resubmit interrupt URB: %s",
+		    get_usb_statmsg(status));
+		error_reset(cs);
+	}
+}
+
+/* read_ctrl_callback
+ * USB completion handler for control pipe input
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ *	urb	USB request block
+ *		urb->context = inbuf structure for controller state
+ */
+static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct cardstate *cs;
+	struct bas_cardstate *ucs;
+	unsigned numbytes;
+	unsigned long flags;
+	struct inbuf_t *inbuf;
+	int have_data = 0;
+
+	IFNULLRET(urb);
+	inbuf = (struct inbuf_t *) urb->context;
+	IFNULLRET(inbuf);
+	cs = inbuf->cs;
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	spin_lock_irqsave(&cs->lock, flags);
+	if (!atomic_read(&cs->connected)) {
+		warn("%s: disconnected", __func__);
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return;
+	}
+
+	if (!ucs->rcvbuf_size) {
+		warn("%s: no receive in progress", __func__);
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return;
+	}
+
+	del_timer(&ucs->timer_cmd_in);
+
+	switch (urb->status) {
+	case 0:				/* normal completion */
+		numbytes = urb->actual_length;
+		if (unlikely(numbytes == 0)) {
+			warn("control read: empty block received");
+			goto retry;
+		}
+		if (unlikely(numbytes != ucs->rcvbuf_size)) {
+			warn("control read: received %d chars, expected %d",
+			     numbytes, ucs->rcvbuf_size);
+			if (numbytes > ucs->rcvbuf_size)
+				numbytes = ucs->rcvbuf_size;
+		}
+
+		/* copy received bytes to inbuf */
+		have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes);
+
+		if (unlikely(numbytes < ucs->rcvbuf_size)) {
+			/* incomplete - resubmit for remaining bytes */
+			ucs->rcvbuf_size -= numbytes;
+			ucs->retry_cmd_in = 0;
+			goto retry;
+		}
+		break;
+
+	case -ENOENT:			/* canceled */
+	case -ECONNRESET:		/* canceled (async) */
+	case -EINPROGRESS:		/* pending */
+		/* no action necessary */
+		dbg(DEBUG_USBREQ,
+		    "%s: %s", __func__, get_usb_statmsg(urb->status));
+		break;
+
+	default:			/* severe trouble */
+		warn("control read: %s", get_usb_statmsg(urb->status));
+	retry:
+		if (ucs->retry_cmd_in++ < BAS_RETRY) {
+			notice("control read: retry %d", ucs->retry_cmd_in);
+			if (atread_submit(cs, BAS_TIMEOUT) >= 0) {
+				/* resubmitted - bypass regular exit block */
+				spin_unlock_irqrestore(&cs->lock, flags);
+				return;
+			}
+		} else {
+			err("control read: giving up after %d tries",
+			    ucs->retry_cmd_in);
+		}
+		error_reset(cs);
+	}
+
+	kfree(ucs->rcvbuf);
+	ucs->rcvbuf = NULL;
+	ucs->rcvbuf_size = 0;
+	spin_unlock_irqrestore(&cs->lock, flags);
+	if (have_data) {
+		dbg(DEBUG_INTR, "%s-->BH", __func__);
+		gigaset_schedule_event(cs);
+	}
+}
+
+/* read_iso_callback
+ * USB completion handler for B channel isochronous input
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ *	urb	USB request block of completed request
+ *		urb->context = bc_state structure
+ */
+static void read_iso_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct bc_state *bcs;
+	struct bas_bc_state *ubc;
+	unsigned long flags;
+	int i, rc;
+
+	IFNULLRET(urb);
+	IFNULLRET(urb->context);
+	IFNULLRET(cardstate);
+
+	/* status codes not worth bothering the tasklet with */
+	if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET ||
+	             urb->status == -EINPROGRESS)) {
+		dbg(DEBUG_ISO,
+		    "%s: %s", __func__, get_usb_statmsg(urb->status));
+		return;
+	}
+
+	bcs = (struct bc_state *) urb->context;
+	ubc = bcs->hw.bas;
+	IFNULLRET(ubc);
+
+	spin_lock_irqsave(&ubc->isoinlock, flags);
+	if (likely(ubc->isoindone == NULL)) {
+		/* pass URB to tasklet */
+		ubc->isoindone = urb;
+		tasklet_schedule(&ubc->rcvd_tasklet);
+	} else {
+		/* tasklet still busy, drop data and resubmit URB */
+		ubc->loststatus = urb->status;
+		for (i = 0; i < BAS_NUMFRAMES; i++) {
+			ubc->isoinlost += urb->iso_frame_desc[i].actual_length;
+			if (unlikely(urb->iso_frame_desc[i].status != 0 &&
+				     urb->iso_frame_desc[i].status != -EINPROGRESS)) {
+				ubc->loststatus = urb->iso_frame_desc[i].status;
+			}
+			urb->iso_frame_desc[i].status = 0;
+			urb->iso_frame_desc[i].actual_length = 0;
+		}
+		if (likely(atomic_read(&ubc->running))) {
+			urb->dev = bcs->cs->hw.bas->udev;	/* clobbered by USB subsystem */
+			urb->transfer_flags = URB_ISO_ASAP;
+			urb->number_of_packets = BAS_NUMFRAMES;
+			dbg(DEBUG_ISO, "%s: isoc read overrun/resubmit", __func__);
+			rc = usb_submit_urb(urb, SLAB_ATOMIC);
+			if (unlikely(rc != 0)) {
+				err("could not resubmit isochronous read URB: %s",
+				    get_usb_statmsg(rc));
+				dump_urb(DEBUG_ISO, "isoc read", urb);
+				error_hangup(bcs);
+			}
+		}
+	}
+	spin_unlock_irqrestore(&ubc->isoinlock, flags);
+}
+
+/* write_iso_callback
+ * USB completion handler for B channel isochronous output
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ *	urb	USB request block of completed request
+ *		urb->context = isow_urbctx_t structure
+ */
+static void write_iso_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct isow_urbctx_t *ucx;
+	struct bas_bc_state *ubc;
+	unsigned long flags;
+
+	IFNULLRET(urb);
+	IFNULLRET(urb->context);
+	IFNULLRET(cardstate);
+
+	/* status codes not worth bothering the tasklet with */
+	if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET ||
+	             urb->status == -EINPROGRESS)) {
+		dbg(DEBUG_ISO,
+		    "%s: %s", __func__, get_usb_statmsg(urb->status));
+		return;
+	}
+
+	/* pass URB context to tasklet */
+	ucx = (struct isow_urbctx_t *) urb->context;
+	IFNULLRET(ucx->bcs);
+	ubc = ucx->bcs->hw.bas;
+	IFNULLRET(ubc);
+
+	spin_lock_irqsave(&ubc->isooutlock, flags);
+	ubc->isooutovfl = ubc->isooutdone;
+	ubc->isooutdone = ucx;
+	spin_unlock_irqrestore(&ubc->isooutlock, flags);
+	tasklet_schedule(&ubc->sent_tasklet);
+}
+
+/* starturbs
+ * prepare and submit USB request blocks for isochronous input and output
+ * argument:
+ *	B channel control structure
+ * return value:
+ *	0 on success
+ *	< 0 on error (no URBs submitted)
+ */
+static int starturbs(struct bc_state *bcs)
+{
+	struct urb *urb;
+	struct bas_bc_state *ubc;
+	int j, k;
+	int rc;
+
+	IFNULLRETVAL(bcs, -EFAULT);
+	ubc = bcs->hw.bas;
+	IFNULLRETVAL(ubc, -EFAULT);
+
+	/* initialize L2 reception */
+	if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
+		bcs->inputstate |= INS_flag_hunt;
+
+	/* submit all isochronous input URBs */
+	atomic_set(&ubc->running, 1);
+	for (k = 0; k < BAS_INURBS; k++) {
+		urb = ubc->isoinurbs[k];
+		if (!urb) {
+			err("isoinurbs[%d]==NULL", k);
+			rc = -EFAULT;
+			goto error;
+		}
+
+		urb->dev = bcs->cs->hw.bas->udev;
+		urb->pipe = usb_rcvisocpipe(urb->dev, 3 + 2 * bcs->channel);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = ubc->isoinbuf + k * BAS_INBUFSIZE;
+		urb->transfer_buffer_length = BAS_INBUFSIZE;
+		urb->number_of_packets = BAS_NUMFRAMES;
+		urb->interval = BAS_FRAMETIME;
+		urb->complete = read_iso_callback;
+		urb->context = bcs;
+		for (j = 0; j < BAS_NUMFRAMES; j++) {
+			urb->iso_frame_desc[j].offset = j * BAS_MAXFRAME;
+			urb->iso_frame_desc[j].length = BAS_MAXFRAME;
+			urb->iso_frame_desc[j].status = 0;
+			urb->iso_frame_desc[j].actual_length = 0;
+		}
+
+		dump_urb(DEBUG_ISO, "Initial isoc read", urb);
+		if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) {
+			err("could not submit isochronous read URB %d: %s",
+			    k, get_usb_statmsg(rc));
+			goto error;
+		}
+	}
+
+	/* initialize L2 transmission */
+	gigaset_isowbuf_init(ubc->isooutbuf, PPP_FLAG);
+
+	/* set up isochronous output URBs for flag idling */
+	for (k = 0; k < BAS_OUTURBS; ++k) {
+		urb = ubc->isoouturbs[k].urb;
+		if (!urb) {
+			err("isoouturbs[%d].urb==NULL", k);
+			rc = -EFAULT;
+			goto error;
+		}
+		urb->dev = bcs->cs->hw.bas->udev;
+		urb->pipe = usb_sndisocpipe(urb->dev, 4 + 2 * bcs->channel);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = ubc->isooutbuf->data;
+		urb->transfer_buffer_length = sizeof(ubc->isooutbuf->data);
+		urb->number_of_packets = BAS_NUMFRAMES;
+		urb->interval = BAS_FRAMETIME;
+		urb->complete = write_iso_callback;
+		urb->context = &ubc->isoouturbs[k];
+		for (j = 0; j < BAS_NUMFRAMES; ++j) {
+			urb->iso_frame_desc[j].offset = BAS_OUTBUFSIZE;
+			urb->iso_frame_desc[j].length = BAS_NORMFRAME;
+			urb->iso_frame_desc[j].status = 0;
+			urb->iso_frame_desc[j].actual_length = 0;
+		}
+		ubc->isoouturbs[k].limit = -1;
+	}
+
+	/* submit two URBs, keep third one */
+	for (k = 0; k < 2; ++k) {
+		dump_urb(DEBUG_ISO, "Initial isoc write", urb);
+		rc = usb_submit_urb(ubc->isoouturbs[k].urb, SLAB_ATOMIC);
+		if (rc != 0) {
+			err("could not submit isochronous write URB %d: %s",
+			    k, get_usb_statmsg(rc));
+			goto error;
+		}
+	}
+	dump_urb(DEBUG_ISO, "Initial isoc write (free)", urb);
+	ubc->isooutfree = &ubc->isoouturbs[2];
+	ubc->isooutdone = ubc->isooutovfl = NULL;
+	return 0;
+ error:
+	stopurbs(ubc);
+	return rc;
+}
+
+/* stopurbs
+ * cancel the USB request blocks for isochronous input and output
+ * errors are silently ignored
+ * argument:
+ *	B channel control structure
+ */
+static void stopurbs(struct bas_bc_state *ubc)
+{
+	int k, rc;
+
+	IFNULLRET(ubc);
+
+	atomic_set(&ubc->running, 0);
+
+	for (k = 0; k < BAS_INURBS; ++k) {
+		rc = usb_unlink_urb(ubc->isoinurbs[k]);
+		dbg(DEBUG_ISO, "%s: isoc input URB %d unlinked, result = %d",
+		    __func__, k, rc);
+	}
+
+	for (k = 0; k < BAS_OUTURBS; ++k) {
+		rc = usb_unlink_urb(ubc->isoouturbs[k].urb);
+		dbg(DEBUG_ISO, "%s: isoc output URB %d unlinked, result = %d",
+		    __func__, k, rc);
+	}
+}
+
+/* Isochronous Write - Bottom Half */
+/* =============================== */
+
+/* submit_iso_write_urb
+ * fill and submit the next isochronous write URB
+ * parameters:
+ *	bcs	B channel state structure
+ * return value:
+ *	number of frames submitted in URB
+ *	0 if URB not submitted because no data available (isooutbuf busy)
+ *	error code < 0 on error
+ */
+static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
+{
+	struct urb *urb;
+	struct bas_bc_state *ubc;
+	struct usb_iso_packet_descriptor *ifd;
+	int corrbytes, nframe, rc;
+
+	IFNULLRETVAL(ucx, -EFAULT);
+	urb = ucx->urb;
+	IFNULLRETVAL(urb, -EFAULT);
+	IFNULLRETVAL(ucx->bcs, -EFAULT);
+	ubc = ucx->bcs->hw.bas;
+	IFNULLRETVAL(ubc, -EFAULT);
+
+	urb->dev = ucx->bcs->cs->hw.bas->udev;	/* clobbered by USB subsystem */
+	urb->transfer_flags = URB_ISO_ASAP;
+	urb->transfer_buffer = ubc->isooutbuf->data;
+	urb->transfer_buffer_length = sizeof(ubc->isooutbuf->data);
+
+	for (nframe = 0; nframe < BAS_NUMFRAMES; nframe++) {
+		ifd = &urb->iso_frame_desc[nframe];
+
+		/* compute frame length according to flow control */
+		ifd->length = BAS_NORMFRAME;
+		if ((corrbytes = atomic_read(&ubc->corrbytes)) != 0) {
+			dbg(DEBUG_ISO, "%s: corrbytes=%d", __func__, corrbytes);
+			if (corrbytes > BAS_HIGHFRAME - BAS_NORMFRAME)
+				corrbytes = BAS_HIGHFRAME - BAS_NORMFRAME;
+			else if (corrbytes < BAS_LOWFRAME - BAS_NORMFRAME)
+				corrbytes = BAS_LOWFRAME - BAS_NORMFRAME;
+			ifd->length += corrbytes;
+			atomic_add(-corrbytes, &ubc->corrbytes);
+		}
+		//dbg(DEBUG_ISO, "%s: frame %d length=%d", __func__, nframe, ifd->length);
+
+		/* retrieve block of data to send */
+		ifd->offset = gigaset_isowbuf_getbytes(ubc->isooutbuf, ifd->length);
+		if (ifd->offset < 0) {
+			if (ifd->offset == -EBUSY) {
+				dbg(DEBUG_ISO, "%s: buffer busy at frame %d",
+				    __func__, nframe);
+				/* tasklet will be restarted from gigaset_send_skb() */
+			} else {
+				err("%s: buffer error %d at frame %d",
+				    __func__, ifd->offset, nframe);
+				return ifd->offset;
+			}
+			break;
+		}
+		ucx->limit = atomic_read(&ubc->isooutbuf->nextread);
+		ifd->status = 0;
+		ifd->actual_length = 0;
+	}
+	if ((urb->number_of_packets = nframe) > 0) {
+		if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) {
+			err("could not submit isochronous write URB: %s",
+			    get_usb_statmsg(rc));
+			dump_urb(DEBUG_ISO, "isoc write", urb);
+			return rc;
+		}
+		++ubc->numsub;
+	}
+	return nframe;
+}
+
+/* write_iso_tasklet
+ * tasklet scheduled when an isochronous output URB from the Gigaset device
+ * has completed
+ * parameter:
+ *	data	B channel state structure
+ */
+static void write_iso_tasklet(unsigned long data)
+{
+	struct bc_state *bcs;
+	struct bas_bc_state *ubc;
+	struct cardstate *cs;
+	struct isow_urbctx_t *done, *next, *ovfl;
+	struct urb *urb;
+	struct usb_iso_packet_descriptor *ifd;
+	int offset;
+	unsigned long flags;
+	int i;
+	struct sk_buff *skb;
+	int len;
+
+	bcs = (struct bc_state *) data;
+	IFNULLRET(bcs);
+	ubc = bcs->hw.bas;
+	IFNULLRET(ubc);
+	cs = bcs->cs;
+	IFNULLRET(cs);
+
+	/* loop while completed URBs arrive in time */
+	for (;;) {
+		if (unlikely(!atomic_read(&cs->connected))) {
+			warn("%s: disconnected", __func__);
+			return;
+		}
+
+		if (unlikely(!(atomic_read(&ubc->running)))) {
+			dbg(DEBUG_ISO, "%s: not running", __func__);
+			return;
+		}
+
+		/* retrieve completed URBs */
+		spin_lock_irqsave(&ubc->isooutlock, flags);
+		done = ubc->isooutdone;
+		ubc->isooutdone = NULL;
+		ovfl = ubc->isooutovfl;
+		ubc->isooutovfl = NULL;
+		spin_unlock_irqrestore(&ubc->isooutlock, flags);
+		if (ovfl) {
+			err("isochronous write buffer underrun - buy a faster machine :-)");
+			error_hangup(bcs);
+			break;
+		}
+		if (!done)
+			break;
+
+		/* submit free URB if available */
+		spin_lock_irqsave(&ubc->isooutlock, flags);
+		next = ubc->isooutfree;
+		ubc->isooutfree = NULL;
+		spin_unlock_irqrestore(&ubc->isooutlock, flags);
+		if (next) {
+			if (submit_iso_write_urb(next) <= 0) {
+				/* could not submit URB, put it back */
+				spin_lock_irqsave(&ubc->isooutlock, flags);
+				if (ubc->isooutfree == NULL) {
+					ubc->isooutfree = next;
+					next = NULL;
+				}
+				spin_unlock_irqrestore(&ubc->isooutlock, flags);
+				if (next) {
+					/* couldn't put it back */
+					err("losing isochronous write URB");
+					error_hangup(bcs);
+				}
+			}
+		}
+
+		/* process completed URB */
+		urb = done->urb;
+		switch (urb->status) {
+		case 0:				/* normal completion */
+			break;
+		case -EXDEV:			/* inspect individual frames */
+			/* assumptions (for lack of documentation):
+			 * - actual_length bytes of the frame in error are successfully sent
+			 * - all following frames are not sent at all
+			 */
+			dbg(DEBUG_ISO, "%s: URB partially completed", __func__);
+			offset = done->limit;	/* just in case */
+			for (i = 0; i < BAS_NUMFRAMES; i++) {
+				ifd = &urb->iso_frame_desc[i];
+				if (ifd->status ||
+				    ifd->actual_length != ifd->length) {
+					warn("isochronous write: frame %d: %s, "
+					     "only %d of %d bytes sent",
+					     i, get_usb_statmsg(ifd->status),
+					     ifd->actual_length, ifd->length);
+					offset = (ifd->offset +
+					          ifd->actual_length)
+					         % BAS_OUTBUFSIZE;
+					break;
+				}
+			}
+#ifdef CONFIG_GIGASET_DEBUG
+			/* check assumption on remaining frames */
+			for (; i < BAS_NUMFRAMES; i++) {
+				ifd = &urb->iso_frame_desc[i];
+				if (ifd->status != -EINPROGRESS
+				    || ifd->actual_length != 0) {
+					warn("isochronous write: frame %d: %s, "
+					     "%d of %d bytes sent",
+					     i, get_usb_statmsg(ifd->status),
+					     ifd->actual_length, ifd->length);
+					offset = (ifd->offset +
+					          ifd->actual_length)
+					         % BAS_OUTBUFSIZE;
+					break;
+				}
+			}
+#endif
+			break;
+		case -EPIPE:			//FIXME is this the code for "underrun"?
+			err("isochronous write stalled");
+			error_hangup(bcs);
+			break;
+		default:			/* severe trouble */
+			warn("isochronous write: %s",
+			     get_usb_statmsg(urb->status));
+		}
+
+		/* mark the write buffer area covered by this URB as free */
+		if (done->limit >= 0)
+			atomic_set(&ubc->isooutbuf->read, done->limit);
+
+		/* mark URB as free */
+		spin_lock_irqsave(&ubc->isooutlock, flags);
+		next = ubc->isooutfree;
+		ubc->isooutfree = done;
+		spin_unlock_irqrestore(&ubc->isooutlock, flags);
+		if (next) {
+			/* only one URB still active - resubmit one */
+			if (submit_iso_write_urb(next) <= 0) {
+				/* couldn't submit */
+				error_hangup(bcs);
+			}
+		}
+	}
+
+	/* process queued SKBs */
+	while ((skb = skb_dequeue(&bcs->squeue))) {
+		/* copy to output buffer, doing L2 encapsulation */
+		len = skb->len;
+		if (gigaset_isoc_buildframe(bcs, skb->data, len) == -EAGAIN) {
+			/* insufficient buffer space, push back onto queue */
+			skb_queue_head(&bcs->squeue, skb);
+			dbg(DEBUG_ISO, "%s: skb requeued, qlen=%d",
+			    __func__, skb_queue_len(&bcs->squeue));
+			break;
+		}
+		skb_pull(skb, len);
+		gigaset_skb_sent(bcs, skb);
+		dev_kfree_skb_any(skb);
+	}
+}
+
+/* Isochronous Read - Bottom Half */
+/* ============================== */
+
+/* read_iso_tasklet
+ * tasklet scheduled when an isochronous input URB from the Gigaset device
+ * has completed
+ * parameter:
+ *	data	B channel state structure
+ */
+static void read_iso_tasklet(unsigned long data)
+{
+	struct bc_state *bcs;
+	struct bas_bc_state *ubc;
+	struct cardstate *cs;
+	struct urb *urb;
+	char *rcvbuf;
+	unsigned long flags;
+	int totleft, numbytes, offset, frame, rc;
+
+	bcs = (struct bc_state *) data;
+	IFNULLRET(bcs);
+	ubc = bcs->hw.bas;
+	IFNULLRET(ubc);
+	cs = bcs->cs;
+	IFNULLRET(cs);
+
+	/* loop while more completed URBs arrive in the meantime */
+	for (;;) {
+		if (!atomic_read(&cs->connected)) {
+			warn("%s: disconnected", __func__);
+			return;
+		}
+
+		/* retrieve URB */
+		spin_lock_irqsave(&ubc->isoinlock, flags);
+		if (!(urb = ubc->isoindone)) {
+			spin_unlock_irqrestore(&ubc->isoinlock, flags);
+			return;
+		}
+		ubc->isoindone = NULL;
+		if (unlikely(ubc->loststatus != -EINPROGRESS)) {
+			warn("isochronous read overrun, dropped URB with status: %s, %d bytes lost",
+			     get_usb_statmsg(ubc->loststatus), ubc->isoinlost);
+			ubc->loststatus = -EINPROGRESS;
+		}
+		spin_unlock_irqrestore(&ubc->isoinlock, flags);
+
+		if (unlikely(!(atomic_read(&ubc->running)))) {
+			dbg(DEBUG_ISO, "%s: channel not running, dropped URB with status: %s",
+			    __func__, get_usb_statmsg(urb->status));
+			return;
+		}
+
+		switch (urb->status) {
+		case 0:				/* normal completion */
+			break;
+		case -EXDEV:			/* inspect individual frames (we do that anyway) */
+			dbg(DEBUG_ISO, "%s: URB partially completed", __func__);
+			break;
+		case -ENOENT:
+		case -ECONNRESET:
+			dbg(DEBUG_ISO, "%s: URB canceled", __func__);
+			continue;		/* -> skip */
+		case -EINPROGRESS:		/* huh? */
+			dbg(DEBUG_ISO, "%s: URB still pending", __func__);
+			continue;		/* -> skip */
+		case -EPIPE:
+			err("isochronous read stalled");
+			error_hangup(bcs);
+			continue;		/* -> skip */
+		default:			/* severe trouble */
+			warn("isochronous read: %s",
+			     get_usb_statmsg(urb->status));
+			goto error;
+		}
+
+		rcvbuf = urb->transfer_buffer;
+		totleft = urb->actual_length;
+		for (frame = 0; totleft > 0 && frame < BAS_NUMFRAMES; frame++) {
+			if (unlikely(urb->iso_frame_desc[frame].status)) {
+				warn("isochronous read: frame %d: %s",
+				     frame, get_usb_statmsg(urb->iso_frame_desc[frame].status));
+				break;
+			}
+			numbytes = urb->iso_frame_desc[frame].actual_length;
+			if (unlikely(numbytes > BAS_MAXFRAME)) {
+				warn("isochronous read: frame %d: numbytes (%d) > BAS_MAXFRAME",
+				     frame, numbytes);
+				break;
+			}
+			if (unlikely(numbytes > totleft)) {
+				warn("isochronous read: frame %d: numbytes (%d) > totleft (%d)",
+				     frame, numbytes, totleft);
+				break;
+			}
+			offset = urb->iso_frame_desc[frame].offset;
+			if (unlikely(offset + numbytes > BAS_INBUFSIZE)) {
+				warn("isochronous read: frame %d: offset (%d) + numbytes (%d) > BAS_INBUFSIZE",
+				     frame, offset, numbytes);
+				break;
+			}
+			gigaset_isoc_receive(rcvbuf + offset, numbytes, bcs);
+			totleft -= numbytes;
+		}
+		if (unlikely(totleft > 0))
+			warn("isochronous read: %d data bytes missing",
+			     totleft);
+
+	error:
+		/* URB processed, resubmit */
+		for (frame = 0; frame < BAS_NUMFRAMES; frame++) {
+			urb->iso_frame_desc[frame].status = 0;
+			urb->iso_frame_desc[frame].actual_length = 0;
+		}
+		urb->dev = bcs->cs->hw.bas->udev;	/* clobbered by USB subsystem */
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->number_of_packets = BAS_NUMFRAMES;
+		if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) {
+			err("could not resubmit isochronous read URB: %s",
+			    get_usb_statmsg(rc));
+			dump_urb(DEBUG_ISO, "resubmit iso read", urb);
+			error_hangup(bcs);
+		}
+	}
+}
+
+/* Channel Operations */
+/* ================== */
+
+/* req_timeout
+ * timeout routine for control output request
+ * argument:
+ *	B channel control structure
+ */
+static void req_timeout(unsigned long data)
+{
+	struct bc_state *bcs = (struct bc_state *) data;
+	struct bas_cardstate *ucs;
+	int pending;
+	unsigned long flags;
+
+	IFNULLRET(bcs);
+	IFNULLRET(bcs->cs);
+	ucs = bcs->cs->hw.bas;
+	IFNULLRET(ucs);
+
+	check_pending(ucs);
+
+	spin_lock_irqsave(&ucs->lock, flags);
+	pending = ucs->pending;
+	ucs->pending = 0;
+	spin_unlock_irqrestore(&ucs->lock, flags);
+
+	switch (pending) {
+	case 0:					/* no pending request */
+		dbg(DEBUG_USBREQ, "%s: no request pending", __func__);
+		break;
+
+	case HD_OPEN_ATCHANNEL:
+		err("timeout opening AT channel");
+		error_reset(bcs->cs);
+		break;
+
+	case HD_OPEN_B2CHANNEL:
+	case HD_OPEN_B1CHANNEL:
+		err("timeout opening channel %d", bcs->channel + 1);
+		error_hangup(bcs);
+		break;
+
+	case HD_CLOSE_ATCHANNEL:
+		err("timeout closing AT channel");
+		//wake_up_interruptible(cs->initwait);
+		//FIXME need own wait queue?
+		break;
+
+	case HD_CLOSE_B2CHANNEL:
+	case HD_CLOSE_B1CHANNEL:
+		err("timeout closing channel %d", bcs->channel + 1);
+		break;
+
+	default:
+		warn("request 0x%02x timed out, clearing", pending);
+	}
+}
+
+/* write_ctrl_callback
+ * USB completion handler for control pipe output
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ *	urb	USB request block of completed request
+ *		urb->context = hardware specific controller state structure
+ */
+static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct bas_cardstate *ucs;
+	unsigned long flags;
+
+	IFNULLRET(urb);
+	IFNULLRET(urb->context);
+	IFNULLRET(cardstate);
+
+	ucs = (struct bas_cardstate *) urb->context;
+	spin_lock_irqsave(&ucs->lock, flags);
+	if (urb->status && ucs->pending) {
+		err("control request 0x%02x failed: %s",
+		    ucs->pending, get_usb_statmsg(urb->status));
+		del_timer(&ucs->timer_ctrl);
+		ucs->pending = 0;
+	}
+	/* individual handling of specific request types */
+	switch (ucs->pending) {
+	case HD_DEVICE_INIT_ACK:		/* no reply expected */
+		ucs->pending = 0;
+		break;
+	}
+	spin_unlock_irqrestore(&ucs->lock, flags);
+}
+
+/* req_submit
+ * submit a control output request without message buffer to the Gigaset base
+ * and optionally start a timeout
+ * parameters:
+ *	bcs	B channel control structure
+ *	req	control request code (HD_*)
+ *	val	control request parameter value (set to 0 if unused)
+ *	timeout	timeout in seconds (0: no timeout)
+ * return value:
+ *	0 on success
+ *	-EINVAL if a NULL pointer is encountered somewhere
+ *	-EBUSY if another request is pending
+ *	any URB submission error code
+ */
+static int req_submit(struct bc_state *bcs, int req, int val, int timeout)
+{
+	struct bas_cardstate *ucs;
+	int ret;
+	unsigned long flags;
+
+	IFNULLRETVAL(bcs, -EINVAL);
+	IFNULLRETVAL(bcs->cs, -EINVAL);
+	ucs = bcs->cs->hw.bas;
+	IFNULLRETVAL(ucs, -EINVAL);
+	IFNULLRETVAL(ucs->urb_ctrl, -EINVAL);
+
+	dbg(DEBUG_USBREQ, "-------> 0x%02x (%d)", req, val);
+
+	spin_lock_irqsave(&ucs->lock, flags);
+	if (ucs->pending) {
+		spin_unlock_irqrestore(&ucs->lock, flags);
+		err("submission of request 0x%02x failed: request 0x%02x still pending",
+		    req, ucs->pending);
+		return -EBUSY;
+	}
+	if (ucs->urb_ctrl->status == -EINPROGRESS) {
+		spin_unlock_irqrestore(&ucs->lock, flags);
+		err("could not submit request 0x%02x: URB busy", req);
+		return -EBUSY;
+	}
+
+	ucs->dr_ctrl.bRequestType = OUT_VENDOR_REQ;
+	ucs->dr_ctrl.bRequest = req;
+	ucs->dr_ctrl.wValue = cpu_to_le16(val);
+	ucs->dr_ctrl.wIndex = 0;
+	ucs->dr_ctrl.wLength = 0;
+	usb_fill_control_urb(ucs->urb_ctrl, ucs->udev,
+                             usb_sndctrlpipe(ucs->udev, 0),
+                             (unsigned char*) &ucs->dr_ctrl, NULL, 0,
+                             write_ctrl_callback, ucs);
+	if ((ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC)) != 0) {
+		err("could not submit request 0x%02x: %s",
+		    req, get_usb_statmsg(ret));
+		spin_unlock_irqrestore(&ucs->lock, flags);
+		return ret;
+	}
+	ucs->pending = req;
+
+	if (timeout > 0) {
+		dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout);
+		ucs->timer_ctrl.expires = jiffies + timeout * HZ / 10;
+		ucs->timer_ctrl.data = (unsigned long) bcs;
+		ucs->timer_ctrl.function = req_timeout;
+		add_timer(&ucs->timer_ctrl);
+	}
+
+	spin_unlock_irqrestore(&ucs->lock, flags);
+	return 0;
+}
+
+/* gigaset_init_bchannel
+ * called by common.c to connect a B channel
+ * initialize isochronous I/O and tell the Gigaset base to open the channel
+ * argument:
+ *	B channel control structure
+ * return value:
+ *	0 on success, error code < 0 on error
+ */
+static int gigaset_init_bchannel(struct bc_state *bcs)
+{
+	int req, ret;
+
+	IFNULLRETVAL(bcs, -EINVAL);
+
+	if ((ret = starturbs(bcs)) < 0) {
+		err("could not start isochronous I/O for channel %d",
+		    bcs->channel + 1);
+		error_hangup(bcs);
+		return ret;
+	}
+
+	req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL;
+	if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) {
+		err("could not open channel %d: %s",
+		    bcs->channel + 1, get_usb_statmsg(ret));
+		stopurbs(bcs->hw.bas);
+		error_hangup(bcs);
+	}
+	return ret;
+}
+
+/* gigaset_close_bchannel
+ * called by common.c to disconnect a B channel
+ * tell the Gigaset base to close the channel
+ * stopping isochronous I/O and LL notification will be done when the
+ * acknowledgement for the close arrives
+ * argument:
+ *	B channel control structure
+ * return value:
+ *	0 on success, error code < 0 on error
+ */
+static int gigaset_close_bchannel(struct bc_state *bcs)
+{
+	int req, ret;
+
+	IFNULLRETVAL(bcs, -EINVAL);
+
+	if (!(atomic_read(&bcs->cs->hw.bas->basstate) &
+	      (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) {
+		/* channel not running: just signal common.c */
+		gigaset_bchannel_down(bcs);
+		return 0;
+	}
+
+	req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL;
+	if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0)
+		err("could not submit HD_CLOSE_BxCHANNEL request: %s",
+		    get_usb_statmsg(ret));
+	return ret;
+}
+
+/* Device Operations */
+/* ================= */
+
+/* complete_cb
+ * unqueue first command buffer from queue, waking any sleepers
+ * must be called with cs->cmdlock held
+ * parameter:
+ *	cs	controller state structure
+ */
+static void complete_cb(struct cardstate *cs)
+{
+	struct cmdbuf_t *cb;
+
+	IFNULLRET(cs);
+	cb = cs->cmdbuf;
+	IFNULLRET(cb);
+
+	/* unqueue completed buffer */
+	cs->cmdbytes -= cs->curlen;
+	dbg(DEBUG_TRANSCMD | DEBUG_LOCKCMD,
+	    "write_command: sent %u bytes, %u left",
+	    cs->curlen, cs->cmdbytes);
+	if ((cs->cmdbuf = cb->next) != NULL) {
+		cs->cmdbuf->prev = NULL;
+		cs->curlen = cs->cmdbuf->len;
+	} else {
+		cs->lastcmdbuf = NULL;
+		cs->curlen = 0;
+	}
+
+	if (cb->wake_tasklet)
+		tasklet_schedule(cb->wake_tasklet);
+
+	kfree(cb);
+}
+
+static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len);
+
+/* write_command_callback
+ * USB completion handler for AT command transmission
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ *	urb	USB request block of completed request
+ *		urb->context = controller state structure
+ */
+static void write_command_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct cardstate *cs;
+	unsigned long flags;
+	struct bas_cardstate *ucs;
+
+	IFNULLRET(urb);
+	cs = (struct cardstate *) urb->context;
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	/* check status */
+	switch (urb->status) {
+	case 0:					/* normal completion */
+		break;
+	case -ENOENT:			/* canceled */
+	case -ECONNRESET:		/* canceled (async) */
+	case -EINPROGRESS:		/* pending */
+		/* ignore silently */
+		dbg(DEBUG_USBREQ,
+		    "%s: %s", __func__, get_usb_statmsg(urb->status));
+		return;
+	default:				/* any failure */
+		if (++ucs->retry_cmd_out > BAS_RETRY) {
+			warn("command write: %s, giving up after %d retries",
+			     get_usb_statmsg(urb->status), ucs->retry_cmd_out);
+			break;
+		}
+		if (cs->cmdbuf == NULL) {
+			warn("command write: %s, cannot retry - cmdbuf gone",
+			     get_usb_statmsg(urb->status));
+			break;
+		}
+		notice("command write: %s, retry %d",
+		       get_usb_statmsg(urb->status), ucs->retry_cmd_out);
+		if (atwrite_submit(cs, cs->cmdbuf->buf, cs->cmdbuf->len) >= 0)
+			/* resubmitted - bypass regular exit block */
+			return;
+		/* command send failed, assume base still waiting */
+		update_basstate(ucs, BS_ATREADY, 0);
+	}
+
+	spin_lock_irqsave(&cs->cmdlock, flags);
+	if (cs->cmdbuf != NULL)
+		complete_cb(cs);
+	spin_unlock_irqrestore(&cs->cmdlock, flags);
+}
+
+/* atrdy_timeout
+ * timeout routine for AT command transmission
+ * argument:
+ *	controller state structure
+ */
+static void atrdy_timeout(unsigned long data)
+{
+	struct cardstate *cs = (struct cardstate *) data;
+	struct bas_cardstate *ucs;
+
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	warn("timeout waiting for HD_READY_SEND_ATDATA");
+
+	/* fake the missing signal - what else can I do? */
+	update_basstate(ucs, BS_ATREADY, BS_ATTIMER);
+	start_cbsend(cs);
+}
+
+/* atwrite_submit
+ * submit an HD_WRITE_ATMESSAGE command URB
+ * parameters:
+ *	cs	controller state structure
+ *	buf	buffer containing command to send
+ *	len	length of command to send
+ * return value:
+ *	0 on success
+ *	-EFAULT if a NULL pointer is encountered somewhere
+ *	-EBUSY if another request is pending
+ *	any URB submission error code
+ */
+static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len)
+{
+	struct bas_cardstate *ucs;
+	int ret;
+
+	IFNULLRETVAL(cs, -EFAULT);
+	ucs = cs->hw.bas;
+	IFNULLRETVAL(ucs, -EFAULT);
+	IFNULLRETVAL(ucs->urb_cmd_out, -EFAULT);
+
+	dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len);
+
+	if (ucs->urb_cmd_out->status == -EINPROGRESS) {
+		err("could not submit HD_WRITE_ATMESSAGE: URB busy");
+		return -EBUSY;
+	}
+
+	ucs->dr_cmd_out.bRequestType = OUT_VENDOR_REQ;
+	ucs->dr_cmd_out.bRequest = HD_WRITE_ATMESSAGE;
+	ucs->dr_cmd_out.wValue = 0;
+	ucs->dr_cmd_out.wIndex = 0;
+	ucs->dr_cmd_out.wLength = cpu_to_le16(len);
+	usb_fill_control_urb(ucs->urb_cmd_out, ucs->udev,
+			     usb_sndctrlpipe(ucs->udev, 0),
+			     (unsigned char*) &ucs->dr_cmd_out, buf, len,
+			     write_command_callback, cs);
+
+	if ((ret = usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC)) != 0) {
+		err("could not submit HD_WRITE_ATMESSAGE: %s",
+		    get_usb_statmsg(ret));
+		return ret;
+	}
+
+	/* submitted successfully */
+	update_basstate(ucs, 0, BS_ATREADY);
+
+	/* start timeout if necessary */
+	if (!(atomic_read(&ucs->basstate) & BS_ATTIMER)) {
+		dbg(DEBUG_OUTPUT,
+		    "setting ATREADY timeout of %d/10 secs", ATRDY_TIMEOUT);
+		ucs->timer_atrdy.expires = jiffies + ATRDY_TIMEOUT * HZ / 10;
+		ucs->timer_atrdy.data = (unsigned long) cs;
+		ucs->timer_atrdy.function = atrdy_timeout;
+		add_timer(&ucs->timer_atrdy);
+		update_basstate(ucs, BS_ATTIMER, 0);
+	}
+	return 0;
+}
+
+/* start_cbsend
+ * start transmission of AT command queue if necessary
+ * parameter:
+ *	cs		controller state structure
+ * return value:
+ *	0 on success
+ *	error code < 0 on error
+ */
+static int start_cbsend(struct cardstate *cs)
+{
+	struct cmdbuf_t *cb;
+	struct bas_cardstate *ucs;
+	unsigned long flags;
+	int rc;
+	int retval = 0;
+
+	IFNULLRETVAL(cs, -EFAULT);
+	ucs = cs->hw.bas;
+	IFNULLRETVAL(ucs, -EFAULT);
+
+	/* check if AT channel is open */
+	if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) {
+		dbg(DEBUG_TRANSCMD | DEBUG_LOCKCMD, "AT channel not open");
+		rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT);
+		if (rc < 0) {
+			err("could not open AT channel");
+			/* flush command queue */
+			spin_lock_irqsave(&cs->cmdlock, flags);
+			while (cs->cmdbuf != NULL)
+				complete_cb(cs);
+			spin_unlock_irqrestore(&cs->cmdlock, flags);
+		}
+		return rc;
+	}
+
+	/* try to send first command in queue */
+	spin_lock_irqsave(&cs->cmdlock, flags);
+
+	while ((cb = cs->cmdbuf) != NULL &&
+	       atomic_read(&ucs->basstate) & BS_ATREADY) {
+		ucs->retry_cmd_out = 0;
+		rc = atwrite_submit(cs, cb->buf, cb->len);
+		if (unlikely(rc)) {
+			retval = rc;
+			complete_cb(cs);
+		}
+	}
+
+	spin_unlock_irqrestore(&cs->cmdlock, flags);
+	return retval;
+}
+
+/* gigaset_write_cmd
+ * This function is called by the device independent part of the driver
+ * to transmit an AT command string to the Gigaset device.
+ * It encapsulates the device specific method for transmission over the
+ * direct USB connection to the base.
+ * The command string is added to the queue of commands to send, and
+ * USB transmission is started if necessary.
+ * parameters:
+ *	cs		controller state structure
+ *	buf		command string to send
+ *	len		number of bytes to send (max. IF_WRITEBUF)
+ *	wake_tasklet	tasklet to run when transmission is completed (NULL if none)
+ * return value:
+ *	number of bytes queued on success
+ *	error code < 0 on error
+ */
+static int gigaset_write_cmd(struct cardstate *cs,
+                             const unsigned char *buf, int len,
+                             struct tasklet_struct *wake_tasklet)
+{
+	struct cmdbuf_t *cb;
+	unsigned long flags;
+	int status;
+
+	gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+	                     DEBUG_TRANSCMD : DEBUG_LOCKCMD,
+	                   "CMD Transmit", len, buf, 0);
+
+	if (!atomic_read(&cs->connected)) {
+		err("%s: not connected", __func__);
+		return -ENODEV;
+	}
+
+	if (len <= 0)
+		return 0;			/* nothing to do */
+
+	if (len > IF_WRITEBUF)
+		len = IF_WRITEBUF;
+	if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) {
+		err("%s: out of memory", __func__);
+		return -ENOMEM;
+	}
+
+	memcpy(cb->buf, buf, len);
+	cb->len = len;
+	cb->offset = 0;
+	cb->next = NULL;
+	cb->wake_tasklet = wake_tasklet;
+
+	spin_lock_irqsave(&cs->cmdlock, flags);
+	cb->prev = cs->lastcmdbuf;
+	if (cs->lastcmdbuf)
+		cs->lastcmdbuf->next = cb;
+	else {
+		cs->cmdbuf = cb;
+		cs->curlen = len;
+	}
+	cs->cmdbytes += len;
+	cs->lastcmdbuf = cb;
+	spin_unlock_irqrestore(&cs->cmdlock, flags);
+
+	status = start_cbsend(cs);
+
+	return status < 0 ? status : len;
+}
+
+/* gigaset_write_room
+ * tty_driver.write_room interface routine
+ * return number of characters the driver will accept to be written via gigaset_write_cmd
+ * parameter:
+ *	controller state structure
+ * return value:
+ *	number of characters
+ */
+static int gigaset_write_room(struct cardstate *cs)
+{
+	return IF_WRITEBUF;
+}
+
+/* gigaset_chars_in_buffer
+ * tty_driver.chars_in_buffer interface routine
+ * return number of characters waiting to be sent
+ * parameter:
+ *	controller state structure
+ * return value:
+ *	number of characters
+ */
+static int gigaset_chars_in_buffer(struct cardstate *cs)
+{
+	unsigned long flags;
+	unsigned bytes;
+
+	spin_lock_irqsave(&cs->cmdlock, flags);
+	bytes = cs->cmdbytes;
+	spin_unlock_irqrestore(&cs->cmdlock, flags);
+
+	return bytes;
+}
+
+/* gigaset_brkchars
+ * implementation of ioctl(GIGASET_BRKCHARS)
+ * parameter:
+ *	controller state structure
+ * return value:
+ *	-EINVAL (unimplemented function)
+ */
+static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])
+{
+	return -EINVAL;
+}
+
+
+/* Device Initialization/Shutdown */
+/* ============================== */
+
+/* Free hardware dependent part of the B channel structure
+ * parameter:
+ *	bcs	B channel structure
+ * return value:
+ *	!=0 on success
+ */
+static int gigaset_freebcshw(struct bc_state *bcs)
+{
+	if (!bcs->hw.bas)
+		return 0;
+
+	if (bcs->hw.bas->isooutbuf)
+		kfree(bcs->hw.bas->isooutbuf);
+	kfree(bcs->hw.bas);
+	bcs->hw.bas = NULL;
+	return 1;
+}
+
+/* Initialize hardware dependent part of the B channel structure
+ * parameter:
+ *	bcs	B channel structure
+ * return value:
+ *	!=0 on success
+ */
+static int gigaset_initbcshw(struct bc_state *bcs)
+{
+	int i;
+	struct bas_bc_state *ubc;
+
+	bcs->hw.bas = ubc = kmalloc(sizeof(struct bas_bc_state), GFP_KERNEL);
+	if (!ubc) {
+		err("could not allocate bas_bc_state");
+		return 0;
+	}
+
+	atomic_set(&ubc->running, 0);
+	atomic_set(&ubc->corrbytes, 0);
+	spin_lock_init(&ubc->isooutlock);
+	for (i = 0; i < BAS_OUTURBS; ++i) {
+		ubc->isoouturbs[i].urb = NULL;
+		ubc->isoouturbs[i].bcs = bcs;
+	}
+	ubc->isooutdone = ubc->isooutfree = ubc->isooutovfl = NULL;
+	ubc->numsub = 0;
+	if (!(ubc->isooutbuf = kmalloc(sizeof(struct isowbuf_t), GFP_KERNEL))) {
+		err("could not allocate isochronous output buffer");
+		kfree(ubc);
+		bcs->hw.bas = NULL;
+		return 0;
+	}
+	tasklet_init(&ubc->sent_tasklet,
+	             &write_iso_tasklet, (unsigned long) bcs);
+
+	spin_lock_init(&ubc->isoinlock);
+	for (i = 0; i < BAS_INURBS; ++i)
+		ubc->isoinurbs[i] = NULL;
+	ubc->isoindone = NULL;
+	ubc->loststatus = -EINPROGRESS;
+	ubc->isoinlost = 0;
+	ubc->seqlen = 0;
+	ubc->inbyte = 0;
+	ubc->inbits = 0;
+	ubc->goodbytes = 0;
+	ubc->alignerrs = 0;
+	ubc->fcserrs = 0;
+	ubc->frameerrs = 0;
+	ubc->giants = 0;
+	ubc->runts = 0;
+	ubc->aborts = 0;
+	ubc->shared0s = 0;
+	ubc->stolen0s = 0;
+	tasklet_init(&ubc->rcvd_tasklet,
+	             &read_iso_tasklet, (unsigned long) bcs);
+	return 1;
+}
+
+static void gigaset_reinitbcshw(struct bc_state *bcs)
+{
+	struct bas_bc_state *ubc = bcs->hw.bas;
+
+	atomic_set(&bcs->hw.bas->running, 0);
+	atomic_set(&bcs->hw.bas->corrbytes, 0);
+	bcs->hw.bas->numsub = 0;
+	spin_lock_init(&ubc->isooutlock);
+	spin_lock_init(&ubc->isoinlock);
+	ubc->loststatus = -EINPROGRESS;
+}
+
+static void gigaset_freecshw(struct cardstate *cs)
+{
+	struct bas_cardstate *ucs = cs->hw.bas;
+
+	del_timer(&ucs->timer_ctrl);
+	del_timer(&ucs->timer_atrdy);
+	del_timer(&ucs->timer_cmd_in);
+
+	kfree(cs->hw.bas);
+}
+
+static int gigaset_initcshw(struct cardstate *cs)
+{
+	struct bas_cardstate *ucs;
+
+	cs->hw.bas = ucs = kmalloc(sizeof *ucs, GFP_KERNEL);
+	if (!ucs)
+		return 0;
+
+	ucs->urb_cmd_in = NULL;
+	ucs->urb_cmd_out = NULL;
+	ucs->rcvbuf = NULL;
+	ucs->rcvbuf_size = 0;
+
+	spin_lock_init(&ucs->lock);
+	ucs->pending = 0;
+
+	atomic_set(&ucs->basstate, 0);
+	init_timer(&ucs->timer_ctrl);
+	init_timer(&ucs->timer_atrdy);
+	init_timer(&ucs->timer_cmd_in);
+
+	return 1;
+}
+
+/* freeurbs
+ * unlink and deallocate all URBs unconditionally
+ * caller must make sure that no commands are still in progress
+ * parameter:
+ *	cs	controller state structure
+ */
+static void freeurbs(struct cardstate *cs)
+{
+	struct bas_cardstate *ucs;
+	struct bas_bc_state *ubc;
+	int i, j;
+
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	for (j = 0; j < 2; ++j) {
+		ubc = cs->bcs[j].hw.bas;
+		IFNULLCONT(ubc);
+		for (i = 0; i < BAS_OUTURBS; ++i)
+			if (ubc->isoouturbs[i].urb) {
+				usb_kill_urb(ubc->isoouturbs[i].urb);
+				dbg(DEBUG_INIT,
+				    "%s: isoc output URB %d/%d unlinked",
+				    __func__, j, i);
+				usb_free_urb(ubc->isoouturbs[i].urb);
+				ubc->isoouturbs[i].urb = NULL;
+			}
+		for (i = 0; i < BAS_INURBS; ++i)
+			if (ubc->isoinurbs[i]) {
+				usb_kill_urb(ubc->isoinurbs[i]);
+				dbg(DEBUG_INIT,
+				    "%s: isoc input URB %d/%d unlinked",
+				    __func__, j, i);
+				usb_free_urb(ubc->isoinurbs[i]);
+				ubc->isoinurbs[i] = NULL;
+			}
+	}
+	if (ucs->urb_int_in) {
+		usb_kill_urb(ucs->urb_int_in);
+		dbg(DEBUG_INIT, "%s: interrupt input URB unlinked", __func__);
+		usb_free_urb(ucs->urb_int_in);
+		ucs->urb_int_in = NULL;
+	}
+	if (ucs->urb_cmd_out) {
+		usb_kill_urb(ucs->urb_cmd_out);
+		dbg(DEBUG_INIT, "%s: command output URB unlinked", __func__);
+		usb_free_urb(ucs->urb_cmd_out);
+		ucs->urb_cmd_out = NULL;
+	}
+	if (ucs->urb_cmd_in) {
+		usb_kill_urb(ucs->urb_cmd_in);
+		dbg(DEBUG_INIT, "%s: command input URB unlinked", __func__);
+		usb_free_urb(ucs->urb_cmd_in);
+		ucs->urb_cmd_in = NULL;
+	}
+	if (ucs->urb_ctrl) {
+		usb_kill_urb(ucs->urb_ctrl);
+		dbg(DEBUG_INIT, "%s: control output URB unlinked", __func__);
+		usb_free_urb(ucs->urb_ctrl);
+		ucs->urb_ctrl = NULL;
+	}
+}
+
+/* gigaset_probe
+ * This function is called when a new USB device is connected.
+ * It checks whether the new device is handled by this driver.
+ */
+static int gigaset_probe(struct usb_interface *interface,
+			 const struct usb_device_id *id)
+{
+	struct usb_host_interface *hostif;
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct cardstate *cs = NULL;
+	struct bas_cardstate *ucs = NULL;
+	struct bas_bc_state *ubc;
+	struct usb_endpoint_descriptor *endpoint;
+	int i, j;
+	int ret;
+
+	IFNULLRETVAL(udev, -ENODEV);
+
+	dbg(DEBUG_ANY,
+	    "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
+	    __func__, le16_to_cpu(udev->descriptor.idVendor),
+	    le16_to_cpu(udev->descriptor.idProduct));
+
+	/* See if the device offered us matches what we can accept */
+	if ((le16_to_cpu(udev->descriptor.idVendor)  != USB_GIGA_VENDOR_ID) ||
+	    (le16_to_cpu(udev->descriptor.idProduct) != USB_GIGA_PRODUCT_ID &&
+	     le16_to_cpu(udev->descriptor.idProduct) != USB_4175_PRODUCT_ID &&
+	     le16_to_cpu(udev->descriptor.idProduct) != USB_SX303_PRODUCT_ID &&
+	     le16_to_cpu(udev->descriptor.idProduct) != USB_SX353_PRODUCT_ID)) {
+		dbg(DEBUG_ANY, "%s: unmatched ID - exiting", __func__);
+		return -ENODEV;
+	}
+
+	/* set required alternate setting */
+	hostif = interface->cur_altsetting;
+	if (hostif->desc.bAlternateSetting != 3) {
+		dbg(DEBUG_ANY,
+		    "%s: wrong alternate setting %d - trying to switch",
+		    __func__, hostif->desc.bAlternateSetting);
+		if (usb_set_interface(udev, hostif->desc.bInterfaceNumber, 3) < 0) {
+			warn("usb_set_interface failed, device %d interface %d altsetting %d",
+			     udev->devnum, hostif->desc.bInterfaceNumber,
+			     hostif->desc.bAlternateSetting);
+			return -ENODEV;
+		}
+		hostif = interface->cur_altsetting;
+	}
+
+	/* Reject application specific interfaces
+	 */
+	if (hostif->desc.bInterfaceClass != 255) {
+		warn("%s: bInterfaceClass == %d",
+		     __func__, hostif->desc.bInterfaceClass);
+		return -ENODEV;
+	}
+
+	info("%s: Device matched (Vendor: 0x%x, Product: 0x%x)",
+	     __func__, le16_to_cpu(udev->descriptor.idVendor),
+	     le16_to_cpu(udev->descriptor.idProduct));
+
+	cs = gigaset_getunassignedcs(driver);
+	if (!cs) {
+		err("%s: no free cardstate", __func__);
+		return -ENODEV;
+	}
+	ucs = cs->hw.bas;
+	ucs->udev = udev;
+	ucs->interface = interface;
+
+	/* allocate URBs:
+	 * - one for the interrupt pipe
+	 * - three for the different uses of the default control pipe
+	 * - three for each isochronous pipe
+	 */
+	ucs->urb_int_in = usb_alloc_urb(0, SLAB_KERNEL);
+	if (!ucs->urb_int_in) {
+		err("No free urbs available");
+		goto error;
+	}
+	ucs->urb_cmd_in = usb_alloc_urb(0, SLAB_KERNEL);
+	if (!ucs->urb_cmd_in) {
+		err("No free urbs available");
+		goto error;
+	}
+	ucs->urb_cmd_out = usb_alloc_urb(0, SLAB_KERNEL);
+	if (!ucs->urb_cmd_out) {
+		err("No free urbs available");
+		goto error;
+	}
+	ucs->urb_ctrl = usb_alloc_urb(0, SLAB_KERNEL);
+	if (!ucs->urb_ctrl) {
+		err("No free urbs available");
+		goto error;
+	}
+
+	for (j = 0; j < 2; ++j) {
+		ubc = cs->bcs[j].hw.bas;
+		for (i = 0; i < BAS_OUTURBS; ++i) {
+			ubc->isoouturbs[i].urb =
+				usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL);
+			if (!ubc->isoouturbs[i].urb) {
+				err("No free urbs available");
+				goto error;
+			}
+		}
+		for (i = 0; i < BAS_INURBS; ++i) {
+			ubc->isoinurbs[i] =
+				usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL);
+			if (!ubc->isoinurbs[i]) {
+				err("No free urbs available");
+				goto error;
+			}
+		}
+	}
+
+	ucs->rcvbuf = NULL;
+	ucs->rcvbuf_size = 0;
+
+	/* Fill the interrupt urb and send it to the core */
+	endpoint = &hostif->endpoint[0].desc;
+	usb_fill_int_urb(ucs->urb_int_in, udev,
+	                 usb_rcvintpipe(udev,
+	                                (endpoint->bEndpointAddress) & 0x0f),
+	                 ucs->int_in_buf, 3, read_int_callback, cs,
+	                 endpoint->bInterval);
+	ret = usb_submit_urb(ucs->urb_int_in, SLAB_KERNEL);
+	if (ret) {
+		err("could not submit interrupt URB: %s", get_usb_statmsg(ret));
+		goto error;
+	}
+
+	/* tell the device that the driver is ready */
+	if ((ret = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0)) != 0)
+		goto error;
+
+	/* tell common part that the device is ready */
+	if (startmode == SM_LOCKED)
+		atomic_set(&cs->mstate, MS_LOCKED);
+	if (!gigaset_start(cs))
+		goto error;
+
+	/* save address of controller structure */
+	usb_set_intfdata(interface, cs);
+
+	/* set up device sysfs */
+	gigaset_init_dev_sysfs(interface);
+	return 0;
+
+error:
+	freeurbs(cs);
+	gigaset_unassign(cs);
+	return -ENODEV;
+}
+
+/* gigaset_disconnect
+ * This function is called when the Gigaset base is unplugged.
+ */
+static void gigaset_disconnect(struct usb_interface *interface)
+{
+	struct cardstate *cs;
+	struct bas_cardstate *ucs;
+
+	/* clear device sysfs */
+	gigaset_free_dev_sysfs(interface);
+
+	cs = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	info("disconnecting GigaSet base");
+	gigaset_stop(cs);
+	freeurbs(cs);
+	kfree(ucs->rcvbuf);
+	ucs->rcvbuf = NULL;
+	ucs->rcvbuf_size = 0;
+	atomic_set(&ucs->basstate, 0);
+	gigaset_unassign(cs);
+}
+
+static struct gigaset_ops gigops = {
+	gigaset_write_cmd,
+	gigaset_write_room,
+	gigaset_chars_in_buffer,
+	gigaset_brkchars,
+	gigaset_init_bchannel,
+	gigaset_close_bchannel,
+	gigaset_initbcshw,
+	gigaset_freebcshw,
+	gigaset_reinitbcshw,
+	gigaset_initcshw,
+	gigaset_freecshw,
+	gigaset_set_modem_ctrl,
+	gigaset_baud_rate,
+	gigaset_set_line_ctrl,
+	gigaset_isoc_send_skb,
+	gigaset_isoc_input,
+};
+
+/* bas_gigaset_init
+ * This function is called after the kernel module is loaded.
+ */
+static int __init bas_gigaset_init(void)
+{
+	int result;
+
+	/* allocate memory for our driver state and intialize it */
+	if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
+	                               GIGASET_MODULENAME, GIGASET_DEVNAME,
+	                               GIGASET_DEVFSNAME, &gigops,
+	                               THIS_MODULE)) == NULL)
+		goto error;
+
+	/* allocate memory for our device state and intialize it */
+	cardstate = gigaset_initcs(driver, 2, 0, 0, cidmode, GIGASET_MODULENAME);
+	if (!cardstate)
+		goto error;
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&gigaset_usb_driver);
+	if (result < 0) {
+		err("usb_register failed (error %d)", -result);
+		goto error;
+	}
+
+	info(DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+	return 0;
+
+error:	if (cardstate)
+		gigaset_freecs(cardstate);
+	cardstate = NULL;
+	if (driver)
+		gigaset_freedriver(driver);
+	driver = NULL;
+	return -1;
+}
+
+/* bas_gigaset_exit
+ * This function is called before the kernel module is unloaded.
+ */
+static void __exit bas_gigaset_exit(void)
+{
+	gigaset_blockdriver(driver); /* => probe will fail
+	                              * => no gigaset_start any more
+	                              */
+
+	gigaset_shutdown(cardstate);
+	/* from now on, no isdn callback should be possible */
+
+	if (atomic_read(&cardstate->hw.bas->basstate) & BS_ATOPEN) {
+		dbg(DEBUG_ANY, "closing AT channel");
+		if (req_submit(cardstate->bcs,
+		               HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT) >= 0) {
+			/* successfully submitted - wait for completion */
+			//wait_event_interruptible(cs->initwait, !cs->hw.bas->pending);
+			//FIXME need own wait queue? wakeup?
+		}
+	}
+
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&gigaset_usb_driver);
+	/* this will call the disconnect-callback */
+	/* from now on, no disconnect/probe callback should be running */
+
+	gigaset_freecs(cardstate);
+	cardstate = NULL;
+	gigaset_freedriver(driver);
+	driver = NULL;
+}
+
+
+module_init(bas_gigaset_init);
+module_exit(bas_gigaset_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
new file mode 100644
index 0000000..6437199
--- /dev/null
+++ b/drivers/isdn/gigaset/common.c
@@ -0,0 +1,1203 @@
+/*
+ * Stuff used by all variants of the driver
+ *
+ * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>,
+ *                       Hansjoerg Lipp <hjlipp@web.de>,
+ *                       Tilman Schmidt <tilman@imap.cc>.
+ *
+ * =====================================================================
+ *	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.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: common.c,v 1.104.4.22 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+/* Version Information */
+#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers <Eilers.Stefan@epost.de>"
+#define DRIVER_DESC "Driver for Gigaset 307x"
+
+/* Module parameters */
+int gigaset_debuglevel = DEBUG_DEFAULT;
+EXPORT_SYMBOL_GPL(gigaset_debuglevel);
+module_param_named(debug, gigaset_debuglevel, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(debug, "debug level");
+
+/*======================================================================
+  Prototypes of internal functions
+ */
+
+//static void gigaset_process_response(int resp_code, int parameter,
+//                                     struct at_state_t *at_state,
+//                                     unsigned char ** pstring);
+static struct cardstate *alloc_cs(struct gigaset_driver *drv);
+static void free_cs(struct cardstate *cs);
+static void make_valid(struct cardstate *cs, unsigned mask);
+static void make_invalid(struct cardstate *cs, unsigned mask);
+
+#define VALID_MINOR       0x01
+#define VALID_ID          0x02
+#define ASSIGNED          0x04
+
+/* bitwise byte inversion table */
+__u8 gigaset_invtab[256] = {
+	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+EXPORT_SYMBOL_GPL(gigaset_invtab);
+
+void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
+                        size_t len, const unsigned char *buf, int from_user)
+{
+	unsigned char outbuf[80];
+	unsigned char inbuf[80 - 1];
+	size_t numin;
+	const unsigned char *in;
+	size_t space = sizeof outbuf - 1;
+	unsigned char *out = outbuf;
+
+	if (!from_user) {
+		in = buf;
+		numin = len;
+	} else {
+		numin = len < sizeof inbuf ? len : sizeof inbuf;
+		in = inbuf;
+		if (copy_from_user(inbuf, (const unsigned char __user *) buf, numin)) {
+			strncpy(inbuf, "<FAULT>", sizeof inbuf);
+			numin = sizeof "<FAULT>" - 1;
+		}
+	}
+
+	for (; numin && space; --numin, ++in) {
+		--space;
+		if (*in >= 32)
+			*out++ = *in;
+		else {
+			*out++ = '^';
+			if (space) {
+				*out++ = '@' + *in;
+				--space;
+			}
+		}
+	}
+	*out = 0;
+
+	dbg(level, "%s (%u bytes): %s", msg, (unsigned) len, outbuf);
+}
+EXPORT_SYMBOL_GPL(gigaset_dbg_buffer);
+
+static int setflags(struct cardstate *cs, unsigned flags, unsigned delay)
+{
+	int r;
+
+	r = cs->ops->set_modem_ctrl(cs, cs->control_state, flags);
+	cs->control_state = flags;
+	if (r < 0)
+		return r;
+
+	if (delay) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(delay * HZ / 1000);
+	}
+
+	return 0;
+}
+
+int gigaset_enterconfigmode(struct cardstate *cs)
+{
+	int i, r;
+
+	if (!atomic_read(&cs->connected)) {
+		err("not connected!");
+		return -1;
+	}
+
+	cs->control_state = TIOCM_RTS; //FIXME
+
+	r = setflags(cs, TIOCM_DTR, 200);
+	if (r < 0)
+		goto error;
+	r = setflags(cs, 0, 200);
+	if (r < 0)
+		goto error;
+	for (i = 0; i < 5; ++i) {
+		r = setflags(cs, TIOCM_RTS, 100);
+		if (r < 0)
+			goto error;
+		r = setflags(cs, 0, 100);
+		if (r < 0)
+			goto error;
+	}
+	r = setflags(cs, TIOCM_RTS|TIOCM_DTR, 800);
+	if (r < 0)
+		goto error;
+
+	return 0;
+
+error:
+	err("error %d on setuartbits!\n", -r);
+	cs->control_state = TIOCM_RTS|TIOCM_DTR; // FIXME is this a good value?
+	cs->ops->set_modem_ctrl(cs, 0, TIOCM_RTS|TIOCM_DTR);
+
+	return -1; //r
+}
+
+static int test_timeout(struct at_state_t *at_state)
+{
+	if (!at_state->timer_expires)
+		return 0;
+
+	if (--at_state->timer_expires) {
+		dbg(DEBUG_MCMD, "decreased timer of %p to %lu",
+		    at_state, at_state->timer_expires);
+		return 0;
+	}
+
+	if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL,
+	                       atomic_read(&at_state->timer_index), NULL)) {
+		//FIXME what should we do?
+	}
+
+	return 1;
+}
+
+static void timer_tick(unsigned long data)
+{
+	struct cardstate *cs = (struct cardstate *) data;
+	unsigned long flags;
+	unsigned channel;
+	struct at_state_t *at_state;
+	int timeout = 0;
+
+	spin_lock_irqsave(&cs->lock, flags);
+
+	for (channel = 0; channel < cs->channels; ++channel)
+		if (test_timeout(&cs->bcs[channel].at_state))
+			timeout = 1;
+
+	if (test_timeout(&cs->at_state))
+		timeout = 1;
+
+	list_for_each_entry(at_state, &cs->temp_at_states, list)
+		if (test_timeout(at_state))
+			timeout = 1;
+
+	if (atomic_read(&cs->running)) {
+		mod_timer(&cs->timer, jiffies + GIG_TICK);
+		if (timeout) {
+			dbg(DEBUG_CMD, "scheduling timeout");
+			tasklet_schedule(&cs->event_tasklet);
+		}
+	}
+
+	spin_unlock_irqrestore(&cs->lock, flags);
+}
+
+int gigaset_get_channel(struct bc_state *bcs)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&bcs->cs->lock, flags);
+	if (bcs->use_count) {
+		dbg(DEBUG_ANY, "could not allocate channel %d", bcs->channel);
+		spin_unlock_irqrestore(&bcs->cs->lock, flags);
+		return 0;
+	}
+	++bcs->use_count;
+	bcs->busy = 1;
+	dbg(DEBUG_ANY, "allocated channel %d", bcs->channel);
+	spin_unlock_irqrestore(&bcs->cs->lock, flags);
+	return 1;
+}
+
+void gigaset_free_channel(struct bc_state *bcs)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&bcs->cs->lock, flags);
+	if (!bcs->busy) {
+		dbg(DEBUG_ANY, "could not free channel %d", bcs->channel);
+		spin_unlock_irqrestore(&bcs->cs->lock, flags);
+		return;
+	}
+	--bcs->use_count;
+	bcs->busy = 0;
+	dbg(DEBUG_ANY, "freed channel %d", bcs->channel);
+	spin_unlock_irqrestore(&bcs->cs->lock, flags);
+}
+
+int gigaset_get_channels(struct cardstate *cs)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	for (i = 0; i < cs->channels; ++i)
+		if (cs->bcs[i].use_count) {
+			spin_unlock_irqrestore(&cs->lock, flags);
+			dbg(DEBUG_ANY, "could not allocated all channels");
+			return 0;
+		}
+	for (i = 0; i < cs->channels; ++i)
+		++cs->bcs[i].use_count;
+	spin_unlock_irqrestore(&cs->lock, flags);
+
+	dbg(DEBUG_ANY, "allocated all channels");
+
+	return 1;
+}
+
+void gigaset_free_channels(struct cardstate *cs)
+{
+	unsigned long flags;
+	int i;
+
+	dbg(DEBUG_ANY, "unblocking all channels");
+	spin_lock_irqsave(&cs->lock, flags);
+	for (i = 0; i < cs->channels; ++i)
+		--cs->bcs[i].use_count;
+	spin_unlock_irqrestore(&cs->lock, flags);
+}
+
+void gigaset_block_channels(struct cardstate *cs)
+{
+	unsigned long flags;
+	int i;
+
+	dbg(DEBUG_ANY, "blocking all channels");
+	spin_lock_irqsave(&cs->lock, flags);
+	for (i = 0; i < cs->channels; ++i)
+		++cs->bcs[i].use_count;
+	spin_unlock_irqrestore(&cs->lock, flags);
+}
+
+static void clear_events(struct cardstate *cs)
+{
+	struct event_t *ev;
+	unsigned head, tail;
+
+	/* no locking needed (no reader/writer allowed) */
+
+	head = atomic_read(&cs->ev_head);
+	tail = atomic_read(&cs->ev_tail);
+
+	while (tail != head) {
+		ev = cs->events + head;
+		kfree(ev->ptr);
+
+		head = (head + 1) % MAX_EVENTS;
+	}
+
+	atomic_set(&cs->ev_head, tail);
+}
+
+struct event_t *gigaset_add_event(struct cardstate *cs,
+                                  struct at_state_t *at_state, int type,
+                                  void *ptr, int parameter, void *arg)
+{
+	unsigned long flags;
+	unsigned next, tail;
+	struct event_t *event = NULL;
+
+	spin_lock_irqsave(&cs->ev_lock, flags);
+
+	tail = atomic_read(&cs->ev_tail);
+	next = (tail + 1) % MAX_EVENTS;
+	if (unlikely(next == atomic_read(&cs->ev_head)))
+		err("event queue full");
+	else {
+		event = cs->events + tail;
+		event->type = type;
+		event->at_state = at_state;
+		event->cid = -1;
+		event->ptr = ptr;
+		event->arg = arg;
+		event->parameter = parameter;
+		atomic_set(&cs->ev_tail, next);
+	}
+
+	spin_unlock_irqrestore(&cs->ev_lock, flags);
+
+	return event;
+}
+EXPORT_SYMBOL_GPL(gigaset_add_event);
+
+static void free_strings(struct at_state_t *at_state)
+{
+	int i;
+
+	for (i = 0; i < STR_NUM; ++i) {
+		kfree(at_state->str_var[i]);
+		at_state->str_var[i] = NULL;
+	}
+}
+
+static void clear_at_state(struct at_state_t *at_state)
+{
+	free_strings(at_state);
+}
+
+static void dealloc_at_states(struct cardstate *cs)
+{
+	struct at_state_t *cur, *next;
+
+	list_for_each_entry_safe(cur, next, &cs->temp_at_states, list) {
+		list_del(&cur->list);
+		free_strings(cur);
+		kfree(cur);
+	}
+}
+
+static void gigaset_freebcs(struct bc_state *bcs)
+{
+	int i;
+
+	dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel);
+	if (!bcs->cs->ops->freebcshw(bcs)) {
+		dbg(DEBUG_INIT, "failed");
+	}
+
+	dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel);
+	clear_at_state(&bcs->at_state);
+	dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel);
+
+	if (bcs->skb)
+		dev_kfree_skb(bcs->skb);
+	for (i = 0; i < AT_NUM; ++i) {
+		kfree(bcs->commands[i]);
+		bcs->commands[i] = NULL;
+	}
+}
+
+void gigaset_freecs(struct cardstate *cs)
+{
+	int i;
+	unsigned long flags;
+
+	if (!cs)
+		return;
+
+	down(&cs->sem);
+
+	if (!cs->bcs)
+		goto f_cs;
+	if (!cs->inbuf)
+		goto f_bcs;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	atomic_set(&cs->running, 0);
+	spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are not rescheduled below */
+
+	tasklet_kill(&cs->event_tasklet);
+	del_timer_sync(&cs->timer);
+
+	switch (cs->cs_init) {
+	default:
+		gigaset_if_free(cs);
+
+		dbg(DEBUG_INIT, "clearing hw");
+		cs->ops->freecshw(cs);
+
+		//FIXME cmdbuf
+
+		/* fall through */
+	case 2: /* error in initcshw */
+		/* Deregister from LL */
+		make_invalid(cs, VALID_ID);
+		dbg(DEBUG_INIT, "clearing iif");
+		gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
+
+		/* fall through */
+	case 1: /* error when regestering to LL */
+		dbg(DEBUG_INIT, "clearing at_state");
+		clear_at_state(&cs->at_state);
+		dealloc_at_states(cs);
+
+		/* fall through */
+	case 0: /* error in one call to initbcs */
+		for (i = 0; i < cs->channels; ++i) {
+			dbg(DEBUG_INIT, "clearing bcs[%d]", i);
+			gigaset_freebcs(cs->bcs + i);
+		}
+
+		clear_events(cs);
+		dbg(DEBUG_INIT, "freeing inbuf");
+		kfree(cs->inbuf);
+	}
+f_bcs:	dbg(DEBUG_INIT, "freeing bcs[]");
+	kfree(cs->bcs);
+f_cs:	dbg(DEBUG_INIT, "freeing cs");
+	up(&cs->sem);
+	free_cs(cs);
+}
+EXPORT_SYMBOL_GPL(gigaset_freecs);
+
+void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
+                     struct cardstate *cs, int cid)
+{
+	int i;
+
+	INIT_LIST_HEAD(&at_state->list);
+	at_state->waiting = 0;
+	at_state->getstring = 0;
+	at_state->pending_commands = 0;
+	at_state->timer_expires = 0;
+	at_state->timer_active = 0;
+	atomic_set(&at_state->timer_index, 0);
+	atomic_set(&at_state->seq_index, 0);
+	at_state->ConState = 0;
+	for (i = 0; i < STR_NUM; ++i)
+		at_state->str_var[i] = NULL;
+	at_state->int_var[VAR_ZDLE] = 0;
+	at_state->int_var[VAR_ZCTP] = -1;
+	at_state->int_var[VAR_ZSAU] = ZSAU_NULL;
+	at_state->cs = cs;
+	at_state->bcs = bcs;
+	at_state->cid = cid;
+	if (!cid)
+		at_state->replystruct = cs->tabnocid;
+	else
+		at_state->replystruct = cs->tabcid;
+}
+
+
+static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs,
+                               struct cardstate *cs, int inputstate)
+/* inbuf->read must be allocated before! */
+{
+	atomic_set(&inbuf->head, 0);
+	atomic_set(&inbuf->tail, 0);
+	inbuf->cs = cs;
+	inbuf->bcs = bcs; /*base driver: NULL*/
+	inbuf->rcvbuf = NULL; //FIXME
+	inbuf->inputstate = inputstate;
+}
+
+/* Initialize the b-channel structure */
+static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
+                                        struct cardstate *cs, int channel)
+{
+	int i;
+
+	bcs->tx_skb = NULL; //FIXME -> hw part
+
+	skb_queue_head_init(&bcs->squeue);
+
+	bcs->corrupted = 0;
+	bcs->trans_down = 0;
+	bcs->trans_up = 0;
+
+	dbg(DEBUG_INIT, "setting up bcs[%d]->at_state", channel);
+	gigaset_at_init(&bcs->at_state, bcs, cs, -1);
+
+	bcs->rcvbytes = 0;
+
+#ifdef CONFIG_GIGASET_DEBUG
+	bcs->emptycount = 0;
+#endif
+
+	dbg(DEBUG_INIT, "allocating bcs[%d]->skb", channel);
+	bcs->fcs = PPP_INITFCS;
+	bcs->inputstate = 0;
+	if (cs->ignoreframes) {
+		bcs->inputstate |= INS_skip_frame;
+		bcs->skb = NULL;
+	} else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
+		skb_reserve(bcs->skb, HW_HDR_LEN);
+	else {
+		warn("could not allocate skb");
+		bcs->inputstate |= INS_skip_frame;
+	}
+
+	bcs->channel = channel;
+	bcs->cs = cs;
+
+	bcs->chstate = 0;
+	bcs->use_count = 1;
+	bcs->busy = 0;
+	bcs->ignore = cs->ignoreframes;
+
+	for (i = 0; i < AT_NUM; ++i)
+		bcs->commands[i] = NULL;
+
+	dbg(DEBUG_INIT, "  setting up bcs[%d]->hw", channel);
+	if (cs->ops->initbcshw(bcs))
+		return bcs;
+
+//error:
+	dbg(DEBUG_INIT, "  failed");
+
+	dbg(DEBUG_INIT, "  freeing bcs[%d]->skb", channel);
+	if (bcs->skb)
+		dev_kfree_skb(bcs->skb);
+
+	return NULL;
+}
+
+/* gigaset_initcs
+ * Allocate and initialize cardstate structure for Gigaset driver
+ * Calls hardware dependent gigaset_initcshw() function
+ * Calls B channel initialization function gigaset_initbcs() for each B channel
+ * parameters:
+ *      drv		hardware driver the device belongs to
+ *	channels	number of B channels supported by device
+ *	onechannel	!=0: B channel data and AT commands share one communication channel
+ *			==0: B channels have separate communication channels
+ *	ignoreframes	number of frames to ignore after setting up B channel
+ *	cidmode		!=0: start in CallID mode
+ *	modulename	name of driver module (used for I4L registration)
+ * return value:
+ *	pointer to cardstate structure
+ */
+struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
+				 int onechannel, int ignoreframes,
+				 int cidmode, const char *modulename)
+{
+	struct cardstate *cs = NULL;
+	int i;
+
+	dbg(DEBUG_INIT, "allocating cs");
+	cs = alloc_cs(drv);
+	if (!cs)
+		goto error;
+	dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
+	cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
+	if (!cs->bcs)
+		goto error;
+	dbg(DEBUG_INIT, "allocating inbuf");
+	cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
+	if (!cs->inbuf)
+		goto error;
+
+	cs->cs_init = 0;
+	cs->channels = channels;
+	cs->onechannel = onechannel;
+	cs->ignoreframes = ignoreframes;
+	INIT_LIST_HEAD(&cs->temp_at_states);
+	atomic_set(&cs->running, 0);
+	init_timer(&cs->timer); /* clear next & prev */
+	spin_lock_init(&cs->ev_lock);
+	atomic_set(&cs->ev_tail, 0);
+	atomic_set(&cs->ev_head, 0);
+	init_MUTEX_LOCKED(&cs->sem);
+	tasklet_init(&cs->event_tasklet, &gigaset_handle_event, (unsigned long) cs);
+	atomic_set(&cs->commands_pending, 0);
+	cs->cur_at_seq = 0;
+	cs->gotfwver = -1;
+	cs->open_count = 0;
+	cs->tty = NULL;
+	atomic_set(&cs->cidmode, cidmode != 0);
+
+	//if(onechannel) { //FIXME
+		cs->tabnocid = gigaset_tab_nocid_m10x;
+		cs->tabcid = gigaset_tab_cid_m10x;
+	//} else {
+	//	cs->tabnocid = gigaset_tab_nocid;
+	//	cs->tabcid = gigaset_tab_cid;
+	//}
+
+	init_waitqueue_head(&cs->waitqueue);
+	cs->waiting = 0;
+
+	atomic_set(&cs->mode, M_UNKNOWN);
+	atomic_set(&cs->mstate, MS_UNINITIALIZED);
+
+	for (i = 0; i < channels; ++i) {
+		dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
+		if (!gigaset_initbcs(cs->bcs + i, cs, i))
+			goto error;
+	}
+
+	++cs->cs_init;
+
+	dbg(DEBUG_INIT, "setting up at_state");
+	spin_lock_init(&cs->lock);
+	gigaset_at_init(&cs->at_state, NULL, cs, 0);
+	cs->dle = 0;
+	cs->cbytes = 0;
+
+	dbg(DEBUG_INIT, "setting up inbuf");
+	if (onechannel) {			//FIXME distinction necessary?
+		gigaset_inbuf_init(cs->inbuf, cs->bcs, cs, INS_command);
+	} else
+		gigaset_inbuf_init(cs->inbuf, NULL,    cs, INS_command);
+
+	atomic_set(&cs->connected, 0);
+
+	dbg(DEBUG_INIT, "setting up cmdbuf");
+	cs->cmdbuf = cs->lastcmdbuf = NULL;
+	spin_lock_init(&cs->cmdlock);
+	cs->curlen = 0;
+	cs->cmdbytes = 0;
+
+	/*
+	 * Tell the ISDN4Linux subsystem (the LL) that
+	 * a driver for a USB-Device is available !
+	 * If this is done, "isdnctrl" is able to bind a device for this driver even
+	 * if no physical usb-device is currently connected.
+	 * But this device will just be accessable if a physical USB device is connected
+	 * (via "gigaset_probe") .
+	 */
+	dbg(DEBUG_INIT, "setting up iif");
+	if (!gigaset_register_to_LL(cs, modulename)) {
+		err("register_isdn=>error");
+		goto error;
+	}
+
+	make_valid(cs, VALID_ID);
+	++cs->cs_init;
+	dbg(DEBUG_INIT, "setting up hw");
+	if (!cs->ops->initcshw(cs))
+		goto error;
+
+	++cs->cs_init;
+
+	gigaset_if_init(cs);
+
+	atomic_set(&cs->running, 1);
+	cs->timer.data = (unsigned long) cs;
+	cs->timer.function = timer_tick;
+	cs->timer.expires = jiffies + GIG_TICK;
+	/* FIXME: can jiffies increase too much until the timer is added?
+	 * Same problem(?) with mod_timer() in timer_tick(). */
+	add_timer(&cs->timer);
+
+	dbg(DEBUG_INIT, "cs initialized!");
+	up(&cs->sem);
+	return cs;
+
+error:	if (cs)
+		up(&cs->sem);
+	dbg(DEBUG_INIT, "failed");
+	gigaset_freecs(cs);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(gigaset_initcs);
+
+/* ReInitialize the b-channel structure */ /* e.g. called on hangup, disconnect */
+void gigaset_bcs_reinit(struct bc_state *bcs)
+{
+	struct sk_buff *skb;
+	struct cardstate *cs = bcs->cs;
+	unsigned long flags;
+
+	while ((skb = skb_dequeue(&bcs->squeue)) != NULL)
+		dev_kfree_skb(skb);
+
+	spin_lock_irqsave(&cs->lock, flags); //FIXME
+	clear_at_state(&bcs->at_state);
+	bcs->at_state.ConState = 0;
+	bcs->at_state.timer_active = 0;
+	bcs->at_state.timer_expires = 0;
+	bcs->at_state.cid = -1;                     /* No CID defined */
+	spin_unlock_irqrestore(&cs->lock, flags);
+
+	bcs->inputstate = 0;
+
+#ifdef CONFIG_GIGASET_DEBUG
+	bcs->emptycount = 0;
+#endif
+
+	bcs->fcs = PPP_INITFCS;
+	bcs->chstate = 0;
+
+	bcs->ignore = cs->ignoreframes;
+	if (bcs->ignore)
+		bcs->inputstate |= INS_skip_frame;
+
+
+	cs->ops->reinitbcshw(bcs);
+}
+
+static void cleanup_cs(struct cardstate *cs)
+{
+	struct cmdbuf_t *cb, *tcb;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cs->lock, flags);
+
+	atomic_set(&cs->mode, M_UNKNOWN);
+	atomic_set(&cs->mstate, MS_UNINITIALIZED);
+
+	clear_at_state(&cs->at_state);
+	dealloc_at_states(cs);
+	free_strings(&cs->at_state);
+	gigaset_at_init(&cs->at_state, NULL, cs, 0);
+
+	kfree(cs->inbuf->rcvbuf);
+	cs->inbuf->rcvbuf = NULL;
+	cs->inbuf->inputstate = INS_command;
+	atomic_set(&cs->inbuf->head, 0);
+	atomic_set(&cs->inbuf->tail, 0);
+
+	cb = cs->cmdbuf;
+	while (cb) {
+		tcb = cb;
+		cb = cb->next;
+		kfree(tcb);
+	}
+	cs->cmdbuf = cs->lastcmdbuf = NULL;
+	cs->curlen = 0;
+	cs->cmdbytes = 0;
+	cs->gotfwver = -1;
+	cs->dle = 0;
+	cs->cur_at_seq = 0;
+	atomic_set(&cs->commands_pending, 0);
+	cs->cbytes = 0;
+
+	spin_unlock_irqrestore(&cs->lock, flags);
+
+	for (i = 0; i < cs->channels; ++i) {
+		gigaset_freebcs(cs->bcs + i);
+		if (!gigaset_initbcs(cs->bcs + i, cs, i))
+			break;			//FIXME error handling
+	}
+
+	if (cs->waiting) {
+		cs->cmd_result = -ENODEV;
+		cs->waiting = 0;
+		wake_up_interruptible(&cs->waitqueue);
+	}
+}
+
+
+int gigaset_start(struct cardstate *cs)
+{
+	if (down_interruptible(&cs->sem))
+		return 0;
+	//info("USB device for Gigaset 307x now attached to Dev %d", ucs->minor);
+
+	atomic_set(&cs->connected, 1);
+
+	if (atomic_read(&cs->mstate) != MS_LOCKED) {
+		cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
+		cs->ops->baud_rate(cs, B115200);
+		cs->ops->set_line_ctrl(cs, CS8);
+		cs->control_state = TIOCM_DTR|TIOCM_RTS;
+	} else {
+		//FIXME use some saved values?
+	}
+
+	cs->waiting = 1;
+
+	if (!gigaset_add_event(cs, &cs->at_state, EV_START, NULL, 0, NULL)) {
+		cs->waiting = 0;
+		//FIXME what should we do?
+		goto error;
+	}
+
+	dbg(DEBUG_CMD, "scheduling START");
+	gigaset_schedule_event(cs);
+
+	wait_event(cs->waitqueue, !cs->waiting);
+
+	up(&cs->sem);
+	return 1;
+
+error:
+	up(&cs->sem);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gigaset_start);
+
+void gigaset_shutdown(struct cardstate *cs)
+{
+	down(&cs->sem);
+
+	cs->waiting = 1;
+
+	if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) {
+		//FIXME what should we do?
+		goto exit;
+	}
+
+	dbg(DEBUG_CMD, "scheduling SHUTDOWN");
+	gigaset_schedule_event(cs);
+
+	if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) {
+		warn("aborted");
+		//FIXME
+	}
+
+	if (atomic_read(&cs->mstate) != MS_LOCKED) {
+		//FIXME?
+		//gigaset_baud_rate(cs, B115200);
+		//gigaset_set_line_ctrl(cs, CS8);
+		//gigaset_set_modem_ctrl(cs, TIOCM_DTR|TIOCM_RTS, 0);
+		//cs->control_state = 0;
+	} else {
+		//FIXME use some saved values?
+	}
+
+	cleanup_cs(cs);
+
+exit:
+	up(&cs->sem);
+}
+EXPORT_SYMBOL_GPL(gigaset_shutdown);
+
+void gigaset_stop(struct cardstate *cs)
+{
+	down(&cs->sem);
+
+	atomic_set(&cs->connected, 0);
+
+	cs->waiting = 1;
+
+	if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL)) {
+		//FIXME what should we do?
+		goto exit;
+	}
+
+	dbg(DEBUG_CMD, "scheduling STOP");
+	gigaset_schedule_event(cs);
+
+	if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) {
+		warn("aborted");
+		//FIXME
+	}
+
+	/* Tell the LL that the device is not available .. */
+	gigaset_i4l_cmd(cs, ISDN_STAT_STOP); // FIXME move to event layer?
+
+	cleanup_cs(cs);
+
+exit:
+	up(&cs->sem);
+}
+EXPORT_SYMBOL_GPL(gigaset_stop);
+
+static LIST_HEAD(drivers);
+static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
+
+struct cardstate *gigaset_get_cs_by_id(int id)
+{
+	unsigned long flags;
+	static struct cardstate *ret = NULL;
+	static struct cardstate *cs;
+	struct gigaset_driver *drv;
+	unsigned i;
+
+	spin_lock_irqsave(&driver_lock, flags);
+	list_for_each_entry(drv, &drivers, list) {
+		spin_lock(&drv->lock);
+		for (i = 0; i < drv->minors; ++i) {
+			if (drv->flags[i] & VALID_ID) {
+				cs = drv->cs + i;
+				if (cs->myid == id)
+					ret = cs;
+			}
+			if (ret)
+				break;
+		}
+		spin_unlock(&drv->lock);
+		if (ret)
+			break;
+	}
+	spin_unlock_irqrestore(&driver_lock, flags);
+	return ret;
+}
+
+void gigaset_debugdrivers(void)
+{
+	unsigned long flags;
+	static struct cardstate *cs;
+	struct gigaset_driver *drv;
+	unsigned i;
+
+	spin_lock_irqsave(&driver_lock, flags);
+	list_for_each_entry(drv, &drivers, list) {
+		dbg(DEBUG_DRIVER, "driver %p", drv);
+		spin_lock(&drv->lock);
+		for (i = 0; i < drv->minors; ++i) {
+			dbg(DEBUG_DRIVER, "  index %u", i);
+			dbg(DEBUG_DRIVER, "    flags 0x%02x", drv->flags[i]);
+			cs = drv->cs + i;
+			dbg(DEBUG_DRIVER, "    cardstate %p", cs);
+			dbg(DEBUG_DRIVER, "    minor_index %u", cs->minor_index);
+			dbg(DEBUG_DRIVER, "    driver %p", cs->driver);
+			dbg(DEBUG_DRIVER, "    i4l id %d", cs->myid);
+		}
+		spin_unlock(&drv->lock);
+	}
+	spin_unlock_irqrestore(&driver_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gigaset_debugdrivers);
+
+struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty)
+{
+	if (tty->index < 0 || tty->index >= tty->driver->num)
+		return NULL;
+	return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start);
+}
+
+struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
+{
+	unsigned long flags;
+	static struct cardstate *ret = NULL;
+	struct gigaset_driver *drv;
+	unsigned index;
+
+	spin_lock_irqsave(&driver_lock, flags);
+	list_for_each_entry(drv, &drivers, list) {
+		if (minor < drv->minor || minor >= drv->minor + drv->minors)
+			continue;
+		index = minor - drv->minor;
+		spin_lock(&drv->lock);
+		if (drv->flags[index] & VALID_MINOR)
+			ret = drv->cs + index;
+		spin_unlock(&drv->lock);
+		if (ret)
+			break;
+	}
+	spin_unlock_irqrestore(&driver_lock, flags);
+	return ret;
+}
+
+void gigaset_freedriver(struct gigaset_driver *drv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&driver_lock, flags);
+	list_del(&drv->list);
+	spin_unlock_irqrestore(&driver_lock, flags);
+
+	gigaset_if_freedriver(drv);
+	module_put(drv->owner);
+
+	kfree(drv->cs);
+	kfree(drv->flags);
+	kfree(drv);
+}
+EXPORT_SYMBOL_GPL(gigaset_freedriver);
+
+/* gigaset_initdriver
+ * Allocate and initialize gigaset_driver structure. Initialize interface.
+ * parameters:
+ *      minor           First minor number
+ *      minors          Number of minors this driver can handle
+ *      procname        Name of the driver (e.g. for /proc/tty/drivers, path in /proc/driver)
+ *      devname         Name of the device files (prefix without minor number)
+ *      devfsname       Devfs name of the device files without %d
+ * return value:
+ *      Pointer to the gigaset_driver structure on success, NULL on failure.
+ */
+struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
+                                          const char *procname,
+                                          const char *devname,
+                                          const char *devfsname,
+                                          const struct gigaset_ops *ops,
+                                          struct module *owner)
+{
+	struct gigaset_driver *drv;
+	unsigned long flags;
+	unsigned i;
+
+	drv = kmalloc(sizeof *drv, GFP_KERNEL);
+	if (!drv)
+		return NULL;
+	if (!try_module_get(owner))
+		return NULL;
+
+	drv->cs = NULL;
+	drv->have_tty = 0;
+	drv->minor = minor;
+	drv->minors = minors;
+	spin_lock_init(&drv->lock);
+	drv->blocked = 0;
+	drv->ops = ops;
+	drv->owner = owner;
+	INIT_LIST_HEAD(&drv->list);
+
+	drv->cs = kmalloc(minors * sizeof *drv->cs, GFP_KERNEL);
+	if (!drv->cs)
+		goto out1;
+	drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL);
+	if (!drv->flags)
+		goto out2;
+
+	for (i = 0; i < minors; ++i) {
+		drv->flags[i] = 0;
+		drv->cs[i].driver = drv;
+		drv->cs[i].ops = drv->ops;
+		drv->cs[i].minor_index = i;
+	}
+
+	gigaset_if_initdriver(drv, procname, devname, devfsname);
+
+	spin_lock_irqsave(&driver_lock, flags);
+	list_add(&drv->list, &drivers);
+	spin_unlock_irqrestore(&driver_lock, flags);
+
+	return drv;
+
+out2:
+	kfree(drv->cs);
+out1:
+	kfree(drv);
+	module_put(owner);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(gigaset_initdriver);
+
+static struct cardstate *alloc_cs(struct gigaset_driver *drv)
+{
+	unsigned long flags;
+	unsigned i;
+	static struct cardstate *ret = NULL;
+
+	spin_lock_irqsave(&drv->lock, flags);
+	for (i = 0; i < drv->minors; ++i) {
+		if (!(drv->flags[i] & VALID_MINOR)) {
+			drv->flags[i] = VALID_MINOR;
+			ret = drv->cs + i;
+		}
+		if (ret)
+			break;
+	}
+	spin_unlock_irqrestore(&drv->lock, flags);
+	return ret;
+}
+
+static void free_cs(struct cardstate *cs)
+{
+	unsigned long flags;
+	struct gigaset_driver *drv = cs->driver;
+	spin_lock_irqsave(&drv->lock, flags);
+	drv->flags[cs->minor_index] = 0;
+	spin_unlock_irqrestore(&drv->lock, flags);
+}
+
+static void make_valid(struct cardstate *cs, unsigned mask)
+{
+	unsigned long flags;
+	struct gigaset_driver *drv = cs->driver;
+	spin_lock_irqsave(&drv->lock, flags);
+	drv->flags[cs->minor_index] |= mask;
+	spin_unlock_irqrestore(&drv->lock, flags);
+}
+
+static void make_invalid(struct cardstate *cs, unsigned mask)
+{
+	unsigned long flags;
+	struct gigaset_driver *drv = cs->driver;
+	spin_lock_irqsave(&drv->lock, flags);
+	drv->flags[cs->minor_index] &= ~mask;
+	spin_unlock_irqrestore(&drv->lock, flags);
+}
+
+/* For drivers without fixed assignment device<->cardstate (usb) */
+struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv)
+{
+	unsigned long flags;
+	struct cardstate *cs = NULL;
+	unsigned i;
+
+	spin_lock_irqsave(&drv->lock, flags);
+	if (drv->blocked)
+		goto exit;
+	for (i = 0; i < drv->minors; ++i) {
+		if ((drv->flags[i] & VALID_MINOR) &&
+		    !(drv->flags[i] & ASSIGNED)) {
+			drv->flags[i] |= ASSIGNED;
+			cs = drv->cs + i;
+			break;
+		}
+	}
+exit:
+	spin_unlock_irqrestore(&drv->lock, flags);
+	return cs;
+}
+EXPORT_SYMBOL_GPL(gigaset_getunassignedcs);
+
+void gigaset_unassign(struct cardstate *cs)
+{
+	unsigned long flags;
+	unsigned *minor_flags;
+	struct gigaset_driver *drv;
+
+	if (!cs)
+		return;
+	drv = cs->driver;
+	spin_lock_irqsave(&drv->lock, flags);
+	minor_flags = drv->flags + cs->minor_index;
+	if (*minor_flags & VALID_MINOR)
+		*minor_flags &= ~ASSIGNED;
+	spin_unlock_irqrestore(&drv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(gigaset_unassign);
+
+void gigaset_blockdriver(struct gigaset_driver *drv)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&drv->lock, flags);
+	drv->blocked = 1;
+	spin_unlock_irqrestore(&drv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(gigaset_blockdriver);
+
+static int __init gigaset_init_module(void)
+{
+	/* in accordance with the principle of least astonishment,
+	 * setting the 'debug' parameter to 1 activates a sensible
+	 * set of default debug levels
+	 */
+	if (gigaset_debuglevel == 1)
+		gigaset_debuglevel = DEBUG_DEFAULT;
+
+	info(DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+	return 0;
+}
+
+static void __exit gigaset_exit_module(void)
+{
+}
+
+module_init(gigaset_init_module);
+module_exit(gigaset_exit_module);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
new file mode 100644
index 0000000..fdcb80b
--- /dev/null
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -0,0 +1,1983 @@
+/*
+ * Stuff used by all variants of the driver
+ *
+ * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>,
+ *                       Hansjoerg Lipp <hjlipp@web.de>,
+ *                       Tilman Schmidt <tilman@imap.cc>.
+ *
+ * =====================================================================
+ *	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.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: ev-layer.c,v 1.4.2.18 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+
+/* ========================================================== */
+/* bit masks for pending commands */
+#define PC_INIT       0x004
+#define PC_DLE0       0x008
+#define PC_DLE1       0x010
+#define PC_CID        0x080
+#define PC_NOCID      0x100
+#define PC_HUP        0x002
+#define PC_DIAL       0x001
+#define PC_ACCEPT     0x040
+#define PC_SHUTDOWN   0x020
+#define PC_CIDMODE    0x200
+#define PC_UMMODE     0x400
+
+/* types of modem responses */
+#define RT_NOTHING 0
+#define RT_ZSAU    1
+#define RT_RING    2
+#define RT_NUMBER  3
+#define RT_STRING  4
+#define RT_HEX     5
+#define RT_ZCAU    6
+
+/* Possible ASCII responses */
+#define RSP_OK           0
+//#define RSP_BUSY       1
+//#define RSP_CONNECT    2
+#define RSP_ZGCI         3
+#define RSP_RING         4
+#define RSP_ZAOC         5
+#define RSP_ZCSTR        6
+#define RSP_ZCFGT        7
+#define RSP_ZCFG         8
+#define RSP_ZCCR         9
+#define RSP_EMPTY        10
+#define RSP_ZLOG         11
+#define RSP_ZCAU         12
+#define RSP_ZMWI         13
+#define RSP_ZABINFO      14
+#define RSP_ZSMLSTCHG    15
+#define RSP_VAR          100
+#define RSP_ZSAU         (RSP_VAR + VAR_ZSAU)
+#define RSP_ZDLE         (RSP_VAR + VAR_ZDLE)
+#define RSP_ZVLS         (RSP_VAR + VAR_ZVLS)
+#define RSP_ZCTP         (RSP_VAR + VAR_ZCTP)
+#define RSP_STR          (RSP_VAR + VAR_NUM)
+#define RSP_NMBR         (RSP_STR + STR_NMBR)
+#define RSP_ZCPN         (RSP_STR + STR_ZCPN)
+#define RSP_ZCON         (RSP_STR + STR_ZCON)
+#define RSP_ZBC          (RSP_STR + STR_ZBC)
+#define RSP_ZHLC         (RSP_STR + STR_ZHLC)
+#define RSP_ERROR       -1       /* ERROR              */
+#define RSP_WRONG_CID   -2       /* unknown cid in cmd */
+//#define RSP_EMPTY     -3
+#define RSP_UNKNOWN     -4       /* unknown response   */
+#define RSP_FAIL        -5       /* internal error     */
+#define RSP_INVAL       -6       /* invalid response   */
+
+#define RSP_NONE        -19
+#define RSP_STRING      -20
+#define RSP_NULL        -21
+//#define RSP_RETRYFAIL -22
+//#define RSP_RETRY     -23
+//#define RSP_SKIP      -24
+#define RSP_INIT        -27
+#define RSP_ANY         -26
+#define RSP_LAST        -28
+#define RSP_NODEV       -9
+
+/* actions for process_response */
+#define ACT_NOTHING		0
+#define ACT_SETDLE1		1
+#define ACT_SETDLE0		2
+#define ACT_FAILINIT		3
+#define ACT_HUPMODEM		4
+#define ACT_CONFIGMODE		5
+#define ACT_INIT		6
+#define ACT_DLE0		7
+#define ACT_DLE1		8
+#define ACT_FAILDLE0		9
+#define ACT_FAILDLE1		10
+#define ACT_RING		11
+#define ACT_CID			12
+#define ACT_FAILCID		13
+#define ACT_SDOWN		14
+#define ACT_FAILSDOWN		15
+#define ACT_DEBUG		16
+#define ACT_WARN		17
+#define ACT_DIALING		18
+#define ACT_ABORTDIAL		19
+#define ACT_DISCONNECT		20
+#define ACT_CONNECT		21
+#define ACT_REMOTEREJECT	22
+#define ACT_CONNTIMEOUT         23
+#define ACT_REMOTEHUP		24
+#define ACT_ABORTHUP		25
+#define ACT_ICALL		26
+#define ACT_ACCEPTED		27
+#define ACT_ABORTACCEPT		28
+#define ACT_TIMEOUT		29
+#define ACT_GETSTRING		30
+#define ACT_SETVER		31
+#define ACT_FAILVER		32
+#define ACT_GOTVER		33
+#define ACT_TEST		34
+#define ACT_ERROR		35
+#define ACT_ABORTCID		36
+#define ACT_ZCAU		37
+#define ACT_NOTIFY_BC_DOWN      38
+#define ACT_NOTIFY_BC_UP        39
+#define ACT_DIAL                40
+#define ACT_ACCEPT              41
+#define ACT_PROTO_L2            42
+#define ACT_HUP                 43
+#define ACT_IF_LOCK             44
+#define ACT_START               45
+#define ACT_STOP                46
+#define ACT_FAKEDLE0            47
+#define ACT_FAKEHUP             48
+#define ACT_FAKESDOWN           49
+#define ACT_SHUTDOWN            50
+#define ACT_PROC_CIDMODE        51
+#define ACT_UMODESET            52
+#define ACT_FAILUMODE           53
+#define ACT_CMODESET            54
+#define ACT_FAILCMODE           55
+#define ACT_IF_VER              56
+#define ACT_CMD			100
+
+/* at command sequences */
+#define SEQ_NONE      0
+#define SEQ_INIT      100
+#define SEQ_DLE0      200
+#define SEQ_DLE1      250
+#define SEQ_CID       300
+#define SEQ_NOCID     350
+#define SEQ_HUP       400
+#define SEQ_DIAL      600
+#define SEQ_ACCEPT    720
+#define SEQ_SHUTDOWN  500
+#define SEQ_CIDMODE   10
+#define SEQ_UMMODE    11
+
+
+// 100: init, 200: dle0, 250:dle1, 300: get cid (dial), 350: "hup" (no cid), 400: hup, 500: reset, 600: dial, 700: ring
+struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */
+{
+	/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
+
+	/* initialize device, set cid mode if possible */
+	//{RSP_INIT,     -1, -1,100,                900, 0, {ACT_TEST}},
+	//{RSP_ERROR,   900,900, -1,                  0, 0, {ACT_FAILINIT}},
+	//{RSP_OK,      900,900, -1,                100, INIT_TIMEOUT,
+	//                                                  {ACT_TIMEOUT}},
+
+	{RSP_INIT,     -1, -1,SEQ_INIT,           100, INIT_TIMEOUT,
+	                                                  {ACT_TIMEOUT}},                /* wait until device is ready */
+
+	{EV_TIMEOUT,  100,100, -1,                101, 3, {0},             "Z\r"},       /* device in transparent mode? try to initialize it. */
+	{RSP_OK,      101,103, -1,                120, 5, {ACT_GETSTRING}, "+GMR\r"},    /* get version */
+
+	{EV_TIMEOUT,  101,101, -1,                102, 5, {0},             "Z\r"},       /* timeout => try once again. */
+	{RSP_ERROR,   101,101, -1,                102, 5, {0},             "Z\r"},       /* error => try once again. */
+
+	{EV_TIMEOUT,  102,102, -1,                108, 5, {ACT_SETDLE1},   "^SDLE=0\r"}, /* timeout => try again in DLE mode. */
+	{RSP_OK,      108,108, -1,                104,-1},
+	{RSP_ZDLE,    104,104,  0,                103, 5, {0},             "Z\r"},
+	{EV_TIMEOUT,  104,104, -1,                  0, 0, {ACT_FAILINIT}},
+	{RSP_ERROR,   108,108, -1,                  0, 0, {ACT_FAILINIT}},
+
+	{EV_TIMEOUT,  108,108, -1,                105, 2, {ACT_SETDLE0,
+	                                                   ACT_HUPMODEM,
+	                                                   ACT_TIMEOUT}},                /* still timeout => connection in unimodem mode? */
+	{EV_TIMEOUT,  105,105, -1,                103, 5, {0},             "Z\r"},
+
+	{RSP_ERROR,   102,102, -1,                107, 5, {0},             "^GETPRE\r"}, /* ERROR on ATZ => maybe in config mode? */
+	{RSP_OK,      107,107, -1,                  0, 0, {ACT_CONFIGMODE}},
+	{RSP_ERROR,   107,107, -1,                  0, 0, {ACT_FAILINIT}},
+	{EV_TIMEOUT,  107,107, -1,                  0, 0, {ACT_FAILINIT}},
+
+	{RSP_ERROR,   103,103, -1,                  0, 0, {ACT_FAILINIT}},
+	{EV_TIMEOUT,  103,103, -1,                  0, 0, {ACT_FAILINIT}},
+
+	{RSP_STRING,  120,120, -1,                121,-1, {ACT_SETVER}},
+
+	{EV_TIMEOUT,  120,121, -1,                  0, 0, {ACT_FAILVER, ACT_INIT}},
+	{RSP_ERROR,   120,121, -1,                  0, 0, {ACT_FAILVER, ACT_INIT}},
+	{RSP_OK,      121,121, -1,                  0, 0, {ACT_GOTVER,  ACT_INIT}},
+#if 0
+	{EV_TIMEOUT,  120,121, -1,                130, 5, {ACT_FAILVER},   "^SGCI=1\r"},
+	{RSP_ERROR,   120,121, -1,                130, 5, {ACT_FAILVER},   "^SGCI=1\r"},
+	{RSP_OK,      121,121, -1,                130, 5, {ACT_GOTVER},    "^SGCI=1\r"},
+
+	{RSP_OK,      130,130, -1,                  0, 0, {ACT_INIT}},
+	{RSP_ERROR,   130,130, -1,                  0, 0, {ACT_FAILINIT}},
+	{EV_TIMEOUT,  130,130, -1,                  0, 0, {ACT_FAILINIT}},
+#endif
+
+	/* leave dle mode */
+	{RSP_INIT,      0,  0,SEQ_DLE0,           201, 5, {0},             "^SDLE=0\r"},
+	{RSP_OK,      201,201, -1,                202,-1},
+	//{RSP_ZDLE,    202,202,  0,                202, 0, {ACT_ERROR}},//DELETE
+	{RSP_ZDLE,    202,202,  0,                  0, 0, {ACT_DLE0}},
+	{RSP_NODEV,   200,249, -1,                  0, 0, {ACT_FAKEDLE0}},
+	{RSP_ERROR,   200,249, -1,                  0, 0, {ACT_FAILDLE0}},
+	{EV_TIMEOUT,  200,249, -1,                  0, 0, {ACT_FAILDLE0}},
+
+	/* enter dle mode */
+	{RSP_INIT,      0,  0,SEQ_DLE1,           251, 5, {0},             "^SDLE=1\r"},
+	{RSP_OK,      251,251, -1,                252,-1},
+	{RSP_ZDLE,    252,252,  1,                  0, 0, {ACT_DLE1}},
+	{RSP_ERROR,   250,299, -1,                  0, 0, {ACT_FAILDLE1}},
+	{EV_TIMEOUT,  250,299, -1,                  0, 0, {ACT_FAILDLE1}},
+
+	/* incoming call */
+	{RSP_RING,     -1, -1, -1,                 -1,-1, {ACT_RING}},
+
+	/* get cid */
+	//{RSP_INIT,      0,  0,300,                901, 0, {ACT_TEST}},
+	//{RSP_ERROR,   901,901, -1,                  0, 0, {ACT_FAILCID}},
+	//{RSP_OK,      901,901, -1,                301, 5, {0},             "^SGCI?\r"},
+
+	{RSP_INIT,      0,  0,SEQ_CID,            301, 5, {0},             "^SGCI?\r"},
+	{RSP_OK,      301,301, -1,                302,-1},
+	{RSP_ZGCI,    302,302, -1,                  0, 0, {ACT_CID}},
+	{RSP_ERROR,   301,349, -1,                  0, 0, {ACT_FAILCID}},
+	{EV_TIMEOUT,  301,349, -1,                  0, 0, {ACT_FAILCID}},
+
+	/* enter cid mode */
+	{RSP_INIT,      0,  0,SEQ_CIDMODE,        150, 5, {0},             "^SGCI=1\r"},
+	{RSP_OK,      150,150, -1,                  0, 0, {ACT_CMODESET}},
+	{RSP_ERROR,   150,150, -1,                  0, 0, {ACT_FAILCMODE}},
+	{EV_TIMEOUT,  150,150, -1,                  0, 0, {ACT_FAILCMODE}},
+
+	/* leave cid mode */
+	//{RSP_INIT,      0,  0,SEQ_UMMODE,         160, 5, {0},             "^SGCI=0\r"},
+	{RSP_INIT,      0,  0,SEQ_UMMODE,         160, 5, {0},             "Z\r"},
+	{RSP_OK,      160,160, -1,                  0, 0, {ACT_UMODESET}},
+	{RSP_ERROR,   160,160, -1,                  0, 0, {ACT_FAILUMODE}},
+	{EV_TIMEOUT,  160,160, -1,                  0, 0, {ACT_FAILUMODE}},
+
+	/* abort getting cid */
+	{RSP_INIT,      0,  0,SEQ_NOCID,            0, 0, {ACT_ABORTCID}},
+
+	/* reset */
+#if 0
+	{RSP_INIT,      0,  0,SEQ_SHUTDOWN,       503, 5, {0},             "^SGCI=0\r"},
+	{RSP_OK,      503,503, -1,                504, 5, {0},             "Z\r"},
+#endif
+	{RSP_INIT,      0,  0,SEQ_SHUTDOWN,       504, 5, {0},             "Z\r"},
+	{RSP_OK,      504,504, -1,                  0, 0, {ACT_SDOWN}},
+	{RSP_ERROR,   501,599, -1,                  0, 0, {ACT_FAILSDOWN}},
+	{EV_TIMEOUT,  501,599, -1,                  0, 0, {ACT_FAILSDOWN}},
+	{RSP_NODEV,   501,599, -1,                  0, 0, {ACT_FAKESDOWN}},
+
+	{EV_PROC_CIDMODE,-1, -1, -1,               -1,-1, {ACT_PROC_CIDMODE}}, //FIXME
+	{EV_IF_LOCK,   -1, -1, -1,                 -1,-1, {ACT_IF_LOCK}}, //FIXME
+	{EV_IF_VER,    -1, -1, -1,                 -1,-1, {ACT_IF_VER}}, //FIXME
+	{EV_START,     -1, -1, -1,                 -1,-1, {ACT_START}}, //FIXME
+	{EV_STOP,      -1, -1, -1,                 -1,-1, {ACT_STOP}}, //FIXME
+	{EV_SHUTDOWN,  -1, -1, -1,                 -1,-1, {ACT_SHUTDOWN}}, //FIXME
+
+	/* misc. */
+	{RSP_EMPTY,    -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZCFGT,    -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZCFG,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZLOG,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZMWI,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZABINFO,  -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZSMLSTCHG,-1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+
+	{RSP_ZCAU,     -1, -1, -1,                 -1,-1, {ACT_ZCAU}},
+	{RSP_NONE,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ANY,      -1, -1, -1,                 -1,-1, {ACT_WARN}},
+	{RSP_LAST}
+};
+
+// 600: start dialing, 650: dial in progress, 800: connection is up, 700: ring, 400: hup, 750: accepted icall
+struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */
+{
+	/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
+
+	/* dial */
+	{EV_DIAL,      -1, -1, -1,                 -1,-1, {ACT_DIAL}}, //FIXME
+	{RSP_INIT,      0,  0,SEQ_DIAL,           601, 5, {ACT_CMD+AT_BC}},
+	{RSP_OK,      601,601, -1,                602, 5, {ACT_CMD+AT_HLC}},
+	{RSP_NULL,    602,602, -1,                603, 5, {ACT_CMD+AT_PROTO}},
+	{RSP_OK,      602,602, -1,                603, 5, {ACT_CMD+AT_PROTO}},
+	{RSP_OK,      603,603, -1,                604, 5, {ACT_CMD+AT_TYPE}},
+	{RSP_OK,      604,604, -1,                605, 5, {ACT_CMD+AT_MSN}},
+	{RSP_OK,      605,605, -1,                606, 5, {ACT_CMD+AT_ISO}},
+	{RSP_NULL,    605,605, -1,                606, 5, {ACT_CMD+AT_ISO}},
+	{RSP_OK,      606,606, -1,                607, 5, {0},             "+VLS=17\r"}, /* set "Endgeraetemodus" */
+	{RSP_OK,      607,607, -1,                608,-1},
+	//{RSP_ZSAU,    608,608,ZSAU_PROCEEDING,    608, 0, {ACT_ERROR}},//DELETE
+	{RSP_ZSAU,    608,608,ZSAU_PROCEEDING,    609, 5, {ACT_CMD+AT_DIAL}},
+	{RSP_OK,      609,609, -1,                650, 0, {ACT_DIALING}},
+
+	{RSP_ZVLS,    608,608, 17,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ZCTP,    609,609, -1,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ZCPN,    609,609, -1,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ERROR,   601,609, -1,                  0, 0, {ACT_ABORTDIAL}},
+	{EV_TIMEOUT,  601,609, -1,                  0, 0, {ACT_ABORTDIAL}},
+
+	/* dialing */
+	{RSP_ZCTP,    650,650, -1,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ZCPN,    650,650, -1,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ZSAU,    650,650,ZSAU_CALL_DELIVERED, -1,-1, {ACT_DEBUG}}, /* some devices don't send this */
+
+	/* connection established  */
+	{RSP_ZSAU,    650,650,ZSAU_ACTIVE,        800,-1, {ACT_CONNECT}}, //FIXME -> DLE1
+	{RSP_ZSAU,    750,750,ZSAU_ACTIVE,        800,-1, {ACT_CONNECT}}, //FIXME -> DLE1
+
+	{EV_BC_OPEN,  800,800, -1,                800,-1, {ACT_NOTIFY_BC_UP}}, //FIXME new constate + timeout
+
+	/* remote hangup */
+	{RSP_ZSAU,    650,650,ZSAU_DISCONNECT_IND,  0, 0, {ACT_REMOTEREJECT}},
+	{RSP_ZSAU,    750,750,ZSAU_DISCONNECT_IND,  0, 0, {ACT_REMOTEHUP}},
+	{RSP_ZSAU,    800,800,ZSAU_DISCONNECT_IND,  0, 0, {ACT_REMOTEHUP}},
+
+	/* hangup */
+	{EV_HUP,       -1, -1, -1,                 -1,-1, {ACT_HUP}}, //FIXME
+	{RSP_INIT,     -1, -1,SEQ_HUP,            401, 5, {0},             "+VLS=0\r"}, /* hang up */ //-1,-1?
+	{RSP_OK,      401,401, -1,                402, 5},
+	{RSP_ZVLS,    402,402,  0,                403, 5},
+	{RSP_ZSAU,    403,403,ZSAU_DISCONNECT_REQ, -1,-1, {ACT_DEBUG}}, /* if not remote hup */
+	//{RSP_ZSAU,    403,403,ZSAU_NULL,          401, 0, {ACT_ERROR}}, //DELETE//FIXME -> DLE0 // should we do this _before_ hanging up for base driver?
+	{RSP_ZSAU,    403,403,ZSAU_NULL,            0, 0, {ACT_DISCONNECT}}, //FIXME -> DLE0 // should we do this _before_ hanging up for base driver?
+	{RSP_NODEV,   401,403, -1,                  0, 0, {ACT_FAKEHUP}}, //FIXME -> DLE0 // should we do this _before_ hanging up for base driver?
+	{RSP_ERROR,   401,401, -1,                  0, 0, {ACT_ABORTHUP}},
+	{EV_TIMEOUT,  401,403, -1,                  0, 0, {ACT_ABORTHUP}},
+
+	{EV_BC_CLOSED,  0,  0, -1,                  0,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME new constate + timeout
+
+	/* ring */
+	{RSP_ZBC,     700,700, -1,                 -1,-1, {0}},
+	{RSP_ZHLC,    700,700, -1,                 -1,-1, {0}},
+	{RSP_NMBR,    700,700, -1,                 -1,-1, {0}},
+	{RSP_ZCPN,    700,700, -1,                 -1,-1, {0}},
+	{RSP_ZCTP,    700,700, -1,                 -1,-1, {0}},
+	{EV_TIMEOUT,  700,700, -1,               720,720, {ACT_ICALL}},
+	{EV_BC_CLOSED,720,720, -1,                  0,-1, {ACT_NOTIFY_BC_DOWN}},
+
+	/*accept icall*/
+	{EV_ACCEPT,    -1, -1, -1,                 -1,-1, {ACT_ACCEPT}}, //FIXME
+	{RSP_INIT,    720,720,SEQ_ACCEPT,         721, 5, {ACT_CMD+AT_PROTO}},
+	{RSP_OK,      721,721, -1,                722, 5, {ACT_CMD+AT_ISO}},
+	{RSP_OK,      722,722, -1,                723, 5, {0},             "+VLS=17\r"}, /* set "Endgeraetemodus" */
+	{RSP_OK,      723,723, -1,                724, 5, {0}},
+	{RSP_ZVLS,    724,724, 17,                750,50, {ACT_ACCEPTED}},
+	{RSP_ERROR,   721,729, -1,                  0, 0, {ACT_ABORTACCEPT}},
+	{EV_TIMEOUT,  721,729, -1,                  0, 0, {ACT_ABORTACCEPT}},
+	{RSP_ZSAU,    700,729,ZSAU_NULL,            0, 0, {ACT_ABORTACCEPT}},
+	{RSP_ZSAU,    700,729,ZSAU_ACTIVE,          0, 0, {ACT_ABORTACCEPT}},
+	{RSP_ZSAU,    700,729,ZSAU_DISCONNECT_IND,  0, 0, {ACT_ABORTACCEPT}},
+
+	{EV_TIMEOUT,  750,750, -1,                  0, 0, {ACT_CONNTIMEOUT}},
+
+	/* misc. */
+	{EV_PROTO_L2,  -1, -1, -1,                 -1,-1, {ACT_PROTO_L2}}, //FIXME
+
+	{RSP_ZCON,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZCCR,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZAOC,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZCSTR,    -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+
+	{RSP_ZCAU,     -1, -1, -1,                 -1,-1, {ACT_ZCAU}},
+	{RSP_NONE,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ANY,      -1, -1, -1,                 -1,-1, {ACT_WARN}},
+	{RSP_LAST}
+};
+
+
+#if 0
+static struct reply_t tab_nocid[]= /* no dle mode */ //FIXME aenderungen uebernehmen
+{
+	/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
+
+	{RSP_ANY,      -1, -1, -1,                 -1,-1, ACT_WARN,         NULL},
+	{RSP_LAST,0,0,0,0,0,0}
+};
+
+static struct reply_t tab_cid[] = /* no dle mode */ //FIXME aenderungen uebernehmen
+{
+	/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
+
+	{RSP_ANY,      -1, -1, -1,                 -1,-1, ACT_WARN,         NULL},
+	{RSP_LAST,0,0,0,0,0,0}
+};
+#endif
+
+static struct resp_type_t resp_type[]=
+{
+	/*{"",          RSP_EMPTY,  RT_NOTHING},*/
+	{"OK",        RSP_OK,     RT_NOTHING},
+	{"ERROR",     RSP_ERROR,  RT_NOTHING},
+	{"ZSAU",      RSP_ZSAU,   RT_ZSAU},
+	{"ZCAU",      RSP_ZCAU,   RT_ZCAU},
+	{"RING",      RSP_RING,   RT_RING},
+	{"ZGCI",      RSP_ZGCI,   RT_NUMBER},
+	{"ZVLS",      RSP_ZVLS,   RT_NUMBER},
+	{"ZCTP",      RSP_ZCTP,   RT_NUMBER},
+	{"ZDLE",      RSP_ZDLE,   RT_NUMBER},
+	{"ZCFGT",     RSP_ZCFGT,  RT_NUMBER},
+	{"ZCCR",      RSP_ZCCR,   RT_NUMBER},
+	{"ZMWI",      RSP_ZMWI,   RT_NUMBER},
+	{"ZHLC",      RSP_ZHLC,   RT_STRING},
+	{"ZBC",       RSP_ZBC,    RT_STRING},
+	{"NMBR",      RSP_NMBR,   RT_STRING},
+	{"ZCPN",      RSP_ZCPN,   RT_STRING},
+	{"ZCON",      RSP_ZCON,   RT_STRING},
+	{"ZAOC",      RSP_ZAOC,   RT_STRING},
+	{"ZCSTR",     RSP_ZCSTR,  RT_STRING},
+	{"ZCFG",      RSP_ZCFG,   RT_HEX},
+	{"ZLOG",      RSP_ZLOG,   RT_NOTHING},
+	{"ZABINFO",   RSP_ZABINFO, RT_NOTHING},
+	{"ZSMLSTCHG", RSP_ZSMLSTCHG, RT_NOTHING},
+	{NULL,0,0}
+};
+
+/*
+ * Get integer from char-pointer
+ */
+static int isdn_getnum(char *p)
+{
+	int v = -1;
+
+	IFNULLRETVAL(p, -1);
+
+	dbg(DEBUG_TRANSCMD, "string: %s", p);
+
+	while (*p >= '0' && *p <= '9')
+		v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p++) - '0');
+	if (*p)
+		v = -1; /* invalid Character */
+	return v;
+}
+
+/*
+ * Get integer from char-pointer
+ */
+static int isdn_gethex(char *p)
+{
+	int v = 0;
+	int c;
+
+	IFNULLRETVAL(p, -1);
+
+	dbg(DEBUG_TRANSCMD, "string: %s", p);
+
+	if (!*p)
+		return -1;
+
+	do {
+		if (v > (INT_MAX - 15) / 16)
+			return -1;
+		c = *p;
+		if (c >= '0' && c <= '9')
+			c -= '0';
+		else if (c >= 'a' && c <= 'f')
+			c -= 'a' - 10;
+		else if (c >= 'A' && c <= 'F')
+			c -= 'A' - 10;
+		else
+			return -1;
+		v = v * 16 + c;
+	} while (*++p);
+
+	return v;
+}
+
+static inline void new_index(atomic_t *index, int max)
+{
+	if (atomic_read(index) == max)	//FIXME race?
+		atomic_set(index, 0);
+	else
+		atomic_inc(index);
+}
+
+/* retrieve CID from parsed response
+ * returns 0 if no CID, -1 if invalid CID, or CID value 1..65535
+ */
+static int cid_of_response(char *s)
+{
+	int cid;
+
+	if (s[-1] != ';')
+		return 0;	/* no CID separator */
+	cid = isdn_getnum(s);
+	if (cid < 0)
+		return 0;	/* CID not numeric */
+	if (cid < 1 || cid > 65535)
+		return -1;	/* CID out of range */
+	return cid;
+	//FIXME is ;<digit>+ at end of non-CID response really impossible?
+}
+
+/* This function will be called via task queue from the callback handler.
+ * We received a modem response and have to handle it..
+ */
+void gigaset_handle_modem_response(struct cardstate *cs)
+{
+	unsigned char *argv[MAX_REC_PARAMS + 1];
+	int params;
+	int i, j;
+	struct resp_type_t *rt;
+	int curarg;
+	unsigned long flags;
+	unsigned next, tail, head;
+	struct event_t *event;
+	int resp_code;
+	int param_type;
+	int abort;
+	size_t len;
+	int cid;
+	int rawstring;
+
+	IFNULLRET(cs);
+
+	len = cs->cbytes;
+	if (!len) {
+		/* ignore additional LFs/CRs (M10x config mode or cx100) */
+		dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[len]);
+		return;
+	}
+	cs->respdata[len] = 0;
+	dbg(DEBUG_TRANSCMD, "raw string: '%s'", cs->respdata);
+	argv[0] = cs->respdata;
+	params = 1;
+	if (cs->at_state.getstring) {
+		/* getstring only allowed without cid at the moment */
+		cs->at_state.getstring = 0;
+		rawstring = 1;
+		cid = 0;
+	} else {
+		/* parse line */
+		for (i = 0; i < len; i++)
+			switch (cs->respdata[i]) {
+			case ';':
+			case ',':
+			case '=':
+				if (params > MAX_REC_PARAMS) {
+					warn("too many parameters in response");
+					/* need last parameter (might be CID) */
+					params--;
+				}
+				argv[params++] = cs->respdata + i + 1;
+			}
+
+		rawstring = 0;
+		cid = params > 1 ? cid_of_response(argv[params-1]) : 0;
+		if (cid < 0) {
+			gigaset_add_event(cs, &cs->at_state, RSP_INVAL,
+			                  NULL, 0, NULL);
+			return;
+		}
+
+		for (j = 1; j < params; ++j)
+			argv[j][-1] = 0;
+
+		dbg(DEBUG_TRANSCMD, "CMD received: %s", argv[0]);
+		if (cid) {
+			--params;
+			dbg(DEBUG_TRANSCMD, "CID: %s", argv[params]);
+		}
+		dbg(DEBUG_TRANSCMD, "available params: %d", params - 1);
+		for (j = 1; j < params; j++)
+			dbg(DEBUG_TRANSCMD, "param %d: %s", j, argv[j]);
+	}
+
+	spin_lock_irqsave(&cs->ev_lock, flags);
+	head = atomic_read(&cs->ev_head);
+	tail = atomic_read(&cs->ev_tail);
+
+	abort = 1;
+	curarg = 0;
+	while (curarg < params) {
+		next = (tail + 1) % MAX_EVENTS;
+		if (unlikely(next == head)) {
+			err("event queue full");
+			break;
+		}
+
+		event = cs->events + tail;
+		event->at_state = NULL;
+		event->cid = cid;
+		event->ptr = NULL;
+		event->arg = NULL;
+		tail = next;
+
+		if (rawstring) {
+			resp_code = RSP_STRING;
+			param_type = RT_STRING;
+		} else {
+			for (rt = resp_type; rt->response; ++rt)
+				if (!strcmp(argv[curarg], rt->response))
+					break;
+
+			if (!rt->response) {
+				event->type = RSP_UNKNOWN;
+				warn("unknown modem response: %s",
+				     argv[curarg]);
+				break;
+			}
+
+			resp_code = rt->resp_code;
+			param_type = rt->type;
+			++curarg;
+		}
+
+		event->type = resp_code;
+
+		switch (param_type) {
+		case RT_NOTHING:
+			break;
+		case RT_RING:
+			if (!cid) {
+				err("received RING without CID!");
+				event->type = RSP_INVAL;
+				abort = 1;
+			} else {
+				event->cid = 0;
+				event->parameter = cid;
+				abort = 0;
+			}
+			break;
+		case RT_ZSAU:
+			if (curarg >= params) {
+				event->parameter = ZSAU_NONE;
+				break;
+			}
+			if (!strcmp(argv[curarg], "OUTGOING_CALL_PROCEEDING"))
+				event->parameter = ZSAU_OUTGOING_CALL_PROCEEDING;
+			else if (!strcmp(argv[curarg], "CALL_DELIVERED"))
+				event->parameter = ZSAU_CALL_DELIVERED;
+			else if (!strcmp(argv[curarg], "ACTIVE"))
+				event->parameter = ZSAU_ACTIVE;
+			else if (!strcmp(argv[curarg], "DISCONNECT_IND"))
+				event->parameter = ZSAU_DISCONNECT_IND;
+			else if (!strcmp(argv[curarg], "NULL"))
+				event->parameter = ZSAU_NULL;
+			else if (!strcmp(argv[curarg], "DISCONNECT_REQ"))
+				event->parameter = ZSAU_DISCONNECT_REQ;
+			else {
+				event->parameter = ZSAU_UNKNOWN;
+				warn("%s: unknown parameter %s after ZSAU",
+				     __func__, argv[curarg]);
+			}
+			++curarg;
+			break;
+		case RT_STRING:
+			if (curarg < params) {
+				len = strlen(argv[curarg]) + 1;
+				event->ptr = kmalloc(len, GFP_ATOMIC);
+				if (event->ptr)
+					memcpy(event->ptr, argv[curarg], len);
+				else
+					err("no memory for string!");
+				++curarg;
+			}
+#ifdef CONFIG_GIGASET_DEBUG
+			if (!event->ptr)
+				dbg(DEBUG_CMD, "string==NULL");
+			else
+				dbg(DEBUG_CMD,
+				    "string==%s", (char *) event->ptr);
+#endif
+			break;
+		case RT_ZCAU:
+			event->parameter = -1;
+			if (curarg + 1 < params) {
+				i = isdn_gethex(argv[curarg]);
+				j = isdn_gethex(argv[curarg + 1]);
+				if (i >= 0 && i < 256 && j >= 0 && j < 256)
+					event->parameter = (unsigned) i << 8
+					                   | j;
+				curarg += 2;
+			} else
+				curarg = params - 1;
+			break;
+		case RT_NUMBER:
+		case RT_HEX:
+			if (curarg < params) {
+				if (param_type == RT_HEX)
+					event->parameter =
+						isdn_gethex(argv[curarg]);
+				else
+					event->parameter =
+						isdn_getnum(argv[curarg]);
+				++curarg;
+			} else
+				event->parameter = -1;
+#ifdef CONFIG_GIGASET_DEBUG
+			dbg(DEBUG_CMD, "parameter==%d", event->parameter);
+#endif
+			break;
+		}
+
+		if (resp_code == RSP_ZDLE)
+			cs->dle = event->parameter;
+
+		if (abort)
+			break;
+	}
+
+	atomic_set(&cs->ev_tail, tail);
+	spin_unlock_irqrestore(&cs->ev_lock, flags);
+
+	if (curarg != params)
+		dbg(DEBUG_ANY, "invalid number of processed parameters: %d/%d",
+		    curarg, params);
+}
+EXPORT_SYMBOL_GPL(gigaset_handle_modem_response);
+
+/* disconnect
+ * process closing of connection associated with given AT state structure
+ */
+static void disconnect(struct at_state_t **at_state_p)
+{
+	unsigned long flags;
+	struct bc_state *bcs;
+	struct cardstate *cs;
+
+	IFNULLRET(at_state_p);
+	IFNULLRET(*at_state_p);
+	bcs = (*at_state_p)->bcs;
+	cs = (*at_state_p)->cs;
+	IFNULLRET(cs);
+
+	new_index(&(*at_state_p)->seq_index, MAX_SEQ_INDEX);
+
+	/* revert to selected idle mode */
+	if (!atomic_read(&cs->cidmode)) {
+		cs->at_state.pending_commands |= PC_UMMODE;
+		atomic_set(&cs->commands_pending, 1); //FIXME
+		dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
+	}
+
+	if (bcs) {
+		/* B channel assigned: invoke hardware specific handler */
+		cs->ops->close_bchannel(bcs);
+	} else {
+		/* no B channel assigned: just deallocate */
+		spin_lock_irqsave(&cs->lock, flags);
+		list_del(&(*at_state_p)->list);
+		kfree(*at_state_p);
+		*at_state_p = NULL;
+		spin_unlock_irqrestore(&cs->lock, flags);
+	}
+}
+
+/* get_free_channel
+ * get a free AT state structure: either one of those associated with the
+ * B channels of the Gigaset device, or if none of those is available,
+ * a newly allocated one with bcs=NULL
+ * The structure should be freed by calling disconnect() after use.
+ */
+static inline struct at_state_t *get_free_channel(struct cardstate *cs,
+                                                  int cid)
+/* cids: >0: siemens-cid
+	  0: without cid
+	 -1: no cid assigned yet
+*/
+{
+	unsigned long flags;
+	int i;
+	struct at_state_t *ret;
+
+	for (i = 0; i < cs->channels; ++i)
+		if (gigaset_get_channel(cs->bcs + i)) {
+			ret = &cs->bcs[i].at_state;
+			ret->cid = cid;
+			return ret;
+		}
+
+	spin_lock_irqsave(&cs->lock, flags);
+	ret = kmalloc(sizeof(struct at_state_t), GFP_ATOMIC);
+	if (ret) {
+		gigaset_at_init(ret, NULL, cs, cid);
+		list_add(&ret->list, &cs->temp_at_states);
+	}
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return ret;
+}
+
+static void init_failed(struct cardstate *cs, int mode)
+{
+	int i;
+	struct at_state_t *at_state;
+
+	cs->at_state.pending_commands &= ~PC_INIT;
+	atomic_set(&cs->mode, mode);
+	atomic_set(&cs->mstate, MS_UNINITIALIZED);
+	gigaset_free_channels(cs);
+	for (i = 0; i < cs->channels; ++i) {
+		at_state = &cs->bcs[i].at_state;
+		if (at_state->pending_commands & PC_CID) {
+			at_state->pending_commands &= ~PC_CID;
+			at_state->pending_commands |= PC_NOCID;
+			atomic_set(&cs->commands_pending, 1);
+		}
+	}
+}
+
+static void schedule_init(struct cardstate *cs, int state)
+{
+	if (cs->at_state.pending_commands & PC_INIT) {
+		dbg(DEBUG_CMD, "not scheduling PC_INIT again");
+		return;
+	}
+	atomic_set(&cs->mstate, state);
+	atomic_set(&cs->mode, M_UNKNOWN);
+	gigaset_block_channels(cs);
+	cs->at_state.pending_commands |= PC_INIT;
+	atomic_set(&cs->commands_pending, 1);
+	dbg(DEBUG_CMD, "Scheduling PC_INIT");
+}
+
+/* Add "AT" to a command, add the cid, dle encode it, send the result to the hardware. */
+static void send_command(struct cardstate *cs, const char *cmd, int cid,
+                         int dle, gfp_t kmallocflags)
+{
+	size_t cmdlen, buflen;
+	char *cmdpos, *cmdbuf, *cmdtail;
+
+	cmdlen = strlen(cmd);
+	buflen = 11 + cmdlen;
+
+	if (likely(buflen > cmdlen)) {
+		cmdbuf = kmalloc(buflen, kmallocflags);
+		if (likely(cmdbuf != NULL)) {
+			cmdpos = cmdbuf + 9;
+			cmdtail = cmdpos + cmdlen;
+			memcpy(cmdpos, cmd, cmdlen);
+
+			if (cid > 0 && cid <= 65535) {
+				do {
+					*--cmdpos = '0' + cid % 10;
+					cid /= 10;
+					++cmdlen;
+				} while (cid);
+			}
+
+			cmdlen += 2;
+			*--cmdpos = 'T';
+			*--cmdpos = 'A';
+
+			if (dle) {
+				cmdlen += 4;
+				*--cmdpos = '(';
+				*--cmdpos = 0x10;
+				*cmdtail++ = 0x10;
+				*cmdtail++ = ')';
+			}
+
+			cs->ops->write_cmd(cs, cmdpos, cmdlen, NULL);
+			kfree(cmdbuf);
+		} else
+			err("no memory for command buffer");
+	} else
+		err("overflow in buflen");
+}
+
+static struct at_state_t *at_state_from_cid(struct cardstate *cs, int cid)
+{
+	struct at_state_t *at_state;
+	int i;
+	unsigned long flags;
+
+	if (cid == 0)
+		return &cs->at_state;
+
+	for (i = 0; i < cs->channels; ++i)
+		if (cid == cs->bcs[i].at_state.cid)
+			return &cs->bcs[i].at_state;
+
+	spin_lock_irqsave(&cs->lock, flags);
+
+	list_for_each_entry(at_state, &cs->temp_at_states, list)
+		if (cid == at_state->cid) {
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return at_state;
+		}
+
+	spin_unlock_irqrestore(&cs->lock, flags);
+
+	return NULL;
+}
+
+static void bchannel_down(struct bc_state *bcs)
+{
+	IFNULLRET(bcs);
+	IFNULLRET(bcs->cs);
+
+	if (bcs->chstate & CHS_B_UP) {
+		bcs->chstate &= ~CHS_B_UP;
+		gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP);
+	}
+
+	if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) {
+		bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL);
+		gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP);
+	}
+
+	gigaset_free_channel(bcs);
+
+	gigaset_bcs_reinit(bcs);
+}
+
+static void bchannel_up(struct bc_state *bcs)
+{
+	IFNULLRET(bcs);
+
+	if (!(bcs->chstate & CHS_D_UP)) {
+		notice("%s: D channel not up", __func__);
+		bcs->chstate |= CHS_D_UP;
+		gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
+	}
+
+	if (bcs->chstate & CHS_B_UP) {
+		notice("%s: B channel already up", __func__);
+		return;
+	}
+
+	bcs->chstate |= CHS_B_UP;
+	gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN);
+}
+
+static void start_dial(struct at_state_t *at_state, void *data, int seq_index)
+{
+	struct bc_state *bcs = at_state->bcs;
+	struct cardstate *cs = at_state->cs;
+	int retval;
+
+	bcs->chstate |= CHS_NOTIFY_LL;
+	//atomic_set(&bcs->status, BCS_INIT);
+
+	if (atomic_read(&at_state->seq_index) != seq_index)
+		goto error;
+
+	retval = gigaset_isdn_setup_dial(at_state, data);
+	if (retval != 0)
+		goto error;
+
+
+	at_state->pending_commands |= PC_CID;
+	dbg(DEBUG_CMD, "Scheduling PC_CID");
+//#ifdef GIG_MAYINITONDIAL
+//	if (atomic_read(&cs->MState) == MS_UNKNOWN) {
+//		cs->at_state.pending_commands |= PC_INIT;
+//		dbg(DEBUG_CMD, "Scheduling PC_INIT");
+//	}
+//#endif
+	atomic_set(&cs->commands_pending, 1); //FIXME
+	return;
+
+error:
+	at_state->pending_commands |= PC_NOCID;
+	dbg(DEBUG_CMD, "Scheduling PC_NOCID");
+	atomic_set(&cs->commands_pending, 1); //FIXME
+	return;
+}
+
+static void start_accept(struct at_state_t *at_state)
+{
+	struct cardstate *cs = at_state->cs;
+	int retval;
+
+	retval = gigaset_isdn_setup_accept(at_state);
+
+	if (retval == 0) {
+		at_state->pending_commands |= PC_ACCEPT;
+		dbg(DEBUG_CMD, "Scheduling PC_ACCEPT");
+		atomic_set(&cs->commands_pending, 1); //FIXME
+	} else {
+		//FIXME
+		at_state->pending_commands |= PC_HUP;
+		dbg(DEBUG_CMD, "Scheduling PC_HUP");
+		atomic_set(&cs->commands_pending, 1); //FIXME
+	}
+}
+
+static void do_start(struct cardstate *cs)
+{
+	gigaset_free_channels(cs);
+
+	if (atomic_read(&cs->mstate) != MS_LOCKED)
+		schedule_init(cs, MS_INIT);
+
+	gigaset_i4l_cmd(cs, ISDN_STAT_RUN);
+	                                // FIXME: not in locked mode
+	                                // FIXME 2: only after init sequence
+
+	cs->waiting = 0;
+	wake_up(&cs->waitqueue);
+}
+
+static void finish_shutdown(struct cardstate *cs)
+{
+	if (atomic_read(&cs->mstate) != MS_LOCKED) {
+		atomic_set(&cs->mstate, MS_UNINITIALIZED);
+		atomic_set(&cs->mode, M_UNKNOWN);
+	}
+
+	/* The rest is done by cleanup_cs () in user mode. */
+
+	cs->cmd_result = -ENODEV;
+	cs->waiting = 0;
+	wake_up_interruptible(&cs->waitqueue);
+}
+
+static void do_shutdown(struct cardstate *cs)
+{
+	gigaset_block_channels(cs);
+
+	if (atomic_read(&cs->mstate) == MS_READY) {
+		atomic_set(&cs->mstate, MS_SHUTDOWN);
+		cs->at_state.pending_commands |= PC_SHUTDOWN;
+		atomic_set(&cs->commands_pending, 1); //FIXME
+		dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN"); //FIXME
+		//gigaset_schedule_event(cs); //FIXME
+	} else
+		finish_shutdown(cs);
+}
+
+static void do_stop(struct cardstate *cs)
+{
+	do_shutdown(cs);
+}
+
+/* Entering cid mode or getting a cid failed:
+ * try to initialize the device and try again.
+ *
+ * channel >= 0: getting cid for the channel failed
+ * channel < 0:  entering cid mode failed
+ *
+ * returns 0 on failure
+ */
+static int reinit_and_retry(struct cardstate *cs, int channel)
+{
+	int i;
+
+	if (--cs->retry_count <= 0)
+		return 0;
+
+	for (i = 0; i < cs->channels; ++i)
+		if (cs->bcs[i].at_state.cid > 0)
+			return 0;
+
+	if (channel < 0)
+		warn("Could not enter cid mode. Reinit device and try again.");
+	else {
+		warn("Could not get a call id. Reinit device and try again.");
+		cs->bcs[channel].at_state.pending_commands |= PC_CID;
+	}
+	schedule_init(cs, MS_INIT);
+	return 1;
+}
+
+static int at_state_invalid(struct cardstate *cs,
+                            struct at_state_t *test_ptr)
+{
+	unsigned long flags;
+	unsigned channel;
+	struct at_state_t *at_state;
+	int retval = 0;
+
+	spin_lock_irqsave(&cs->lock, flags);
+
+	if (test_ptr == &cs->at_state)
+		goto exit;
+
+	list_for_each_entry(at_state, &cs->temp_at_states, list)
+		if (at_state == test_ptr)
+			goto exit;
+
+	for (channel = 0; channel < cs->channels; ++channel)
+		if (&cs->bcs[channel].at_state == test_ptr)
+			goto exit;
+
+	retval = 1;
+exit:
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return retval;
+}
+
+static void handle_icall(struct cardstate *cs, struct bc_state *bcs,
+			 struct at_state_t **p_at_state)
+{
+	int retval;
+	struct at_state_t *at_state = *p_at_state;
+
+	retval = gigaset_isdn_icall(at_state);
+	switch (retval) {
+	case ICALL_ACCEPT:
+		break;
+	default:
+		err("internal error: disposition=%d", retval);
+		/* --v-- fall through --v-- */
+	case ICALL_IGNORE:
+	case ICALL_REJECT:
+		/* hang up actively
+		 * Device doc says that would reject the call.
+		 * In fact it doesn't.
+		 */
+		at_state->pending_commands |= PC_HUP;
+		atomic_set(&cs->commands_pending, 1);
+		break;
+	}
+}
+
+static int do_lock(struct cardstate *cs)
+{
+	int mode;
+	int i;
+
+	switch (atomic_read(&cs->mstate)) {
+	case MS_UNINITIALIZED:
+	case MS_READY:
+		if (cs->cur_at_seq || !list_empty(&cs->temp_at_states) ||
+		    cs->at_state.pending_commands)
+			return -EBUSY;
+
+		for (i = 0; i < cs->channels; ++i)
+			if (cs->bcs[i].at_state.pending_commands)
+				return -EBUSY;
+
+		if (!gigaset_get_channels(cs))
+			return -EBUSY;
+
+		break;
+	case MS_LOCKED:
+		//retval = -EACCES;
+		break;
+	default:
+		return -EBUSY;
+	}
+
+	mode = atomic_read(&cs->mode);
+	atomic_set(&cs->mstate, MS_LOCKED);
+	atomic_set(&cs->mode, M_UNKNOWN);
+	//FIXME reset card state / at states / bcs states
+
+	return mode;
+}
+
+static int do_unlock(struct cardstate *cs)
+{
+	if (atomic_read(&cs->mstate) != MS_LOCKED)
+		return -EINVAL;
+
+	atomic_set(&cs->mstate, MS_UNINITIALIZED);
+	atomic_set(&cs->mode, M_UNKNOWN);
+	gigaset_free_channels(cs);
+	//FIXME reset card state / at states / bcs states
+	if (atomic_read(&cs->connected))
+		schedule_init(cs, MS_INIT);
+
+	return 0;
+}
+
+static void do_action(int action, struct cardstate *cs,
+		      struct bc_state *bcs,
+		      struct at_state_t **p_at_state, char **pp_command,
+		      int *p_genresp, int *p_resp_code,
+		      struct event_t *ev)
+{
+	struct at_state_t *at_state = *p_at_state;
+	struct at_state_t *at_state2;
+	unsigned long flags;
+
+	int channel;
+
+	unsigned char *s, *e;
+	int i;
+	unsigned long val;
+
+	switch (action) {
+	case ACT_NOTHING:
+		break;
+	case ACT_TIMEOUT:
+		at_state->waiting = 1;
+		break;
+	case ACT_INIT:
+		//FIXME setup everything
+		cs->at_state.pending_commands &= ~PC_INIT;
+		cs->cur_at_seq = SEQ_NONE;
+		atomic_set(&cs->mode, M_UNIMODEM);
+		if (!atomic_read(&cs->cidmode)) {
+			gigaset_free_channels(cs);
+			atomic_set(&cs->mstate, MS_READY);
+			break;
+		}
+		cs->at_state.pending_commands |= PC_CIDMODE;
+		atomic_set(&cs->commands_pending, 1); //FIXME
+		dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
+		break;
+	case ACT_FAILINIT:
+		warn("Could not initialize the device.");
+		cs->dle = 0;
+		init_failed(cs, M_UNKNOWN);
+		cs->cur_at_seq = SEQ_NONE;
+		break;
+	case ACT_CONFIGMODE:
+		init_failed(cs, M_CONFIG);
+		cs->cur_at_seq = SEQ_NONE;
+		break;
+	case ACT_SETDLE1:
+		cs->dle = 1;
+		/* cs->inbuf[0].inputstate |= INS_command | INS_DLE_command; */
+		cs->inbuf[0].inputstate &=
+			~(INS_command | INS_DLE_command);
+		break;
+	case ACT_SETDLE0:
+		cs->dle = 0;
+		cs->inbuf[0].inputstate =
+			(cs->inbuf[0].inputstate & ~INS_DLE_command)
+			| INS_command;
+		break;
+	case ACT_CMODESET:
+		if (atomic_read(&cs->mstate) == MS_INIT ||
+		    atomic_read(&cs->mstate) == MS_RECOVER) {
+			gigaset_free_channels(cs);
+			atomic_set(&cs->mstate, MS_READY);
+		}
+		atomic_set(&cs->mode, M_CID);
+		cs->cur_at_seq = SEQ_NONE;
+		break;
+	case ACT_UMODESET:
+		atomic_set(&cs->mode, M_UNIMODEM);
+		cs->cur_at_seq = SEQ_NONE;
+		break;
+	case ACT_FAILCMODE:
+		cs->cur_at_seq = SEQ_NONE;
+		if (atomic_read(&cs->mstate) == MS_INIT ||
+		    atomic_read(&cs->mstate) == MS_RECOVER) {
+			init_failed(cs, M_UNKNOWN);
+			break;
+		}
+		if (!reinit_and_retry(cs, -1))
+			schedule_init(cs, MS_RECOVER);
+		break;
+	case ACT_FAILUMODE:
+		cs->cur_at_seq = SEQ_NONE;
+		schedule_init(cs, MS_RECOVER);
+		break;
+	case ACT_HUPMODEM:
+		/* send "+++" (hangup in unimodem mode) */
+		cs->ops->write_cmd(cs, "+++", 3, NULL);
+		break;
+	case ACT_RING:
+		/* get fresh AT state structure for new CID */
+		at_state2 = get_free_channel(cs, ev->parameter);
+		if (!at_state2) {
+			warn("RING ignored: "
+			     "could not allocate channel structure");
+			break;
+		}
+
+		/* initialize AT state structure
+		 * note that bcs may be NULL if no B channel is free
+		 */
+		at_state2->ConState = 700;
+		kfree(at_state2->str_var[STR_NMBR]);
+		at_state2->str_var[STR_NMBR] = NULL;
+		kfree(at_state2->str_var[STR_ZCPN]);
+		at_state2->str_var[STR_ZCPN] = NULL;
+		kfree(at_state2->str_var[STR_ZBC]);
+		at_state2->str_var[STR_ZBC] = NULL;
+		kfree(at_state2->str_var[STR_ZHLC]);
+		at_state2->str_var[STR_ZHLC] = NULL;
+		at_state2->int_var[VAR_ZCTP] = -1;
+
+		spin_lock_irqsave(&cs->lock, flags);
+		at_state2->timer_expires = RING_TIMEOUT;
+		at_state2->timer_active = 1;
+		spin_unlock_irqrestore(&cs->lock, flags);
+		break;
+	case ACT_ICALL:
+		handle_icall(cs, bcs, p_at_state);
+		at_state = *p_at_state;
+		break;
+	case ACT_FAILSDOWN:
+		warn("Could not shut down the device.");
+		/* fall through */
+	case ACT_FAKESDOWN:
+	case ACT_SDOWN:
+		cs->cur_at_seq = SEQ_NONE;
+		finish_shutdown(cs);
+		break;
+	case ACT_CONNECT:
+		if (cs->onechannel) {
+			at_state->pending_commands |= PC_DLE1;
+			atomic_set(&cs->commands_pending, 1);
+			break;
+		}
+		bcs->chstate |= CHS_D_UP;
+		gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
+		cs->ops->init_bchannel(bcs);
+		break;
+	case ACT_DLE1:
+		cs->cur_at_seq = SEQ_NONE;
+		bcs = cs->bcs + cs->curchannel;
+
+		bcs->chstate |= CHS_D_UP;
+		gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
+		cs->ops->init_bchannel(bcs);
+		break;
+	case ACT_FAKEHUP:
+		at_state->int_var[VAR_ZSAU] = ZSAU_NULL;
+		/* fall through */
+	case ACT_DISCONNECT:
+		cs->cur_at_seq = SEQ_NONE;
+		at_state->cid = -1;
+		if (bcs && cs->onechannel && cs->dle) {
+			/* Check for other open channels not needed:
+			 * DLE only used for M10x with one B channel.
+			 */
+			at_state->pending_commands |= PC_DLE0;
+			atomic_set(&cs->commands_pending, 1);
+		} else {
+			disconnect(p_at_state);
+			at_state = *p_at_state;
+		}
+		break;
+	case ACT_FAKEDLE0:
+		at_state->int_var[VAR_ZDLE] = 0;
+		cs->dle = 0;
+		/* fall through */
+	case ACT_DLE0:
+		cs->cur_at_seq = SEQ_NONE;
+		at_state2 = &cs->bcs[cs->curchannel].at_state;
+		disconnect(&at_state2);
+		break;
+	case ACT_ABORTHUP:
+		cs->cur_at_seq = SEQ_NONE;
+		warn("Could not hang up.");
+		at_state->cid = -1;
+		if (bcs && cs->onechannel)
+			at_state->pending_commands |= PC_DLE0;
+		else {
+			disconnect(p_at_state);
+			at_state = *p_at_state;
+		}
+		schedule_init(cs, MS_RECOVER);
+		break;
+	case ACT_FAILDLE0:
+		cs->cur_at_seq = SEQ_NONE;
+		warn("Could not leave DLE mode.");
+		at_state2 = &cs->bcs[cs->curchannel].at_state;
+		disconnect(&at_state2);
+		schedule_init(cs, MS_RECOVER);
+		break;
+	case ACT_FAILDLE1:
+		cs->cur_at_seq = SEQ_NONE;
+		warn("Could not enter DLE mode. Try to hang up.");
+		channel = cs->curchannel;
+		cs->bcs[channel].at_state.pending_commands |= PC_HUP;
+		atomic_set(&cs->commands_pending, 1);
+		break;
+
+	case ACT_CID: /* got cid; start dialing */
+		cs->cur_at_seq = SEQ_NONE;
+		channel = cs->curchannel;
+		if (ev->parameter > 0 && ev->parameter <= 65535) {
+			cs->bcs[channel].at_state.cid = ev->parameter;
+			cs->bcs[channel].at_state.pending_commands |=
+				PC_DIAL;
+			atomic_set(&cs->commands_pending, 1);
+			break;
+		}
+		/* fall through */
+	case ACT_FAILCID:
+		cs->cur_at_seq = SEQ_NONE;
+		channel = cs->curchannel;
+		if (!reinit_and_retry(cs, channel)) {
+			warn("Could not get a call id. Dialing not possible");
+			at_state2 = &cs->bcs[channel].at_state;
+			disconnect(&at_state2);
+		}
+		break;
+	case ACT_ABORTCID:
+		cs->cur_at_seq = SEQ_NONE;
+		at_state2 = &cs->bcs[cs->curchannel].at_state;
+		disconnect(&at_state2);
+		break;
+
+	case ACT_DIALING:
+	case ACT_ACCEPTED:
+		cs->cur_at_seq = SEQ_NONE;
+		break;
+
+	case ACT_ABORTACCEPT:	/* hangup/error/timeout during ICALL processing */
+		disconnect(p_at_state);
+		at_state = *p_at_state;
+		break;
+
+	case ACT_ABORTDIAL:	/* error/timeout during dial preparation */
+		cs->cur_at_seq = SEQ_NONE;
+		at_state->pending_commands |= PC_HUP;
+		atomic_set(&cs->commands_pending, 1);
+		break;
+
+	case ACT_REMOTEREJECT:	/* DISCONNECT_IND after dialling */
+	case ACT_CONNTIMEOUT:	/* timeout waiting for ZSAU=ACTIVE */
+	case ACT_REMOTEHUP:	/* DISCONNECT_IND with established connection */
+		at_state->pending_commands |= PC_HUP;
+		atomic_set(&cs->commands_pending, 1);
+		break;
+	case ACT_GETSTRING: /* warning: RING, ZDLE, ... are not handled properly any more */
+		at_state->getstring = 1;
+		break;
+	case ACT_SETVER:
+		if (!ev->ptr) {
+			*p_genresp = 1;
+			*p_resp_code = RSP_ERROR;
+			break;
+		}
+		s = ev->ptr;
+
+		if (!strcmp(s, "OK")) {
+			*p_genresp = 1;
+			*p_resp_code = RSP_ERROR;
+			break;
+		}
+
+		for (i = 0; i < 4; ++i) {
+			val = simple_strtoul(s, (char **) &e, 10);
+			if (val > INT_MAX || e == s)
+				break;
+			if (i == 3) {
+				if (*e)
+					break;
+			} else if (*e != '.')
+				break;
+			else
+				s = e + 1;
+			cs->fwver[i] = val;
+		}
+		if (i != 4) {
+			*p_genresp = 1;
+			*p_resp_code = RSP_ERROR;
+			break;
+		}
+		/*at_state->getstring = 1;*/
+		cs->gotfwver = 0;
+		break;
+	case ACT_GOTVER:
+		if (cs->gotfwver == 0) {
+			cs->gotfwver = 1;
+			dbg(DEBUG_ANY,
+			    "firmware version %02d.%03d.%02d.%02d",
+			    cs->fwver[0], cs->fwver[1],
+			    cs->fwver[2], cs->fwver[3]);
+			break;
+		}
+		/* fall through */
+	case ACT_FAILVER:
+		cs->gotfwver = -1;
+		err("could not read firmware version.");
+		break;
+#ifdef CONFIG_GIGASET_DEBUG
+	case ACT_ERROR:
+		*p_genresp = 1;
+		*p_resp_code = RSP_ERROR;
+		break;
+	case ACT_TEST:
+		{
+			static int count = 3; //2; //1;
+			*p_genresp = 1;
+			*p_resp_code = count ? RSP_ERROR : RSP_OK;
+			if (count > 0)
+				--count;
+		}
+		break;
+#endif
+	case ACT_DEBUG:
+		dbg(DEBUG_ANY, "%s: resp_code %d in ConState %d",
+			__func__, ev->type, at_state->ConState);
+		break;
+	case ACT_WARN:
+		warn("%s: resp_code %d in ConState %d!",
+			__func__, ev->type, at_state->ConState);
+		break;
+	case ACT_ZCAU:
+		warn("cause code %04x in connection state %d.",
+		     ev->parameter, at_state->ConState);
+		break;
+
+	/* events from the LL */
+	case ACT_DIAL:
+		start_dial(at_state, ev->ptr, ev->parameter);
+		break;
+	case ACT_ACCEPT:
+		start_accept(at_state);
+		break;
+	case ACT_PROTO_L2:
+		dbg(DEBUG_CMD,
+		    "set protocol to %u", (unsigned) ev->parameter);
+		at_state->bcs->proto2 = ev->parameter;
+		break;
+	case ACT_HUP:
+		at_state->pending_commands |= PC_HUP;
+		atomic_set(&cs->commands_pending, 1); //FIXME
+		dbg(DEBUG_CMD, "Scheduling PC_HUP");
+		break;
+
+	/* hotplug events */
+	case ACT_STOP:
+		do_stop(cs);
+		break;
+	case ACT_START:
+		do_start(cs);
+		break;
+
+	/* events from the interface */ // FIXME without ACT_xxxx?
+	case ACT_IF_LOCK:
+		cs->cmd_result = ev->parameter ? do_lock(cs) : do_unlock(cs);
+		cs->waiting = 0;
+		wake_up(&cs->waitqueue);
+		break;
+	case ACT_IF_VER:
+		if (ev->parameter != 0)
+			cs->cmd_result = -EINVAL;
+		else if (cs->gotfwver != 1) {
+			cs->cmd_result = -ENOENT;
+		} else {
+			memcpy(ev->arg, cs->fwver, sizeof cs->fwver);
+			cs->cmd_result = 0;
+		}
+		cs->waiting = 0;
+		wake_up(&cs->waitqueue);
+		break;
+
+	/* events from the proc file system */ // FIXME without ACT_xxxx?
+	case ACT_PROC_CIDMODE:
+		if (ev->parameter != atomic_read(&cs->cidmode)) {
+			atomic_set(&cs->cidmode, ev->parameter);
+			if (ev->parameter) {
+				cs->at_state.pending_commands |= PC_CIDMODE;
+				dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
+			} else {
+				cs->at_state.pending_commands |= PC_UMMODE;
+				dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
+			}
+			atomic_set(&cs->commands_pending, 1);
+		}
+		cs->waiting = 0;
+		wake_up(&cs->waitqueue);
+		break;
+
+	/* events from the hardware drivers */
+	case ACT_NOTIFY_BC_DOWN:
+		bchannel_down(bcs);
+		break;
+	case ACT_NOTIFY_BC_UP:
+		bchannel_up(bcs);
+		break;
+	case ACT_SHUTDOWN:
+		do_shutdown(cs);
+		break;
+
+
+	default:
+		if (action >= ACT_CMD && action < ACT_CMD + AT_NUM) {
+			*pp_command = at_state->bcs->commands[action - ACT_CMD];
+			if (!*pp_command) {
+				*p_genresp = 1;
+				*p_resp_code = RSP_NULL;
+			}
+		} else
+			err("%s: action==%d!", __func__, action);
+	}
+}
+
+/* State machine to do the calling and hangup procedure */
+static void process_event(struct cardstate *cs, struct event_t *ev)
+{
+	struct bc_state *bcs;
+	char *p_command = NULL;
+	struct reply_t *rep;
+	int rcode;
+	int genresp = 0;
+	int resp_code = RSP_ERROR;
+	int sendcid;
+	struct at_state_t *at_state;
+	int index;
+	int curact;
+	unsigned long flags;
+
+	IFNULLRET(cs);
+	IFNULLRET(ev);
+
+	if (ev->cid >= 0) {
+		at_state = at_state_from_cid(cs, ev->cid);
+		if (!at_state) {
+			gigaset_add_event(cs, &cs->at_state, RSP_WRONG_CID,
+			                  NULL, 0, NULL);
+			return;
+		}
+	} else {
+		at_state = ev->at_state;
+		if (at_state_invalid(cs, at_state)) {
+			dbg(DEBUG_ANY,
+			    "event for invalid at_state %p", at_state);
+			return;
+		}
+	}
+
+	dbg(DEBUG_CMD,
+	    "connection state %d, event %d", at_state->ConState, ev->type);
+
+	bcs = at_state->bcs;
+	sendcid = at_state->cid;
+
+	/* Setting the pointer to the dial array */
+	rep = at_state->replystruct;
+	IFNULLRET(rep);
+
+	if (ev->type == EV_TIMEOUT) {
+		if (ev->parameter != atomic_read(&at_state->timer_index)
+		    || !at_state->timer_active) {
+			ev->type = RSP_NONE; /* old timeout */
+			dbg(DEBUG_ANY, "old timeout");
+		} else if (!at_state->waiting)
+			dbg(DEBUG_ANY, "timeout occured");
+		else
+			dbg(DEBUG_ANY, "stopped waiting");
+	}
+
+	/* if the response belongs to a variable in at_state->int_var[VAR_XXXX] or at_state->str_var[STR_XXXX], set it */
+	if (ev->type >= RSP_VAR && ev->type < RSP_VAR + VAR_NUM) {
+		index = ev->type - RSP_VAR;
+		at_state->int_var[index] = ev->parameter;
+	} else if (ev->type >= RSP_STR && ev->type < RSP_STR + STR_NUM) {
+		index = ev->type - RSP_STR;
+		kfree(at_state->str_var[index]);
+		at_state->str_var[index] = ev->ptr;
+		ev->ptr = NULL; /* prevent process_events() from deallocating ptr */
+	}
+
+	if (ev->type == EV_TIMEOUT || ev->type == RSP_STRING)
+		at_state->getstring = 0;
+
+	/* Search row in dial array which matches modem response and current constate */
+	for (;; rep++) {
+		rcode = rep->resp_code;
+		/* dbg (DEBUG_ANY, "rcode %d", rcode); */
+		if (rcode == RSP_LAST) {
+			/* found nothing...*/
+			warn("%s: rcode=RSP_LAST: resp_code %d in ConState %d!",
+				__func__, ev->type, at_state->ConState);
+			return;
+		}
+		if ((rcode == RSP_ANY || rcode == ev->type)
+		  && ((int) at_state->ConState >= rep->min_ConState)
+		  && (rep->max_ConState < 0
+		      || (int) at_state->ConState <= rep->max_ConState)
+		  && (rep->parameter < 0 || rep->parameter == ev->parameter))
+			break;
+	}
+
+	p_command = rep->command;
+
+	at_state->waiting = 0;
+	for (curact = 0; curact < MAXACT; ++curact) {
+		/* The row tells us what we should do  ..
+		 */
+		do_action(rep->action[curact], cs, bcs, &at_state, &p_command, &genresp, &resp_code, ev);
+		if (!at_state)
+			break; /* may be freed after disconnect */
+	}
+
+	if (at_state) {
+		/* Jump to the next con-state regarding the array */
+		if (rep->new_ConState >= 0)
+			at_state->ConState = rep->new_ConState;
+
+		if (genresp) {
+			spin_lock_irqsave(&cs->lock, flags);
+			at_state->timer_expires = 0; //FIXME
+			at_state->timer_active = 0; //FIXME
+			spin_unlock_irqrestore(&cs->lock, flags);
+			gigaset_add_event(cs, at_state, resp_code, NULL, 0, NULL);
+		} else {
+			/* Send command to modem if not NULL... */
+			if (p_command/*rep->command*/) {
+				if (atomic_read(&cs->connected))
+					send_command(cs, p_command,
+					             sendcid, cs->dle,
+					             GFP_ATOMIC);
+				else
+					gigaset_add_event(cs, at_state,
+					                  RSP_NODEV,
+					                  NULL, 0, NULL);
+			}
+
+			spin_lock_irqsave(&cs->lock, flags);
+			if (!rep->timeout) {
+				at_state->timer_expires = 0;
+				at_state->timer_active = 0;
+			} else if (rep->timeout > 0) { /* new timeout */
+				at_state->timer_expires = rep->timeout * 10;
+				at_state->timer_active = 1;
+				new_index(&at_state->timer_index,
+				          MAX_TIMER_INDEX);
+			}
+			spin_unlock_irqrestore(&cs->lock, flags);
+		}
+	}
+}
+
+static void schedule_sequence(struct cardstate *cs,
+			      struct at_state_t *at_state, int sequence)
+{
+	cs->cur_at_seq = sequence;
+	gigaset_add_event(cs, at_state, RSP_INIT, NULL, sequence, NULL);
+}
+
+static void process_command_flags(struct cardstate *cs)
+{
+	struct at_state_t *at_state = NULL;
+	struct bc_state *bcs;
+	int i;
+	int sequence;
+
+	IFNULLRET(cs);
+
+	atomic_set(&cs->commands_pending, 0);
+
+	if (cs->cur_at_seq) {
+		dbg(DEBUG_CMD, "not searching scheduled commands: busy");
+		return;
+	}
+
+	dbg(DEBUG_CMD, "searching scheduled commands");
+
+	sequence = SEQ_NONE;
+
+	/* clear pending_commands and hangup channels on shutdown */
+	if (cs->at_state.pending_commands & PC_SHUTDOWN) {
+		cs->at_state.pending_commands &= ~PC_CIDMODE;
+		for (i = 0; i < cs->channels; ++i) {
+			bcs = cs->bcs + i;
+			at_state = &bcs->at_state;
+			at_state->pending_commands &=
+				~(PC_DLE1 | PC_ACCEPT | PC_DIAL);
+			if (at_state->cid > 0)
+				at_state->pending_commands |= PC_HUP;
+			if (at_state->pending_commands & PC_CID) {
+				at_state->pending_commands |= PC_NOCID;
+				at_state->pending_commands &= ~PC_CID;
+			}
+		}
+	}
+
+	/* clear pending_commands and hangup channels on reset */
+	if (cs->at_state.pending_commands & PC_INIT) {
+		cs->at_state.pending_commands &= ~PC_CIDMODE;
+		for (i = 0; i < cs->channels; ++i) {
+			bcs = cs->bcs + i;
+			at_state = &bcs->at_state;
+			at_state->pending_commands &=
+				~(PC_DLE1 | PC_ACCEPT | PC_DIAL);
+			if (at_state->cid > 0)
+				at_state->pending_commands |= PC_HUP;
+			if (atomic_read(&cs->mstate) == MS_RECOVER) {
+				if (at_state->pending_commands & PC_CID) {
+					at_state->pending_commands |= PC_NOCID;
+					at_state->pending_commands &= ~PC_CID;
+				}
+			}
+		}
+	}
+
+	/* only switch back to unimodem mode, if no commands are pending and no channels are up */
+	if (cs->at_state.pending_commands == PC_UMMODE
+	    && !atomic_read(&cs->cidmode)
+	    && list_empty(&cs->temp_at_states)
+	    && atomic_read(&cs->mode) == M_CID) {
+		sequence = SEQ_UMMODE;
+		at_state = &cs->at_state;
+		for (i = 0; i < cs->channels; ++i) {
+			bcs = cs->bcs + i;
+			if (bcs->at_state.pending_commands ||
+			    bcs->at_state.cid > 0) {
+				sequence = SEQ_NONE;
+				break;
+			}
+		}
+	}
+	cs->at_state.pending_commands &= ~PC_UMMODE;
+	if (sequence != SEQ_NONE) {
+		schedule_sequence(cs, at_state, sequence);
+		return;
+	}
+
+	for (i = 0; i < cs->channels; ++i) {
+		bcs = cs->bcs + i;
+		if (bcs->at_state.pending_commands & PC_HUP) {
+			bcs->at_state.pending_commands &= ~PC_HUP;
+			if (bcs->at_state.pending_commands & PC_CID) {
+				/* not yet dialing: PC_NOCID is sufficient */
+				bcs->at_state.pending_commands |= PC_NOCID;
+				bcs->at_state.pending_commands &= ~PC_CID;
+			} else {
+				schedule_sequence(cs, &bcs->at_state, SEQ_HUP);
+				return;
+			}
+		}
+		if (bcs->at_state.pending_commands & PC_NOCID) {
+			bcs->at_state.pending_commands &= ~PC_NOCID;
+			cs->curchannel = bcs->channel;
+			schedule_sequence(cs, &cs->at_state, SEQ_NOCID);
+			return;
+		} else if (bcs->at_state.pending_commands & PC_DLE0) {
+			bcs->at_state.pending_commands &= ~PC_DLE0;
+			cs->curchannel = bcs->channel;
+			schedule_sequence(cs, &cs->at_state, SEQ_DLE0);
+			return;
+		}
+	}
+
+	list_for_each_entry(at_state, &cs->temp_at_states, list)
+		if (at_state->pending_commands & PC_HUP) {
+			at_state->pending_commands &= ~PC_HUP;
+			schedule_sequence(cs, at_state, SEQ_HUP);
+			return;
+		}
+
+	if (cs->at_state.pending_commands & PC_INIT) {
+		cs->at_state.pending_commands &= ~PC_INIT;
+		cs->dle = 0; //FIXME
+		cs->inbuf->inputstate = INS_command;
+		//FIXME reset card state (or -> LOCK0)?
+		schedule_sequence(cs, &cs->at_state, SEQ_INIT);
+		return;
+	}
+	if (cs->at_state.pending_commands & PC_SHUTDOWN) {
+		cs->at_state.pending_commands &= ~PC_SHUTDOWN;
+		schedule_sequence(cs, &cs->at_state, SEQ_SHUTDOWN);
+		return;
+	}
+	if (cs->at_state.pending_commands & PC_CIDMODE) {
+		cs->at_state.pending_commands &= ~PC_CIDMODE;
+		if (atomic_read(&cs->mode) == M_UNIMODEM) {
+#if 0
+			cs->retry_count = 2;
+#else
+			cs->retry_count = 1;
+#endif
+			schedule_sequence(cs, &cs->at_state, SEQ_CIDMODE);
+			return;
+		}
+	}
+
+	for (i = 0; i < cs->channels; ++i) {
+		bcs = cs->bcs + i;
+		if (bcs->at_state.pending_commands & PC_DLE1) {
+			bcs->at_state.pending_commands &= ~PC_DLE1;
+			cs->curchannel = bcs->channel;
+			schedule_sequence(cs, &cs->at_state, SEQ_DLE1);
+			return;
+		}
+		if (bcs->at_state.pending_commands & PC_ACCEPT) {
+			bcs->at_state.pending_commands &= ~PC_ACCEPT;
+			schedule_sequence(cs, &bcs->at_state, SEQ_ACCEPT);
+			return;
+		}
+		if (bcs->at_state.pending_commands & PC_DIAL) {
+			bcs->at_state.pending_commands &= ~PC_DIAL;
+			schedule_sequence(cs, &bcs->at_state, SEQ_DIAL);
+			return;
+		}
+		if (bcs->at_state.pending_commands & PC_CID) {
+			switch (atomic_read(&cs->mode)) {
+			case M_UNIMODEM:
+				cs->at_state.pending_commands |= PC_CIDMODE;
+				dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
+				atomic_set(&cs->commands_pending, 1);
+				return;
+#ifdef GIG_MAYINITONDIAL
+			case M_UNKNOWN:
+				schedule_init(cs, MS_INIT);
+				return;
+#endif
+			}
+			bcs->at_state.pending_commands &= ~PC_CID;
+			cs->curchannel = bcs->channel;
+#ifdef GIG_RETRYCID
+			cs->retry_count = 2;
+#else
+			cs->retry_count = 1;
+#endif
+			schedule_sequence(cs, &cs->at_state, SEQ_CID);
+			return;
+		}
+	}
+}
+
+static void process_events(struct cardstate *cs)
+{
+	struct event_t *ev;
+	unsigned head, tail;
+	int i;
+	int check_flags = 0;
+	int was_busy;
+
+	/* no locking needed (only one reader) */
+	head = atomic_read(&cs->ev_head);
+
+	for (i = 0; i < 2 * MAX_EVENTS; ++i) {
+		tail = atomic_read(&cs->ev_tail);
+		if (tail == head) {
+			if (!check_flags && !atomic_read(&cs->commands_pending))
+				break;
+			check_flags = 0;
+			process_command_flags(cs);
+			tail = atomic_read(&cs->ev_tail);
+			if (tail == head) {
+				if (!atomic_read(&cs->commands_pending))
+					break;
+				continue;
+			}
+		}
+
+		ev = cs->events + head;
+		was_busy = cs->cur_at_seq != SEQ_NONE;
+		process_event(cs, ev);
+		kfree(ev->ptr);
+		ev->ptr = NULL;
+		if (was_busy && cs->cur_at_seq == SEQ_NONE)
+			check_flags = 1;
+
+		head = (head + 1) % MAX_EVENTS;
+		atomic_set(&cs->ev_head, head);
+	}
+
+	if (i == 2 * MAX_EVENTS) {
+		err("infinite loop in process_events; aborting.");
+	}
+}
+
+/* tasklet scheduled on any event received from the Gigaset device
+ * parameter:
+ *	data	ISDN controller state structure
+ */
+void gigaset_handle_event(unsigned long data)
+{
+	struct cardstate *cs = (struct cardstate *) data;
+
+	IFNULLRET(cs);
+	IFNULLRET(cs->inbuf);
+
+	/* handle incoming data on control/common channel */
+	if (atomic_read(&cs->inbuf->head) != atomic_read(&cs->inbuf->tail)) {
+		dbg(DEBUG_INTR, "processing new data");
+		cs->ops->handle_input(cs->inbuf);
+	}
+
+	process_events(cs);
+}
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
new file mode 100644
index 0000000..729edcd
--- /dev/null
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -0,0 +1,938 @@
+/* Siemens Gigaset 307x driver
+ * Common header file for all connection variants
+ *
+ * Written by Stefan Eilers <Eilers.Stefan@epost.de>
+ *        and Hansjoerg Lipp <hjlipp@web.de>
+ *
+ * Version: $Id: gigaset.h,v 1.97.4.26 2006/02/04 18:28:16 hjlipp Exp $
+ * ===========================================================================
+ */
+
+#ifndef GIGASET_H
+#define GIGASET_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <asm/atomic.h>
+#include <linux/spinlock.h>
+#include <linux/isdnif.h>
+#include <linux/usb.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ppp_defs.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/list.h>
+
+#define GIG_VERSION {0,5,0,0}
+#define GIG_COMPAT  {0,4,0,0}
+
+#define MAX_REC_PARAMS 10                         /* Max. number of params in response string */
+#define MAX_RESP_SIZE 512                         /* Max. size of a response string */
+#define HW_HDR_LEN 2                              /* Header size used to store ack info */
+
+#define MAX_EVENTS 64                          /* size of event queue */
+
+#define RBUFSIZE 8192
+#define SBUFSIZE 4096				/* sk_buff payload size */
+
+#define MAX_BUF_SIZE (SBUFSIZE - 2)		/* Max. size of a data packet from LL */
+#define TRANSBUFSIZE 768			/* bytes per skb for transparent receive */
+
+/* compile time options */
+#define GIG_MAJOR 0
+
+#define GIG_MAYINITONDIAL
+#define GIG_RETRYCID
+#define GIG_X75
+
+#define MAX_TIMER_INDEX 1000
+#define MAX_SEQ_INDEX   1000
+
+#define GIG_TICK (HZ / 10)
+
+/* timeout values (unit: 1 sec) */
+#define INIT_TIMEOUT 1
+
+/* timeout values (unit: 0.1 sec) */
+#define RING_TIMEOUT 3		/* for additional parameters to RING */
+#define BAS_TIMEOUT 20		/* for response to Base USB ops */
+#define ATRDY_TIMEOUT 3		/* for HD_READY_SEND_ATDATA */
+
+#define BAS_RETRY 3		/* max. retries for base USB ops */
+
+#define MAXACT 3
+
+#define IFNULL(a)         if (unlikely(!(a)))
+#define IFNULLRET(a)      if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); return; }
+#define IFNULLRETVAL(a,b) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); return (b); }
+#define IFNULLCONT(a)     if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); continue; }
+#define IFNULLGOTO(a,b)   if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); goto b; }
+
+extern int gigaset_debuglevel;	/* "needs" cast to (enum debuglevel) */
+
+/* any combination of these can be given with the 'debug=' parameter to insmod, e.g.
+ * 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and DEBUG_INTR. */
+enum debuglevel { /* up to 24 bits (atomic_t) */
+	DEBUG_REG	  = 0x0002, /* serial port I/O register operations */
+	DEBUG_OPEN	  = 0x0004, /* open/close serial port */
+	DEBUG_INTR	  = 0x0008, /* interrupt processing */
+	DEBUG_INTR_DUMP   = 0x0010, /* Activating hexdump debug output on interrupt
+				      requests, not available as run-time option */
+	DEBUG_CMD	  = 0x00020, /* sent/received LL commands */
+	DEBUG_STREAM	  = 0x00040, /* application data stream I/O events */
+	DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */
+	DEBUG_LLDATA	  = 0x00100, /* sent/received LL data */
+	DEBUG_INTR_0	  = 0x00200, /* serial port output interrupt processing */
+	DEBUG_DRIVER	  = 0x00400, /* driver structure */
+	DEBUG_HDLC	  = 0x00800, /* M10x HDLC processing */
+	DEBUG_WRITE	  = 0x01000, /* M105 data write */
+	DEBUG_TRANSCMD    = 0x02000, /*AT-COMMANDS+RESPONSES*/
+	DEBUG_MCMD        = 0x04000, /*COMMANDS THAT ARE SENT VERY OFTEN*/
+	DEBUG_INIT	  = 0x08000, /* (de)allocation+initialization of data structures */
+	DEBUG_LOCK	  = 0x10000, /* semaphore operations */
+	DEBUG_OUTPUT	  = 0x20000, /* output to device */
+	DEBUG_ISO         = 0x40000, /* isochronous transfers */
+	DEBUG_IF	  = 0x80000, /* character device operations */
+	DEBUG_USBREQ	  = 0x100000, /* USB communication (except payload data) */
+	DEBUG_LOCKCMD     = 0x200000, /* AT commands and responses when MS_LOCKED */
+
+	DEBUG_ANY	  = 0x3fffff, /* print message if any of the others is activated */
+};
+
+#ifdef CONFIG_GIGASET_DEBUG
+#define DEBUG_DEFAULT (DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ)
+//#define DEBUG_DEFAULT (DEBUG_LOCK | DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUF_IF | DEBUG_DRIVER | DEBUG_OUTPUT | DEBUG_INTR)
+#else
+#define DEBUG_DEFAULT 0
+#endif
+
+/* redefine syslog macros to prepend module name instead of entire source path */
+/* The space before the comma in ", ##" is needed by gcc 2.95 */
+#undef info
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg)
+
+#undef notice
+#define notice(format, arg...) printk(KERN_NOTICE "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg)
+
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg)
+
+#undef err
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg)
+
+#undef dbg
+#ifdef CONFIG_GIGASET_DEBUG
+#define dbg(level, format, arg...) do { if (unlikely(((enum debuglevel)gigaset_debuglevel) & (level))) \
+	printk(KERN_DEBUG "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg); } while (0)
+#else
+#define dbg(level, format, arg...) do {} while (0)
+#endif
+
+void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
+                        size_t len, const unsigned char *buf, int from_user);
+
+/* connection state */
+#define ZSAU_NONE			0
+#define ZSAU_DISCONNECT_IND		4
+#define ZSAU_OUTGOING_CALL_PROCEEDING	1
+#define ZSAU_PROCEEDING			1
+#define ZSAU_CALL_DELIVERED		2
+#define ZSAU_ACTIVE			3
+#define ZSAU_NULL			5
+#define ZSAU_DISCONNECT_REQ		6
+#define ZSAU_UNKNOWN			-1
+
+/* USB control transfer requests */
+#define OUT_VENDOR_REQ			(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT)
+#define IN_VENDOR_REQ			(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT)
+
+/* int-in-events 3070 */
+#define HD_B1_FLOW_CONTROL		0x80
+#define HD_B2_FLOW_CONTROL		0x81
+#define HD_RECEIVEATDATA_ACK		(0x35)		// 3070		// att: HD_RECEIVE>>AT<<DATA_ACK
+#define HD_READY_SEND_ATDATA		(0x36)		// 3070
+#define HD_OPEN_ATCHANNEL_ACK		(0x37)		// 3070
+#define HD_CLOSE_ATCHANNEL_ACK		(0x38)		// 3070
+#define HD_DEVICE_INIT_OK		(0x11)		// ISurf USB + 3070
+#define HD_OPEN_B1CHANNEL_ACK		(0x51)		// ISurf USB + 3070
+#define HD_OPEN_B2CHANNEL_ACK		(0x52)		// ISurf USB + 3070
+#define HD_CLOSE_B1CHANNEL_ACK		(0x53)		// ISurf USB + 3070
+#define HD_CLOSE_B2CHANNEL_ACK		(0x54)		// ISurf USB + 3070
+// 	 Powermangment
+#define HD_SUSPEND_END			(0x61)		// ISurf USB
+//   Configuration
+#define HD_RESET_INTERRUPT_PIPE_ACK	(0xFF)		// ISurf USB + 3070
+
+/* control requests 3070 */
+#define	HD_OPEN_B1CHANNEL		(0x23)		// ISurf USB + 3070
+#define	HD_CLOSE_B1CHANNEL		(0x24)		// ISurf USB + 3070
+#define	HD_OPEN_B2CHANNEL		(0x25)		// ISurf USB + 3070
+#define	HD_CLOSE_B2CHANNEL		(0x26)		// ISurf USB + 3070
+#define HD_RESET_INTERRUPT_PIPE		(0x27)		// ISurf USB + 3070
+#define	HD_DEVICE_INIT_ACK		(0x34)		// ISurf USB + 3070
+#define	HD_WRITE_ATMESSAGE		(0x12)		// 3070
+#define	HD_READ_ATMESSAGE		(0x13)		// 3070
+#define	HD_OPEN_ATCHANNEL		(0x28)		// 3070
+#define	HD_CLOSE_ATCHANNEL		(0x29)		// 3070
+
+/* USB frames for isochronous transfer */
+#define BAS_FRAMETIME	1		/* number of milliseconds between frames */
+#define BAS_NUMFRAMES	8		/* number of frames per URB */
+#define BAS_MAXFRAME	16		/* allocated bytes per frame */
+#define BAS_NORMFRAME	8		/* send size without flow control */
+#define BAS_HIGHFRAME	10		/* "    "    with positive flow control */
+#define BAS_LOWFRAME	5		/* "    "    with negative flow control */
+#define BAS_CORRFRAMES	4		/* flow control multiplicator */
+
+#define BAS_INBUFSIZE	(BAS_MAXFRAME * BAS_NUMFRAMES) /* size of isochronous input buffer per URB */
+#define BAS_OUTBUFSIZE	4096		/* size of common isochronous output buffer */
+#define BAS_OUTBUFPAD	BAS_MAXFRAME	/* size of pad area for isochronous output buffer */
+
+#define BAS_INURBS	3
+#define BAS_OUTURBS	3
+
+/* variable commands in struct bc_state */
+#define AT_ISO		0
+#define AT_DIAL		1
+#define AT_MSN		2
+#define AT_BC		3
+#define AT_PROTO	4
+#define AT_TYPE		5
+#define AT_HLC		6
+#define AT_NUM		7
+
+/* variables in struct at_state_t */
+#define VAR_ZSAU   0
+#define VAR_ZDLE   1
+#define VAR_ZVLS   2
+#define VAR_ZCTP   3
+#define VAR_NUM    4
+
+#define STR_NMBR   0
+#define STR_ZCPN   1
+#define STR_ZCON   2
+#define STR_ZBC    3
+#define STR_ZHLC   4
+#define STR_NUM    5
+
+#define EV_TIMEOUT      -105
+#define EV_IF_VER       -106
+#define EV_PROC_CIDMODE -107
+#define EV_SHUTDOWN     -108
+#define EV_START        -110
+#define EV_STOP         -111
+#define EV_IF_LOCK      -112
+#define EV_PROTO_L2     -113
+#define EV_ACCEPT       -114
+#define EV_DIAL         -115
+#define EV_HUP          -116
+#define EV_BC_OPEN      -117
+#define EV_BC_CLOSED    -118
+
+/* input state */
+#define INS_command     0x0001
+#define INS_DLE_char    0x0002
+#define INS_byte_stuff  0x0004
+#define INS_have_data   0x0008
+#define INS_skip_frame  0x0010
+#define INS_DLE_command 0x0020
+#define INS_flag_hunt	0x0040
+
+/* channel state */
+#define CHS_D_UP	0x01
+#define CHS_B_UP	0x02
+#define CHS_NOTIFY_LL	0x04
+
+#define ICALL_REJECT  0
+#define ICALL_ACCEPT  1
+#define ICALL_IGNORE  2
+
+/* device state */
+#define MS_UNINITIALIZED        0
+#define MS_INIT                 1
+#define MS_LOCKED               2
+#define MS_SHUTDOWN             3
+#define MS_RECOVER              4
+#define MS_READY                5
+
+/* mode */
+#define M_UNKNOWN       0
+#define M_CONFIG        1
+#define M_UNIMODEM      2
+#define M_CID           3
+
+/* start mode */
+#define SM_LOCKED       0
+#define SM_ISDN         1 /* default */
+
+struct gigaset_ops;
+struct gigaset_driver;
+
+struct usb_cardstate;
+struct ser_cardstate;
+struct bas_cardstate;
+
+struct bc_state;
+struct usb_bc_state;
+struct ser_bc_state;
+struct bas_bc_state;
+
+struct reply_t {
+	int	resp_code;      /* RSP_XXXX */
+	int	min_ConState;   /* <0 => ignore */
+	int	max_ConState;   /* <0 => ignore */
+	int	parameter;      /* e.g. ZSAU_XXXX <0: ignore*/
+	int	new_ConState;   /* <0 => ignore */
+	int	timeout;        /* >0 => *HZ; <=0 => TOUT_XXXX*/
+	int	action[MAXACT]; /* ACT_XXXX */
+	char *command;        /* NULL==none */
+};
+
+extern struct reply_t gigaset_tab_cid_m10x[];
+extern struct reply_t gigaset_tab_nocid_m10x[];
+
+struct inbuf_t {
+	unsigned char           *rcvbuf;                /* usb-gigaset receive buffer */
+	struct bc_state		*bcs;
+	struct cardstate *cs;
+	int inputstate;
+
+	atomic_t head, tail;
+	unsigned char data[RBUFSIZE];
+};
+
+/* isochronous write buffer structure
+ * circular buffer with pad area for extraction of complete USB frames
+ * - data[read..nextread-1] is valid data already submitted to the USB subsystem
+ * - data[nextread..write-1] is valid data yet to be sent
+ * - data[write] is the next byte to write to
+ *   - in byte-oriented L2 procotols, it is completely free
+ *   - in bit-oriented L2 procotols, it may contain a partial byte of valid data
+ * - data[write+1..read-1] is free
+ * - wbits is the number of valid data bits in data[write], starting at the LSB
+ * - writesem is the semaphore for writing to the buffer:
+ *   if writesem <= 0, data[write..read-1] is currently being written to
+ * - idle contains the byte value to repeat when the end of valid data is
+ *   reached; if nextread==write (buffer contains no data to send), either the
+ *   BAS_OUTBUFPAD bytes immediately before data[write] (if write>=BAS_OUTBUFPAD)
+ *   or those of the pad area (if write<BAS_OUTBUFPAD) are also filled with that
+ *   value
+ * - optionally, the following statistics on the buffer's usage can be collected:
+ *   maxfill: maximum number of bytes occupied
+ *   idlefills: number of times a frame of idle bytes is prepared
+ *   emptygets: number of times the buffer was empty when a data frame was requested
+ *   backtoback: number of times two data packets were entered into the buffer
+ *    without intervening idle flags
+ *   nakedback: set if no idle flags have been inserted since the last data packet
+ */
+struct isowbuf_t {
+	atomic_t	read;
+	atomic_t	nextread;
+	atomic_t	write;
+	atomic_t	writesem;
+	int		wbits;
+	unsigned char	data[BAS_OUTBUFSIZE + BAS_OUTBUFPAD];
+	unsigned char	idle;
+};
+
+/* isochronous write URB context structure
+ * data to be stored along with the URB and retrieved when it is returned
+ * as completed by the USB subsystem
+ * - urb: pointer to the URB itself
+ * - bcs: pointer to the B Channel control structure
+ * - limit: end of write buffer area covered by this URB
+ */
+struct isow_urbctx_t {
+	struct urb *urb;
+	struct bc_state *bcs;
+	int limit;
+};
+
+/* AT state structure
+ * data associated with the state of an ISDN connection, whether or not
+ * it is currently assigned a B channel
+ */
+struct at_state_t {
+	struct list_head        list;
+	int                     waiting;
+	int                     getstring;
+	atomic_t		timer_index;
+	unsigned long		timer_expires;
+	int			timer_active;
+	unsigned int		ConState;                           /* State of connection */
+	struct reply_t          *replystruct;
+	int                     cid;
+	int                     int_var[VAR_NUM];   /* see VAR_XXXX */
+	char                    *str_var[STR_NUM];  /* see STR_XXXX */
+	unsigned                pending_commands;   /* see PC_XXXX */
+	atomic_t                seq_index;
+
+	struct cardstate    *cs;
+	struct bc_state         *bcs;
+};
+
+struct resp_type_t {
+	unsigned char	*response;
+	int		resp_code;           /* RSP_XXXX */
+	int		type;                /* RT_XXXX */
+};
+
+struct prot_skb {
+	atomic_t		empty;
+	struct semaphore	*sem;
+	struct sk_buff		*skb;
+};
+
+struct event_t {
+	int type;
+	void *ptr, *arg;
+	int parameter;
+	int cid;
+	struct at_state_t *at_state;
+};
+
+/* This buffer holds all information about the used B-Channel */
+struct bc_state {
+	struct sk_buff *tx_skb;                        /* Current transfer buffer to modem */
+	struct sk_buff_head squeue;	               /* B-Channel send Queue */
+
+	/* Variables for debugging .. */
+	int corrupted;                                   /* Counter for corrupted packages */
+	int trans_down;                                  /* Counter of packages (downstream) */
+	int trans_up;                                    /* Counter of packages (upstream) */
+
+	struct at_state_t at_state;
+	unsigned long rcvbytes;
+
+	__u16 fcs;
+	struct sk_buff *skb;
+	int inputstate; /* see INS_XXXX */
+
+	int channel;
+
+	struct cardstate *cs;
+
+	unsigned chstate;			/* bitmap (CHS_*) */
+	int ignore;
+	unsigned	proto2;			/* Layer 2 protocol (ISDN_PROTO_L2_*) */
+	char		*commands[AT_NUM]; /* see AT_XXXX */
+
+#ifdef CONFIG_GIGASET_DEBUG
+	int emptycount;
+#endif
+	int busy;
+	int use_count;
+
+	/* hardware drivers */
+	union {
+		struct ser_bc_state *ser;		 /* private data of serial hardware driver */
+		struct usb_bc_state *usb;		 /* private data of usb hardware driver */
+		struct bas_bc_state *bas;
+	} hw;
+};
+
+struct cardstate {
+	struct gigaset_driver *driver;
+	unsigned minor_index;
+
+	const struct gigaset_ops *ops;
+
+	/* Stuff to handle communication */
+	//wait_queue_head_t initwait;
+	wait_queue_head_t waitqueue;
+	int waiting;
+	atomic_t mode;                       /* see M_XXXX */
+	atomic_t mstate;                     /* Modem state: see MS_XXXX */
+	                                     /* only changed by the event layer */
+	int cmd_result;
+
+	int channels;
+	struct bc_state *bcs;                /* Array of struct bc_state */
+
+	int onechannel;                      /* data and commands transmitted in one stream (M10x) */
+
+	spinlock_t lock;
+	struct at_state_t at_state;          /* at_state_t for cid == 0 */
+	struct list_head temp_at_states;     /* list of temporary "struct at_state_t"s without B channel */
+
+	struct inbuf_t *inbuf;
+
+	struct cmdbuf_t *cmdbuf, *lastcmdbuf;
+	spinlock_t cmdlock;
+	unsigned curlen, cmdbytes;
+
+	unsigned open_count;
+	struct tty_struct *tty;
+	struct tasklet_struct if_wake_tasklet;
+	unsigned control_state;
+
+	unsigned fwver[4];
+	int gotfwver;
+
+	atomic_t running;                    /* !=0 if events are handled */
+	atomic_t connected;                  /* !=0 if hardware is connected */
+
+	atomic_t cidmode;
+
+	int myid;                            /* id for communication with LL */
+	isdn_if iif;
+
+	struct reply_t *tabnocid;
+	struct reply_t *tabcid;
+	int cs_init;
+	int ignoreframes;                    /* frames to ignore after setting up the B channel */
+	struct semaphore sem;                /* locks this structure: */
+	                                     /*   connected is not changed, */
+	                                     /*   hardware_up is not changed, */
+	                                     /*   MState is not changed to or from MS_LOCKED */
+
+	struct timer_list timer;
+	int retry_count;
+	int dle;                             /* !=0 if modem commands/responses are dle encoded */
+	int cur_at_seq;                      /* sequence of AT commands being processed */
+	int curchannel;                      /* channel, those commands are meant for */
+	atomic_t commands_pending;           /* flag(s) in xxx.commands_pending have been set */
+	struct tasklet_struct event_tasklet; /* tasklet for serializing AT commands. Scheduled
+	                                      *   -> for modem reponses (and incomming data for M10x)
+	                                      *   -> on timeout
+	                                      *   -> after setting bits in xxx.at_state.pending_command
+	                                      *      (e.g. command from LL) */
+	struct tasklet_struct write_tasklet; /* tasklet for serial output
+					      * (not used in base driver) */
+
+	/* event queue */
+	struct event_t events[MAX_EVENTS];
+	atomic_t ev_tail, ev_head;
+	spinlock_t ev_lock;
+
+	/* current modem response */
+	unsigned char respdata[MAX_RESP_SIZE];
+	unsigned cbytes;
+
+	/* hardware drivers */
+	union {
+		struct usb_cardstate *usb; /* private data of USB hardware driver */
+		struct ser_cardstate *ser; /* private data of serial hardware driver */
+		struct bas_cardstate *bas; /* private data of base hardware driver */
+	} hw;
+};
+
+struct gigaset_driver {
+	struct list_head list;
+	spinlock_t lock;                       /* locks minor tables and blocked */
+	//struct semaphore sem;                /* locks this structure */
+	struct tty_driver *tty;
+	unsigned have_tty;
+	unsigned minor;
+	unsigned minors;
+	struct cardstate *cs;
+	unsigned *flags;
+	int blocked;
+
+	const struct gigaset_ops *ops;
+	struct module *owner;
+};
+
+struct cmdbuf_t {
+	struct cmdbuf_t *next, *prev;
+	int len, offset;
+	struct tasklet_struct *wake_tasklet;
+	unsigned char buf[0];
+};
+
+struct bas_bc_state {
+	/* isochronous output state */
+	atomic_t	running;
+	atomic_t	corrbytes;
+	spinlock_t	isooutlock;
+	struct isow_urbctx_t	isoouturbs[BAS_OUTURBS];
+	struct isow_urbctx_t	*isooutdone, *isooutfree, *isooutovfl;
+	struct isowbuf_t	*isooutbuf;
+	unsigned numsub;			/* submitted URB counter (for diagnostic messages only) */
+	struct tasklet_struct	sent_tasklet;
+
+	/* isochronous input state */
+	spinlock_t isoinlock;
+	struct urb *isoinurbs[BAS_INURBS];
+	unsigned char isoinbuf[BAS_INBUFSIZE * BAS_INURBS];
+	struct urb *isoindone;	                /* completed isoc read URB */
+	int loststatus;				/* status of dropped URB */
+	unsigned isoinlost;			/* number of bytes lost */
+	/* state of bit unstuffing algorithm (in addition to BC_state.inputstate) */
+	unsigned seqlen;			/* number of '1' bits not yet unstuffed */
+	unsigned inbyte, inbits;		/* collected bits for next byte */
+	/* statistics */
+	unsigned goodbytes;			/* bytes correctly received */
+	unsigned alignerrs;			/* frames with incomplete byte at end */
+	unsigned fcserrs;			/* FCS errors */
+	unsigned frameerrs;			/* framing errors */
+	unsigned giants;			/* long frames */
+	unsigned runts;				/* short frames */
+	unsigned aborts;			/* HDLC aborts */
+	unsigned shared0s;			/* '0' bits shared between flags */
+	unsigned stolen0s;			/* '0' stuff bits also serving as leading flag bits */
+	struct tasklet_struct rcvd_tasklet;
+};
+
+struct gigaset_ops {
+	/* Called from ev-layer.c/interface.c for sending AT commands to the device */
+	int (*write_cmd)(struct cardstate *cs,
+	                 const unsigned char *buf, int len,
+	                 struct tasklet_struct *wake_tasklet);
+
+	/* Called from interface.c for additional device control */
+	int (*write_room)(struct cardstate *cs);
+	int (*chars_in_buffer)(struct cardstate *cs);
+	int (*brkchars)(struct cardstate *cs, const unsigned char buf[6]);
+
+	/* Called from ev-layer.c after setting up connection
+	 * Should call gigaset_bchannel_up(), when finished. */
+	int (*init_bchannel)(struct bc_state *bcs);
+
+	/* Called from ev-layer.c after hanging up
+	 * Should call gigaset_bchannel_down(), when finished. */
+	int (*close_bchannel)(struct bc_state *bcs);
+
+	/* Called by gigaset_initcs() for setting up bcs->hw.xxx */
+	int (*initbcshw)(struct bc_state *bcs);
+
+	/* Called by gigaset_freecs() for freeing bcs->hw.xxx */
+	int (*freebcshw)(struct bc_state *bcs);
+
+	/* Called by gigaset_stop() or gigaset_bchannel_down() for resetting bcs->hw.xxx */
+	void (*reinitbcshw)(struct bc_state *bcs);
+
+	/* Called by gigaset_initcs() for setting up cs->hw.xxx */
+	int (*initcshw)(struct cardstate *cs);
+
+	/* Called by gigaset_freecs() for freeing cs->hw.xxx */
+	void (*freecshw)(struct cardstate *cs);
+
+	///* Called by gigaset_stop() for killing URBs, shutting down the device, ...
+	//   hardwareup: ==0: don't try to shut down the device, hardware is really not accessible
+	//	       !=0: hardware still up */
+	//void (*stophw)(struct cardstate *cs, int hardwareup);
+
+	/* Called from common.c/interface.c for additional serial port control */
+	int (*set_modem_ctrl)(struct cardstate *cs, unsigned old_state, unsigned new_state);
+	int (*baud_rate)(struct cardstate *cs, unsigned cflag);
+	int (*set_line_ctrl)(struct cardstate *cs, unsigned cflag);
+
+	/* Called from i4l.c to put an skb into the send-queue. */
+	int (*send_skb)(struct bc_state *bcs, struct sk_buff *skb);
+
+	/* Called from ev-layer.c to process a block of data
+	 * received through the common/control channel. */
+	void (*handle_input)(struct inbuf_t *inbuf);
+
+};
+
+/* = Common structures and definitions ======================================= */
+
+/* Parser states for DLE-Event:
+ * <DLE-EVENT>: <DLE_FLAG> "X" <EVENT> <DLE_FLAG> "."
+ * <DLE_FLAG>:  0x10
+ * <EVENT>:     ((a-z)* | (A-Z)* | (0-10)*)+
+ */
+#define DLE_FLAG       0x10
+
+/* ===========================================================================
+ *  Functions implemented in asyncdata.c
+ */
+
+/* Called from i4l.c to put an skb into the send-queue.
+ * After sending gigaset_skb_sent() should be called. */
+int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb);
+
+/* Called from ev-layer.c to process a block of data
+ * received through the common/control channel. */
+void gigaset_m10x_input(struct inbuf_t *inbuf);
+
+/* ===========================================================================
+ *  Functions implemented in isocdata.c
+ */
+
+/* Called from i4l.c to put an skb into the send-queue.
+ * After sending gigaset_skb_sent() should be called. */
+int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb);
+
+/* Called from ev-layer.c to process a block of data
+ * received through the common/control channel. */
+void gigaset_isoc_input(struct inbuf_t *inbuf);
+
+/* Called from bas-gigaset.c to process a block of data
+ * received through the isochronous channel */
+void gigaset_isoc_receive(unsigned char *src, unsigned count, struct bc_state *bcs);
+
+/* Called from bas-gigaset.c to put a block of data
+ * into the isochronous output buffer */
+int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len);
+
+/* Called from bas-gigaset.c to initialize the isochronous output buffer */
+void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle);
+
+/* Called from bas-gigaset.c to retrieve a block of bytes for sending */
+int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size);
+
+/* ===========================================================================
+ *  Functions implemented in i4l.c/gigaset.h
+ */
+
+/* Called by gigaset_initcs() for setting up with the isdn4linux subsystem */
+int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid);
+
+/* Called from xxx-gigaset.c to indicate completion of sending an skb */
+void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
+
+/* Called from common.c/ev-layer.c to indicate events relevant to the LL */
+int gigaset_isdn_icall(struct at_state_t *at_state);
+int gigaset_isdn_setup_accept(struct at_state_t *at_state);
+int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data);
+
+void gigaset_i4l_cmd(struct cardstate *cs, int cmd);
+void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd);
+
+
+static inline void gigaset_isdn_rcv_err(struct bc_state *bcs)
+{
+	isdn_ctrl response;
+
+	/* error -> LL */
+	dbg(DEBUG_CMD, "sending L1ERR");
+	response.driver = bcs->cs->myid;
+	response.command = ISDN_STAT_L1ERR;
+	response.arg = bcs->channel;
+	response.parm.errcode = ISDN_STAT_L1ERR_RECV;
+	bcs->cs->iif.statcallb(&response);
+}
+
+/* ===========================================================================
+ *  Functions implemented in ev-layer.c
+ */
+
+/* tasklet called from common.c to process queued events */
+void gigaset_handle_event(unsigned long data);
+
+/* called from isocdata.c / asyncdata.c
+ * when a complete modem response line has been received */
+void gigaset_handle_modem_response(struct cardstate *cs);
+
+/* ===========================================================================
+ *  Functions implemented in proc.c
+ */
+
+/* initialize sysfs for device */
+void gigaset_init_dev_sysfs(struct usb_interface *interface);
+void gigaset_free_dev_sysfs(struct usb_interface *interface);
+
+/* ===========================================================================
+ *  Functions implemented in common.c/gigaset.h
+ */
+
+void gigaset_bcs_reinit(struct bc_state *bcs);
+void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
+                     struct cardstate *cs, int cid);
+int gigaset_get_channel(struct bc_state *bcs);
+void gigaset_free_channel(struct bc_state *bcs);
+int gigaset_get_channels(struct cardstate *cs);
+void gigaset_free_channels(struct cardstate *cs);
+void gigaset_block_channels(struct cardstate *cs);
+
+/* Allocate and initialize driver structure. */
+struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
+                                          const char *procname,
+                                          const char *devname,
+                                          const char *devfsname,
+                                          const struct gigaset_ops *ops,
+                                          struct module *owner);
+
+/* Deallocate driver structure. */
+void gigaset_freedriver(struct gigaset_driver *drv);
+void gigaset_debugdrivers(void);
+struct cardstate *gigaset_get_cs_by_minor(unsigned minor);
+struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty);
+struct cardstate *gigaset_get_cs_by_id(int id);
+
+/* For drivers without fixed assignment device<->cardstate (usb) */
+struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv);
+void gigaset_unassign(struct cardstate *cs);
+void gigaset_blockdriver(struct gigaset_driver *drv);
+
+/* Allocate and initialize card state. Calls hardware dependent gigaset_init[b]cs(). */
+struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
+				 int onechannel, int ignoreframes,
+				 int cidmode, const char *modulename);
+
+/* Free card state. Calls hardware dependent gigaset_free[b]cs(). */
+void gigaset_freecs(struct cardstate *cs);
+
+/* Tell common.c that hardware and driver are ready. */
+int gigaset_start(struct cardstate *cs);
+
+/* Tell common.c that the device is not present any more. */
+void gigaset_stop(struct cardstate *cs);
+
+/* Tell common.c that the driver is being unloaded. */
+void gigaset_shutdown(struct cardstate *cs);
+
+/* Tell common.c that an skb has been sent. */
+void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
+
+/* Append event to the queue.
+ * Returns NULL on failure or a pointer to the event on success.
+ * ptr must be kmalloc()ed (and not be freed by the caller).
+ */
+struct event_t *gigaset_add_event(struct cardstate *cs,
+                                  struct at_state_t *at_state, int type,
+                                  void *ptr, int parameter, void *arg);
+
+/* Called on CONFIG1 command from frontend. */
+int gigaset_enterconfigmode(struct cardstate *cs); //0: success <0: errorcode
+
+/* cs->lock must not be locked */
+static inline void gigaset_schedule_event(struct cardstate *cs)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&cs->lock, flags);
+	if (atomic_read(&cs->running))
+		tasklet_schedule(&cs->event_tasklet);
+	spin_unlock_irqrestore(&cs->lock, flags);
+}
+
+/* Tell common.c that B channel has been closed. */
+/* cs->lock must not be locked */
+static inline void gigaset_bchannel_down(struct bc_state *bcs)
+{
+	gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_CLOSED, NULL, 0, NULL);
+
+	dbg(DEBUG_CMD, "scheduling BC_CLOSED");
+	gigaset_schedule_event(bcs->cs);
+}
+
+/* Tell common.c that B channel has been opened. */
+/* cs->lock must not be locked */
+static inline void gigaset_bchannel_up(struct bc_state *bcs)
+{
+	gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_OPEN, NULL, 0, NULL);
+
+	dbg(DEBUG_CMD, "scheduling BC_OPEN");
+	gigaset_schedule_event(bcs->cs);
+}
+
+/* handling routines for sk_buff */
+/* ============================= */
+
+/* private version of __skb_put()
+ * append 'len' bytes to the content of 'skb', already knowing that the
+ * existing buffer can accomodate them
+ * returns a pointer to the location where the new bytes should be copied to
+ * This function does not take any locks so it must be called with the
+ * appropriate locks held only.
+ */
+static inline unsigned char *gigaset_skb_put_quick(struct sk_buff *skb,
+                                                   unsigned int len)
+{
+	unsigned char *tmp = skb->tail;
+	/*SKB_LINEAR_ASSERT(skb);*/		/* not needed here */
+	skb->tail += len;
+	skb->len += len;
+	return tmp;
+}
+
+/* pass received skb to LL
+ * Warning: skb must not be accessed anymore!
+ */
+static inline void gigaset_rcv_skb(struct sk_buff *skb,
+                                   struct cardstate *cs,
+                                   struct bc_state *bcs)
+{
+	cs->iif.rcvcallb_skb(cs->myid, bcs->channel, skb);
+	bcs->trans_down++;
+}
+
+/* handle reception of corrupted skb
+ * Warning: skb must not be accessed anymore!
+ */
+static inline void gigaset_rcv_error(struct sk_buff *procskb,
+                                     struct cardstate *cs,
+                                     struct bc_state *bcs)
+{
+	if (procskb)
+		dev_kfree_skb(procskb);
+
+	if (bcs->ignore)
+		--bcs->ignore;
+	else {
+		++bcs->corrupted;
+		gigaset_isdn_rcv_err(bcs);
+	}
+}
+
+
+/* bitwise byte inversion table */
+extern __u8 gigaset_invtab[];	/* in common.c */
+
+
+/* append received bytes to inbuf */
+static inline int gigaset_fill_inbuf(struct inbuf_t *inbuf,
+                                     const unsigned char *src,
+                                     unsigned numbytes)
+{
+	unsigned n, head, tail, bytesleft;
+
+	dbg(DEBUG_INTR, "received %u bytes", numbytes);
+
+	if (!numbytes)
+		return 0;
+
+	bytesleft = numbytes;
+	tail = atomic_read(&inbuf->tail);
+	head = atomic_read(&inbuf->head);
+	dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
+
+	while (bytesleft) {
+		if (head > tail)
+			n = head - 1 - tail;
+		else if (head == 0)
+			n = (RBUFSIZE-1) - tail;
+		else
+			n = RBUFSIZE - tail;
+		if (!n) {
+			err("buffer overflow (%u bytes lost)", bytesleft);
+			break;
+		}
+		if (n > bytesleft)
+			n = bytesleft;
+		memcpy(inbuf->data + tail, src, n);
+		bytesleft -= n;
+		tail = (tail + n) % RBUFSIZE;
+		src += n;
+	}
+	dbg(DEBUG_INTR, "setting tail to %u", tail);
+	atomic_set(&inbuf->tail, tail);
+	return numbytes != bytesleft;
+}
+
+/* ===========================================================================
+ *  Functions implemented in interface.c
+ */
+
+/* initialize interface */
+void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
+                           const char *devname, const char *devfsname);
+/* release interface */
+void gigaset_if_freedriver(struct gigaset_driver *drv);
+/* add minor */
+void gigaset_if_init(struct cardstate *cs);
+/* remove minor */
+void gigaset_if_free(struct cardstate *cs);
+/* device received data */
+void gigaset_if_receive(struct cardstate *cs,
+                        unsigned char *buffer, size_t len);
+
+#endif
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
new file mode 100644
index 0000000..731a675
--- /dev/null
+++ b/drivers/isdn/gigaset/i4l.c
@@ -0,0 +1,567 @@
+/*
+ * Stuff used by all variants of the driver
+ *
+ * Copyright (c) 2001 by Stefan Eilers (Eilers.Stefan@epost.de),
+ *                       Hansjoerg Lipp (hjlipp@web.de),
+ *                       Tilman Schmidt (tilman@imap.cc).
+ *
+ * =====================================================================
+ *	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.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: i4l.c,v 1.3.2.9 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+
+/* == Handling of I4L IO ============================================================================*/
+
+/* writebuf_from_LL
+ * called by LL to transmit data on an open channel
+ * inserts the buffer data into the send queue and starts the transmission
+ * Note that this operation must not sleep!
+ * When the buffer is processed completely, gigaset_skb_sent() should be called.
+ * parameters:
+ *	driverID	driver ID as assigned by LL
+ *	channel		channel number
+ *	ack		if != 0 LL wants to be notified on completion via statcallb(ISDN_STAT_BSENT)
+ *	skb		skb containing data to send
+ * return value:
+ *	number of accepted bytes
+ *	0 if temporarily unable to accept data (out of buffer space)
+ *	<0 on error (eg. -EINVAL)
+ */
+static int writebuf_from_LL(int driverID, int channel, int ack, struct sk_buff *skb)
+{
+	struct cardstate *cs;
+	struct bc_state *bcs;
+	unsigned len;
+	unsigned skblen;
+
+	if (!(cs = gigaset_get_cs_by_id(driverID))) {
+		err("%s: invalid driver ID (%d)", __func__, driverID);
+		return -ENODEV;
+	}
+	if (channel < 0 || channel >= cs->channels) {
+		err("%s: invalid channel ID (%d)", __func__, channel);
+		return -ENODEV;
+	}
+	bcs = &cs->bcs[channel];
+	len = skb->len;
+
+	dbg(DEBUG_LLDATA,
+	    "Receiving data from LL (id: %d, channel: %d, ack: %d, size: %d)",
+	    driverID, channel, ack, len);
+
+	if (!len) {
+		if (ack)
+			warn("not ACKing empty packet from LL");
+		return 0;
+	}
+	if (len > MAX_BUF_SIZE) {
+		err("%s: packet too large (%d bytes)", __func__, channel);
+		return -EINVAL;
+	}
+
+	if (!atomic_read(&cs->connected))
+		return -ENODEV;
+
+	skblen = ack ? len : 0;
+	skb->head[0] = skblen & 0xff;
+	skb->head[1] = skblen >> 8;
+	dbg(DEBUG_MCMD, "skb: len=%u, skblen=%u: %02x %02x", len, skblen,
+	     (unsigned) skb->head[0], (unsigned) skb->head[1]);
+
+	/* pass to device-specific module */
+	return cs->ops->send_skb(bcs, skb);
+}
+
+void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
+{
+	unsigned len;
+	isdn_ctrl response;
+
+	++bcs->trans_up;
+
+	if (skb->len)
+		warn("%s: skb->len==%d", __func__, skb->len);
+
+	len = (unsigned char) skb->head[0] |
+	      (unsigned) (unsigned char) skb->head[1] << 8;
+	if (len) {
+		dbg(DEBUG_MCMD,
+		    "Acknowledge sending to LL (id: %d, channel: %d size: %u)",
+		    bcs->cs->myid, bcs->channel, len);
+
+		response.driver = bcs->cs->myid;
+		response.command = ISDN_STAT_BSENT;
+		response.arg = bcs->channel;
+		response.parm.length = len;
+		bcs->cs->iif.statcallb(&response);
+	}
+}
+EXPORT_SYMBOL_GPL(gigaset_skb_sent);
+
+/* This function will be called by LL to send commands
+ * NOTE: LL ignores the returned value, for commands other than ISDN_CMD_IOCTL,
+ * so don't put too much effort into it.
+ */
+static int command_from_LL(isdn_ctrl *cntrl)
+{
+	struct cardstate *cs = gigaset_get_cs_by_id(cntrl->driver);
+	//isdn_ctrl response;
+	//unsigned long flags;
+	struct bc_state *bcs;
+	int retval = 0;
+	struct setup_parm *sp;
+
+	//dbg(DEBUG_ANY, "Gigaset_HW: Receiving command");
+	gigaset_debugdrivers();
+
+	/* Terminate this call if no device is present. Bt if the command is "ISDN_CMD_LOCK" or
+	 * "ISDN_CMD_UNLOCK" then execute it due to the fact that they are device independent !
+	 */
+	//FIXME "remove test for &connected"
+	if ((!cs || !atomic_read(&cs->connected))) {
+		warn("LL tried to access unknown device with nr. %d",
+		     cntrl->driver);
+		return -ENODEV;
+	}
+
+	switch (cntrl->command) {
+	case ISDN_CMD_IOCTL:
+
+		dbg(DEBUG_ANY, "ISDN_CMD_IOCTL (driver:%d,arg: %ld)",
+		    cntrl->driver, cntrl->arg);
+
+		warn("ISDN_CMD_IOCTL is not supported.");
+		return -EINVAL;
+
+	case ISDN_CMD_DIAL:
+		dbg(DEBUG_ANY, "ISDN_CMD_DIAL (driver: %d, channel: %ld, "
+		    "phone: %s,ownmsn: %s, si1: %d, si2: %d)",
+		    cntrl->driver, cntrl->arg,
+		    cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn,
+		    cntrl->parm.setup.si1, cntrl->parm.setup.si2);
+
+		if (cntrl->arg >= cs->channels) {
+			err("invalid channel (%d)", (int) cntrl->arg);
+			return -EINVAL;
+		}
+
+		bcs = cs->bcs + cntrl->arg;
+
+		if (!gigaset_get_channel(bcs)) {
+			err("channel not free");
+			return -EBUSY;
+		}
+
+		sp = kmalloc(sizeof *sp, GFP_ATOMIC);
+		if (!sp) {
+			gigaset_free_channel(bcs);
+			err("ISDN_CMD_DIAL: out of memory");
+			return -ENOMEM;
+		}
+		*sp = cntrl->parm.setup;
+
+		if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp,
+			               atomic_read(&bcs->at_state.seq_index),
+			               NULL)) {
+			//FIXME what should we do?
+			kfree(sp);
+			gigaset_free_channel(bcs);
+			return -ENOMEM;
+		}
+
+		dbg(DEBUG_CMD, "scheduling DIAL");
+		gigaset_schedule_event(cs);
+		break;
+	case ISDN_CMD_ACCEPTD: //FIXME
+		dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTD");
+
+		if (cntrl->arg >= cs->channels) {
+			err("invalid channel (%d)", (int) cntrl->arg);
+			return -EINVAL;
+		}
+
+		if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state,
+			               EV_ACCEPT, NULL, 0, NULL)) {
+			//FIXME what should we do?
+			return -ENOMEM;
+		}
+
+		dbg(DEBUG_CMD, "scheduling ACCEPT");
+		gigaset_schedule_event(cs);
+
+		break;
+	case ISDN_CMD_ACCEPTB:
+		dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTB");
+		break;
+	case ISDN_CMD_HANGUP:
+		dbg(DEBUG_ANY,
+		    "ISDN_CMD_HANGUP (channel: %d)", (int) cntrl->arg);
+
+		if (cntrl->arg >= cs->channels) {
+			err("ISDN_CMD_HANGUP: invalid channel (%u)",
+			    (unsigned) cntrl->arg);
+			return -EINVAL;
+		}
+
+		if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state,
+			               EV_HUP, NULL, 0, NULL)) {
+			//FIXME what should we do?
+			return -ENOMEM;
+		}
+
+		dbg(DEBUG_CMD, "scheduling HUP");
+		gigaset_schedule_event(cs);
+
+		break;
+	case ISDN_CMD_CLREAZ:               /* Do not signal incoming signals */ //FIXME
+		dbg(DEBUG_ANY, "ISDN_CMD_CLREAZ");
+		break;
+	case ISDN_CMD_SETEAZ:               /* Signal incoming calls for given MSN */ //FIXME
+		dbg(DEBUG_ANY,
+		    "ISDN_CMD_SETEAZ (id:%d, channel: %ld, number: %s)",
+		    cntrl->driver, cntrl->arg, cntrl->parm.num);
+		break;
+	case ISDN_CMD_SETL2:                /* Set L2 to given protocol */
+		dbg(DEBUG_ANY, "ISDN_CMD_SETL2 (Channel: %ld, Proto: %lx)",
+		     cntrl->arg & 0xff, (cntrl->arg >> 8));
+
+		if ((cntrl->arg & 0xff) >= cs->channels) {
+			err("invalid channel (%u)",
+			    (unsigned) cntrl->arg & 0xff);
+			return -EINVAL;
+		}
+
+		if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg & 0xff].at_state,
+		                       EV_PROTO_L2, NULL, cntrl->arg >> 8,
+		                       NULL)) {
+			//FIXME what should we do?
+			return -ENOMEM;
+		}
+
+		dbg(DEBUG_CMD, "scheduling PROTO_L2");
+		gigaset_schedule_event(cs);
+		break;
+	case ISDN_CMD_SETL3:              /* Set L3 to given protocol */
+		dbg(DEBUG_ANY, "ISDN_CMD_SETL3 (Channel: %ld, Proto: %lx)",
+		     cntrl->arg & 0xff, (cntrl->arg >> 8));
+
+		if ((cntrl->arg & 0xff) >= cs->channels) {
+			err("invalid channel (%u)",
+			    (unsigned) cntrl->arg & 0xff);
+			return -EINVAL;
+		}
+
+		if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) {
+			err("invalid protocol %lu", cntrl->arg >> 8);
+			return -EINVAL;
+		}
+
+		break;
+	case ISDN_CMD_PROCEED:
+		dbg(DEBUG_ANY, "ISDN_CMD_PROCEED"); //FIXME
+		break;
+	case ISDN_CMD_ALERT:
+		dbg(DEBUG_ANY, "ISDN_CMD_ALERT"); //FIXME
+		if (cntrl->arg >= cs->channels) {
+			err("invalid channel (%d)", (int) cntrl->arg);
+			return -EINVAL;
+		}
+		//bcs = cs->bcs + cntrl->arg;
+		//bcs->proto2 = -1;
+		// FIXME
+		break;
+	case ISDN_CMD_REDIR:
+		dbg(DEBUG_ANY, "ISDN_CMD_REDIR"); //FIXME
+		break;
+	case ISDN_CMD_PROT_IO:
+		dbg(DEBUG_ANY, "ISDN_CMD_PROT_IO");
+		break;
+	case ISDN_CMD_FAXCMD:
+		dbg(DEBUG_ANY, "ISDN_CMD_FAXCMD");
+		break;
+	case ISDN_CMD_GETL2:
+		dbg(DEBUG_ANY, "ISDN_CMD_GETL2");
+		break;
+	case ISDN_CMD_GETL3:
+		dbg(DEBUG_ANY, "ISDN_CMD_GETL3");
+		break;
+	case ISDN_CMD_GETEAZ:
+		dbg(DEBUG_ANY, "ISDN_CMD_GETEAZ");
+		break;
+	case ISDN_CMD_SETSIL:
+		dbg(DEBUG_ANY, "ISDN_CMD_SETSIL");
+		break;
+	case ISDN_CMD_GETSIL:
+		dbg(DEBUG_ANY, "ISDN_CMD_GETSIL");
+		break;
+	default:
+		err("unknown command %d from LL",
+		     cntrl->command);
+		return -EINVAL;
+	}
+
+	return retval;
+}
+
+void gigaset_i4l_cmd(struct cardstate *cs, int cmd)
+{
+	isdn_ctrl command;
+
+	command.driver = cs->myid;
+	command.command = cmd;
+	command.arg = 0;
+	cs->iif.statcallb(&command);
+}
+
+void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd)
+{
+	isdn_ctrl command;
+
+	command.driver = bcs->cs->myid;
+	command.command = cmd;
+	command.arg = bcs->channel;
+	bcs->cs->iif.statcallb(&command);
+}
+
+int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data)
+{
+	struct bc_state *bcs = at_state->bcs;
+	unsigned proto;
+	const char *bc;
+	size_t length[AT_NUM];
+	size_t l;
+	int i;
+	struct setup_parm *sp = data;
+
+	switch (bcs->proto2) {
+	case ISDN_PROTO_L2_HDLC:
+		proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */
+		break;
+	case ISDN_PROTO_L2_TRANS:
+		proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
+		break;
+	default:
+		err("invalid protocol: %u", bcs->proto2);
+		return -EINVAL;
+	}
+
+	switch (sp->si1) {
+	case 1:		/* audio */
+		bc = "9090A3";	/* 3.1 kHz audio, A-law */
+		break;
+	case 7:		/* data */
+	default:	/* hope the app knows what it is doing */
+		bc = "8890";	/* unrestricted digital information */
+	}
+	//FIXME add missing si1 values from 1TR6, inspect si2, set HLC/LLC
+
+	length[AT_DIAL ] = 1 + strlen(sp->phone) + 1 + 1;
+	l = strlen(sp->eazmsn);
+	length[AT_MSN  ] = l ? 6 + l + 1 + 1 : 0;
+	length[AT_BC   ] = 5 + strlen(bc) + 1 + 1;
+	length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */
+	length[AT_ISO  ] = 6 + 1 + 1 + 1; /* channel: 1 character */
+	length[AT_TYPE ] = 6 + 1 + 1 + 1; /* call type: 1 character */
+	length[AT_HLC  ] = 0;
+
+	for (i = 0; i < AT_NUM; ++i) {
+		kfree(bcs->commands[i]);
+		bcs->commands[i] = NULL;
+		if (length[i] &&
+		    !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
+			err("out of memory");
+			return -ENOMEM;
+		}
+	}
+
+	/* type = 1: extern, 0: intern, 2: recall, 3: door, 4: centrex */
+	if (sp->phone[0] == '*' && sp->phone[1] == '*') {
+		/* internal call: translate ** prefix to CTP value */
+		snprintf(bcs->commands[AT_DIAL], length[AT_DIAL],
+			 "D%s\r", sp->phone+2);
+		strncpy(bcs->commands[AT_TYPE], "^SCTP=0\r", length[AT_TYPE]);
+	} else {
+		snprintf(bcs->commands[AT_DIAL], length[AT_DIAL],
+			 "D%s\r", sp->phone);
+		strncpy(bcs->commands[AT_TYPE], "^SCTP=1\r", length[AT_TYPE]);
+	}
+
+	if (bcs->commands[AT_MSN])
+		snprintf(bcs->commands[AT_MSN], length[AT_MSN], "^SMSN=%s\r", sp->eazmsn);
+	snprintf(bcs->commands[AT_BC   ], length[AT_BC   ], "^SBC=%s\r", bc);
+	snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], "^SBPR=%u\r", proto);
+	snprintf(bcs->commands[AT_ISO  ], length[AT_ISO  ], "^SISO=%u\r", (unsigned)bcs->channel + 1);
+
+	return 0;
+}
+
+int gigaset_isdn_setup_accept(struct at_state_t *at_state)
+{
+	unsigned proto;
+	size_t length[AT_NUM];
+	int i;
+	struct bc_state *bcs = at_state->bcs;
+
+	switch (bcs->proto2) {
+	case ISDN_PROTO_L2_HDLC:
+		proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */
+		break;
+	case ISDN_PROTO_L2_TRANS:
+		proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
+		break;
+	default:
+		err("invalid protocol: %u", bcs->proto2);
+		return -EINVAL;
+	}
+
+	length[AT_DIAL ] = 0;
+	length[AT_MSN  ] = 0;
+	length[AT_BC   ] = 0;
+	length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */
+	length[AT_ISO  ] = 6 + 1 + 1 + 1; /* channel: 1 character */
+	length[AT_TYPE ] = 0;
+	length[AT_HLC  ] = 0;
+
+	for (i = 0; i < AT_NUM; ++i) {
+		kfree(bcs->commands[i]);
+		bcs->commands[i] = NULL;
+		if (length[i] &&
+		    !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
+			err("out of memory");
+			return -ENOMEM;
+		}
+	}
+
+	snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], "^SBPR=%u\r", proto);
+	snprintf(bcs->commands[AT_ISO  ], length[AT_ISO  ], "^SISO=%u\r", (unsigned) bcs->channel + 1);
+
+	return 0;
+}
+
+int gigaset_isdn_icall(struct at_state_t *at_state)
+{
+	struct cardstate *cs = at_state->cs;
+	struct bc_state *bcs = at_state->bcs;
+	isdn_ctrl response;
+	int retval;
+
+	/* fill ICALL structure */
+	response.parm.setup.si1 = 0;	/* default: unknown */
+	response.parm.setup.si2 = 0;
+	response.parm.setup.screen = 0;	//FIXME how to set these?
+	response.parm.setup.plan = 0;
+	if (!at_state->str_var[STR_ZBC]) {
+		/* no BC (internal call): assume speech, A-law */
+		response.parm.setup.si1 = 1;
+	} else if (!strcmp(at_state->str_var[STR_ZBC], "8890")) {
+		/* unrestricted digital information */
+		response.parm.setup.si1 = 7;
+	} else if (!strcmp(at_state->str_var[STR_ZBC], "8090A3")) {
+		/* speech, A-law */
+		response.parm.setup.si1 = 1;
+	} else if (!strcmp(at_state->str_var[STR_ZBC], "9090A3")) {
+		/* 3,1 kHz audio, A-law */
+		response.parm.setup.si1 = 1;
+		response.parm.setup.si2 = 2;
+	} else {
+		warn("RING ignored - unsupported BC %s",
+		     at_state->str_var[STR_ZBC]);
+		return ICALL_IGNORE;
+	}
+	if (at_state->str_var[STR_NMBR]) {
+		strncpy(response.parm.setup.phone, at_state->str_var[STR_NMBR],
+			sizeof response.parm.setup.phone - 1);
+		response.parm.setup.phone[sizeof response.parm.setup.phone - 1] = 0;
+	} else
+		response.parm.setup.phone[0] = 0;
+	if (at_state->str_var[STR_ZCPN]) {
+		strncpy(response.parm.setup.eazmsn, at_state->str_var[STR_ZCPN],
+			sizeof response.parm.setup.eazmsn - 1);
+		response.parm.setup.eazmsn[sizeof response.parm.setup.eazmsn - 1] = 0;
+	} else
+		response.parm.setup.eazmsn[0] = 0;
+
+	if (!bcs) {
+		notice("no channel for incoming call");
+		dbg(DEBUG_CMD, "Sending ICALLW");
+		response.command = ISDN_STAT_ICALLW;
+		response.arg = 0; //FIXME
+	} else {
+		dbg(DEBUG_CMD, "Sending ICALL");
+		response.command = ISDN_STAT_ICALL;
+		response.arg = bcs->channel; //FIXME
+	}
+	response.driver = cs->myid;
+	retval = cs->iif.statcallb(&response);
+	dbg(DEBUG_CMD, "Response: %d", retval);
+	switch (retval) {
+	case 0:	/* no takers */
+		return ICALL_IGNORE;
+	case 1:	/* alerting */
+		bcs->chstate |= CHS_NOTIFY_LL;
+		return ICALL_ACCEPT;
+	case 2:	/* reject */
+		return ICALL_REJECT;
+	case 3:	/* incomplete */
+		warn("LL requested unsupported feature: Incomplete Number");
+		return ICALL_IGNORE;
+	case 4:	/* proceeding */
+		/* Gigaset will send ALERTING anyway.
+		 * There doesn't seem to be a way to avoid this.
+		 */
+		return ICALL_ACCEPT;
+	case 5:	/* deflect */
+		warn("LL requested unsupported feature: Call Deflection");
+		return ICALL_IGNORE;
+	default:
+		err("LL error %d on ICALL", retval);
+		return ICALL_IGNORE;
+	}
+}
+
+/* Set Callback function pointer */
+int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid)
+{
+	isdn_if *iif = &cs->iif;
+
+	dbg(DEBUG_ANY, "Register driver capabilities to LL");
+
+	//iif->id[sizeof(iif->id) - 1]=0;
+	//strncpy(iif->id, isdnid, sizeof(iif->id) - 1);
+	if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index)
+	    >= sizeof iif->id)
+		return -ENOMEM; //FIXME EINVAL/...??
+
+	iif->owner = THIS_MODULE;
+	iif->channels = cs->channels;                        /* I am supporting just one channel *//* I was supporting...*/
+	iif->maxbufsize = MAX_BUF_SIZE;
+	iif->features = ISDN_FEATURE_L2_TRANS |   /* Our device is very advanced, therefore */
+		ISDN_FEATURE_L2_HDLC |
+#ifdef GIG_X75
+		ISDN_FEATURE_L2_X75I |
+#endif
+		ISDN_FEATURE_L3_TRANS |
+		ISDN_FEATURE_P_EURO;
+	iif->hl_hdrlen = HW_HDR_LEN;              /* Area for storing ack */
+	iif->command = command_from_LL;
+	iif->writebuf_skb = writebuf_from_LL;
+	iif->writecmd = NULL;                     /* Don't support isdnctrl */
+	iif->readstat = NULL;                     /* Don't support isdnctrl */
+	iif->rcvcallb_skb = NULL;                 /* Will be set by LL */
+	iif->statcallb = NULL;                    /* Will be set by LL */
+
+	if (!register_isdn(iif))
+		return 0;
+
+	cs->myid = iif->channels;                 /* Set my device id */
+	return 1;
+}
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
new file mode 100644
index 0000000..3a81d9c
--- /dev/null
+++ b/drivers/isdn/gigaset/interface.c
@@ -0,0 +1,718 @@
+/*
+ * interface to user space for the gigaset driver
+ *
+ * Copyright (c) 2004 by Hansjoerg Lipp <hjlipp@web.de>
+ *
+ * =====================================================================
+ *    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.
+ * =====================================================================
+ * Version: $Id: interface.c,v 1.14.4.15 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+#include <linux/gigaset_dev.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+/*** our ioctls ***/
+
+static int if_lock(struct cardstate *cs, int *arg)
+{
+	int cmd = *arg;
+
+	dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd);
+
+	if (cmd > 1)
+		return -EINVAL;
+
+	if (cmd < 0) {
+		*arg = atomic_read(&cs->mstate) == MS_LOCKED; //FIXME remove?
+		return 0;
+	}
+
+	if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED
+	    && atomic_read(&cs->connected)) {
+		cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
+		cs->ops->baud_rate(cs, B115200);
+		cs->ops->set_line_ctrl(cs, CS8);
+		cs->control_state = TIOCM_DTR|TIOCM_RTS;
+	}
+
+	cs->waiting = 1;
+	if (!gigaset_add_event(cs, &cs->at_state, EV_IF_LOCK,
+		               NULL, cmd, NULL)) {
+		cs->waiting = 0;
+		return -ENOMEM;
+	}
+
+	dbg(DEBUG_CMD, "scheduling IF_LOCK");
+	gigaset_schedule_event(cs);
+
+	wait_event(cs->waitqueue, !cs->waiting);
+
+	if (cs->cmd_result >= 0) {
+		*arg = cs->cmd_result;
+		return 0;
+	}
+
+	return cs->cmd_result;
+}
+
+static int if_version(struct cardstate *cs, unsigned arg[4])
+{
+	static const unsigned version[4] = GIG_VERSION;
+	static const unsigned compat[4] = GIG_COMPAT;
+	unsigned cmd = arg[0];
+
+	dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd);
+
+	switch (cmd) {
+	case GIGVER_DRIVER:
+		memcpy(arg, version, sizeof version);
+		return 0;
+	case GIGVER_COMPAT:
+		memcpy(arg, compat, sizeof compat);
+		return 0;
+	case GIGVER_FWBASE:
+		cs->waiting = 1;
+		if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER,
+			               NULL, 0, arg)) {
+			cs->waiting = 0;
+			return -ENOMEM;
+		}
+
+		dbg(DEBUG_CMD, "scheduling IF_VER");
+		gigaset_schedule_event(cs);
+
+		wait_event(cs->waitqueue, !cs->waiting);
+
+		if (cs->cmd_result >= 0)
+			return 0;
+
+		return cs->cmd_result;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int if_config(struct cardstate *cs, int *arg)
+{
+	dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg);
+
+	if (*arg != 1)
+		return -EINVAL;
+
+	if (atomic_read(&cs->mstate) != MS_LOCKED)
+		return -EBUSY;
+
+	*arg = 0;
+	return gigaset_enterconfigmode(cs);
+}
+
+/*** the terminal driver ***/
+/* stolen from usbserial and some other tty drivers */
+
+static int  if_open(struct tty_struct *tty, struct file *filp);
+static void if_close(struct tty_struct *tty, struct file *filp);
+static int  if_ioctl(struct tty_struct *tty, struct file *file,
+                     unsigned int cmd, unsigned long arg);
+static int  if_write_room(struct tty_struct *tty);
+static int  if_chars_in_buffer(struct tty_struct *tty);
+static void if_throttle(struct tty_struct *tty);
+static void if_unthrottle(struct tty_struct *tty);
+static void if_set_termios(struct tty_struct *tty, struct termios *old);
+static int  if_tiocmget(struct tty_struct *tty, struct file *file);
+static int  if_tiocmset(struct tty_struct *tty, struct file *file,
+                        unsigned int set, unsigned int clear);
+static int  if_write(struct tty_struct *tty,
+                     const unsigned char *buf, int count);
+
+static struct tty_operations if_ops = {
+	.open =			if_open,
+	.close =		if_close,
+	.ioctl =		if_ioctl,
+	.write =		if_write,
+	.write_room =		if_write_room,
+	.chars_in_buffer =	if_chars_in_buffer,
+	.set_termios =		if_set_termios,
+	.throttle =		if_throttle,
+	.unthrottle =		if_unthrottle,
+#if 0
+	.break_ctl =		serial_break,
+#endif
+	.tiocmget =		if_tiocmget,
+	.tiocmset =		if_tiocmset,
+};
+
+static int if_open(struct tty_struct *tty, struct file *filp)
+{
+	struct cardstate *cs;
+	unsigned long flags;
+
+	dbg(DEBUG_IF, "%d+%d: %s()", tty->driver->minor_start, tty->index,
+	    __FUNCTION__);
+
+	tty->driver_data = NULL;
+
+	cs = gigaset_get_cs_by_tty(tty);
+	if (!cs)
+		return -ENODEV;
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+	tty->driver_data = cs;
+
+	++cs->open_count;
+
+	if (cs->open_count == 1) {
+		spin_lock_irqsave(&cs->lock, flags);
+		cs->tty = tty;
+		spin_unlock_irqrestore(&cs->lock, flags);
+		tty->low_latency = 1; //FIXME test
+		//FIXME
+	}
+
+	up(&cs->sem);
+	return 0;
+}
+
+static void if_close(struct tty_struct *tty, struct file *filp)
+{
+	struct cardstate *cs;
+	unsigned long flags;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	down(&cs->sem);
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else {
+		if (!--cs->open_count) {
+			spin_lock_irqsave(&cs->lock, flags);
+			cs->tty = NULL;
+			spin_unlock_irqrestore(&cs->lock, flags);
+			//FIXME
+		}
+	}
+
+	up(&cs->sem);
+}
+
+static int if_ioctl(struct tty_struct *tty, struct file *file,
+                    unsigned int cmd, unsigned long arg)
+{
+	struct cardstate *cs;
+	int retval = -ENODEV;
+	int int_arg;
+	unsigned char buf[6];
+	unsigned version[4];
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __FUNCTION__, cmd);
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else {
+		retval = 0;
+		switch (cmd) {
+		case GIGASET_REDIR:
+			retval = get_user(int_arg, (int __user *) arg);
+			if (retval >= 0)
+				retval = if_lock(cs, &int_arg);
+			if (retval >= 0)
+				retval = put_user(int_arg, (int __user *) arg);
+			break;
+		case GIGASET_CONFIG:
+			retval = get_user(int_arg, (int __user *) arg);
+			if (retval >= 0)
+				retval = if_config(cs, &int_arg);
+			if (retval >= 0)
+				retval = put_user(int_arg, (int __user *) arg);
+			break;
+		case GIGASET_BRKCHARS:
+			//FIXME test if MS_LOCKED
+			gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS",
+			                   6, (const unsigned char *) arg, 1);
+			if (!atomic_read(&cs->connected)) {
+				dbg(DEBUG_ANY, "can't communicate with unplugged device");
+				retval = -ENODEV;
+				break;
+			}
+			retval = copy_from_user(&buf,
+			                        (const unsigned char __user *) arg, 6)
+			         ? -EFAULT : 0;
+			if (retval >= 0)
+				retval = cs->ops->brkchars(cs, buf);
+			break;
+		case GIGASET_VERSION:
+			retval = copy_from_user(version, (unsigned __user *) arg,
+			                        sizeof version) ? -EFAULT : 0;
+			if (retval >= 0)
+				retval = if_version(cs, version);
+			if (retval >= 0)
+				retval = copy_to_user((unsigned __user *) arg, version,
+				                      sizeof version)
+				         ? -EFAULT : 0;
+			break;
+	        default:
+			dbg(DEBUG_ANY, "%s: arg not supported - 0x%04x",
+			    __FUNCTION__, cmd);
+			retval = -ENOIOCTLCMD;
+		}
+	}
+
+	up(&cs->sem);
+
+	return retval;
+}
+
+static int if_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	struct cardstate *cs;
+	int retval;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	// FIXME read from device?
+	retval = cs->control_state & (TIOCM_RTS|TIOCM_DTR);
+
+	up(&cs->sem);
+
+	return retval;
+}
+
+static int if_tiocmset(struct tty_struct *tty, struct file *file,
+                       unsigned int set, unsigned int clear)
+{
+	struct cardstate *cs;
+	int retval;
+	unsigned mc;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	dbg(DEBUG_IF,
+	    "%u: %s(0x%x, 0x%x)", cs->minor_index, __FUNCTION__, set, clear);
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	if (!atomic_read(&cs->connected)) {
+		dbg(DEBUG_ANY, "can't communicate with unplugged device");
+		retval = -ENODEV;
+	} else {
+		mc = (cs->control_state | set) & ~clear & (TIOCM_RTS|TIOCM_DTR);
+		retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc);
+		cs->control_state = mc;
+	}
+
+	up(&cs->sem);
+
+	return retval;
+}
+
+static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+	struct cardstate *cs;
+	int retval = -ENODEV;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+		warn("can't write to unlocked device");
+		retval = -EBUSY;
+	} else if (!atomic_read(&cs->connected)) {
+		dbg(DEBUG_ANY, "can't write to unplugged device");
+		retval = -EBUSY; //FIXME
+	} else {
+		retval = cs->ops->write_cmd(cs, buf, count,
+		                            &cs->if_wake_tasklet);
+	}
+
+	up(&cs->sem);
+
+	return retval;
+}
+
+static int if_write_room(struct tty_struct *tty)
+{
+	struct cardstate *cs;
+	int retval = -ENODEV;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+		warn("can't write to unlocked device");
+		retval = -EBUSY; //FIXME
+	} else if (!atomic_read(&cs->connected)) {
+		dbg(DEBUG_ANY, "can't write to unplugged device");
+		retval = -EBUSY; //FIXME
+	} else
+		retval = cs->ops->write_room(cs);
+
+	up(&cs->sem);
+
+	return retval;
+}
+
+static int if_chars_in_buffer(struct tty_struct *tty)
+{
+	struct cardstate *cs;
+	int retval = -ENODEV;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+		warn("can't write to unlocked device");
+		retval = -EBUSY;
+	} else if (!atomic_read(&cs->connected)) {
+		dbg(DEBUG_ANY, "can't write to unplugged device");
+		retval = -EBUSY; //FIXME
+	} else
+		retval = cs->ops->chars_in_buffer(cs);
+
+	up(&cs->sem);
+
+	return retval;
+}
+
+static void if_throttle(struct tty_struct *tty)
+{
+	struct cardstate *cs;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	down(&cs->sem);
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else {
+		//FIXME
+	}
+
+	up(&cs->sem);
+}
+
+static void if_unthrottle(struct tty_struct *tty)
+{
+	struct cardstate *cs;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	down(&cs->sem);
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else {
+		//FIXME
+	}
+
+	up(&cs->sem);
+}
+
+static void if_set_termios(struct tty_struct *tty, struct termios *old)
+{
+	struct cardstate *cs;
+	unsigned int iflag;
+	unsigned int cflag;
+	unsigned int old_cflag;
+	unsigned int control_state, new_state;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	down(&cs->sem);
+
+	if (!cs->open_count) {
+		warn("%s: device not opened", __FUNCTION__);
+		goto out;
+	}
+
+	if (!atomic_read(&cs->connected)) {
+		dbg(DEBUG_ANY, "can't communicate with unplugged device");
+		goto out;
+	}
+
+	// stolen from mct_u232.c
+	iflag = tty->termios->c_iflag;
+	cflag = tty->termios->c_cflag;
+	old_cflag = old ? old->c_cflag : cflag; //FIXME?
+	dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x", cs->minor_index,
+	    iflag, cflag, old_cflag);
+
+	/* get a local copy of the current port settings */
+	control_state = cs->control_state;
+
+	/*
+	 * Update baud rate.
+	 * Do not attempt to cache old rates and skip settings,
+	 * disconnects screw such tricks up completely.
+	 * Premature optimization is the root of all evil.
+	 */
+
+        /* reassert DTR and (maybe) RTS on transition from B0 */
+	if ((old_cflag & CBAUD) == B0) {
+		new_state = control_state | TIOCM_DTR;
+		/* don't set RTS if using hardware flow control */
+		if (!(old_cflag & CRTSCTS))
+			new_state |= TIOCM_RTS;
+		dbg(DEBUG_IF, "%u: from B0 - set DTR%s", cs->minor_index,
+		    (new_state & TIOCM_RTS) ? " only" : "/RTS");
+		cs->ops->set_modem_ctrl(cs, control_state, new_state);
+		control_state = new_state;
+	}
+
+	cs->ops->baud_rate(cs, cflag & CBAUD);
+
+	if ((cflag & CBAUD) == B0) {
+		/* Drop RTS and DTR */
+		dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index);
+		new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS);
+		cs->ops->set_modem_ctrl(cs, control_state, new_state);
+		control_state = new_state;
+	}
+
+	/*
+	 * Update line control register (LCR)
+	 */
+
+	cs->ops->set_line_ctrl(cs, cflag);
+
+#if 0
+	//FIXME this hangs M101 [ts 2005-03-09]
+	//FIXME do we need this?
+	/*
+	 * Set flow control: well, I do not really now how to handle DTR/RTS.
+	 * Just do what we have seen with SniffUSB on Win98.
+	 */
+	/* Drop DTR/RTS if no flow control otherwise assert */
+	dbg(DEBUG_IF, "%u: control_state %x", cs->minor_index, control_state);
+	new_state = control_state;
+	if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
+		new_state |= TIOCM_DTR | TIOCM_RTS;
+	else
+		new_state &= ~(TIOCM_DTR | TIOCM_RTS);
+	if (new_state != control_state) {
+		dbg(DEBUG_IF, "%u: new_state %x", cs->minor_index, new_state);
+		gigaset_set_modem_ctrl(cs, control_state, new_state); // FIXME: mct_u232.c sets the old state here. is this a bug?
+		control_state = new_state;
+	}
+#endif
+
+	/* save off the modified port settings */
+	cs->control_state = control_state;
+
+out:
+	up(&cs->sem);
+}
+
+
+/* wakeup tasklet for the write operation */
+static void if_wake(unsigned long data)
+{
+	struct cardstate *cs = (struct cardstate *) data;
+	struct tty_struct *tty;
+
+	tty = cs->tty;
+	if (!tty)
+		return;
+
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup) {
+		dbg(DEBUG_IF, "write wakeup call");
+		tty->ldisc.write_wakeup(tty);
+	}
+
+	wake_up_interruptible(&tty->write_wait);
+}
+
+/*** interface to common ***/
+
+void gigaset_if_init(struct cardstate *cs)
+{
+	struct gigaset_driver *drv;
+
+	drv = cs->driver;
+	if (!drv->have_tty)
+		return;
+
+	tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs);
+	tty_register_device(drv->tty, cs->minor_index, NULL);
+}
+
+void gigaset_if_free(struct cardstate *cs)
+{
+	struct gigaset_driver *drv;
+
+	drv = cs->driver;
+	if (!drv->have_tty)
+		return;
+
+	tasklet_disable(&cs->if_wake_tasklet);
+	tasklet_kill(&cs->if_wake_tasklet);
+	tty_unregister_device(drv->tty, cs->minor_index);
+}
+
+void gigaset_if_receive(struct cardstate *cs,
+                        unsigned char *buffer, size_t len)
+{
+	unsigned long flags;
+	struct tty_struct *tty;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	if ((tty = cs->tty) == NULL)
+		dbg(DEBUG_ANY, "receive on closed device");
+	else {
+		tty_buffer_request_room(tty, len);
+		tty_insert_flip_string(tty, buffer, len);
+		tty_flip_buffer_push(tty);
+	}
+	spin_unlock_irqrestore(&cs->lock, flags);
+}
+EXPORT_SYMBOL_GPL(gigaset_if_receive);
+
+/* gigaset_if_initdriver
+ * Initialize tty interface.
+ * parameters:
+ *      drv             Driver
+ *      procname        Name of the driver (e.g. for /proc/tty/drivers)
+ *      devname         Name of the device files (prefix without minor number)
+ *      devfsname       Devfs name of the device files without %d
+ */
+void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
+                           const char *devname, const char *devfsname)
+{
+	unsigned minors = drv->minors;
+	int ret;
+	struct tty_driver *tty;
+
+	drv->have_tty = 0;
+
+	if ((drv->tty = alloc_tty_driver(minors)) == NULL)
+		goto enomem;
+	tty = drv->tty;
+
+	tty->magic =		TTY_DRIVER_MAGIC,
+	tty->major =		GIG_MAJOR,
+	tty->type =		TTY_DRIVER_TYPE_SERIAL,
+	tty->subtype =		SERIAL_TYPE_NORMAL,
+	tty->flags =		TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+
+	tty->driver_name =	procname;
+	tty->name =		devname;
+	tty->minor_start =	drv->minor;
+	tty->num =		drv->minors;
+
+	tty->owner =		THIS_MODULE;
+	tty->devfs_name =	devfsname;
+
+	tty->init_termios          = tty_std_termios; //FIXME
+	tty->init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL; //FIXME
+	tty_set_operations(tty, &if_ops);
+
+	ret = tty_register_driver(tty);
+	if (ret < 0) {
+		warn("failed to register tty driver (error %d)", ret);
+		goto error;
+	}
+	dbg(DEBUG_IF, "tty driver initialized");
+	drv->have_tty = 1;
+	return;
+
+enomem:
+	warn("could not allocate tty structures");
+error:
+	if (drv->tty)
+		put_tty_driver(drv->tty);
+}
+
+void gigaset_if_freedriver(struct gigaset_driver *drv)
+{
+	if (!drv->have_tty)
+		return;
+
+	drv->have_tty = 0;
+	tty_unregister_driver(drv->tty);
+	put_tty_driver(drv->tty);
+}
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
new file mode 100644
index 0000000..5744eb9
--- /dev/null
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -0,0 +1,1009 @@
+/*
+ * Common data handling layer for bas_gigaset
+ *
+ * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>,
+ *                       Hansjoerg Lipp <hjlipp@web.de>.
+ *
+ * =====================================================================
+ *	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.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: isocdata.c,v 1.2.2.5 2005/11/13 23:05:19 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+#include <linux/crc-ccitt.h>
+
+/* access methods for isowbuf_t */
+/* ============================ */
+
+/* initialize buffer structure
+ */
+void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle)
+{
+	atomic_set(&iwb->read, 0);
+	atomic_set(&iwb->nextread, 0);
+	atomic_set(&iwb->write, 0);
+	atomic_set(&iwb->writesem, 1);
+	iwb->wbits = 0;
+	iwb->idle = idle;
+	memset(iwb->data + BAS_OUTBUFSIZE, idle, BAS_OUTBUFPAD);
+}
+
+/* compute number of bytes which can be appended to buffer
+ * so that there is still room to append a maximum frame of flags
+ */
+static inline int isowbuf_freebytes(struct isowbuf_t *iwb)
+{
+	int read, write, freebytes;
+
+	read = atomic_read(&iwb->read);
+	write = atomic_read(&iwb->write);
+	if ((freebytes = read - write) > 0) {
+		/* no wraparound: need padding space within regular area */
+		return freebytes - BAS_OUTBUFPAD;
+	} else if (read < BAS_OUTBUFPAD) {
+		/* wraparound: can use space up to end of regular area */
+		return BAS_OUTBUFSIZE - write;
+	} else {
+		/* following the wraparound yields more space */
+		return freebytes + BAS_OUTBUFSIZE - BAS_OUTBUFPAD;
+	}
+}
+
+/* compare two offsets within the buffer
+ * The buffer is seen as circular, with the read position as start
+ * returns -1/0/1 if position a </=/> position b without crossing 'read'
+ */
+static inline int isowbuf_poscmp(struct isowbuf_t *iwb, int a, int b)
+{
+	int read;
+	if (a == b)
+		return 0;
+	read = atomic_read(&iwb->read);
+	if (a < b) {
+		if (a < read && read <= b)
+			return +1;
+		else
+			return -1;
+	} else {
+		if (b < read && read <= a)
+			return -1;
+		else
+			return +1;
+	}
+}
+
+/* start writing
+ * acquire the write semaphore
+ * return true if acquired, false if busy
+ */
+static inline int isowbuf_startwrite(struct isowbuf_t *iwb)
+{
+	if (!atomic_dec_and_test(&iwb->writesem)) {
+		atomic_inc(&iwb->writesem);
+		dbg(DEBUG_ISO,
+		    "%s: couldn't acquire iso write semaphore", __func__);
+		return 0;
+	}
+#ifdef CONFIG_GIGASET_DEBUG
+	dbg(DEBUG_ISO,
+	    "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d",
+	    __func__, iwb->data[atomic_read(&iwb->write)], iwb->wbits);
+#endif
+	return 1;
+}
+
+/* finish writing
+ * release the write semaphore and update the maximum buffer fill level
+ * returns the current write position
+ */
+static inline int isowbuf_donewrite(struct isowbuf_t *iwb)
+{
+	int write = atomic_read(&iwb->write);
+	atomic_inc(&iwb->writesem);
+	return write;
+}
+
+/* append bits to buffer without any checks
+ * - data contains bits to append, starting at LSB
+ * - nbits is number of bits to append (0..24)
+ * must be called with the write semaphore held
+ * If more than nbits bits are set in data, the extraneous bits are set in the
+ * buffer too, but the write position is only advanced by nbits.
+ */
+static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits)
+{
+	int write = atomic_read(&iwb->write);
+	data <<= iwb->wbits;
+	data |= iwb->data[write];
+	nbits += iwb->wbits;
+	while (nbits >= 8) {
+		iwb->data[write++] = data & 0xff;
+		write %= BAS_OUTBUFSIZE;
+		data >>= 8;
+		nbits -= 8;
+	}
+	iwb->wbits = nbits;
+	iwb->data[write] = data & 0xff;
+	atomic_set(&iwb->write, write);
+}
+
+/* put final flag on HDLC bitstream
+ * also sets the idle fill byte to the correspondingly shifted flag pattern
+ * must be called with the write semaphore held
+ */
+static inline void isowbuf_putflag(struct isowbuf_t *iwb)
+{
+	int write;
+
+	/* add two flags, thus reliably covering one byte */
+	isowbuf_putbits(iwb, 0x7e7e, 8);
+	/* recover the idle flag byte */
+	write = atomic_read(&iwb->write);
+	iwb->idle = iwb->data[write];
+	dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle);
+	/* mask extraneous bits in buffer */
+	iwb->data[write] &= (1 << iwb->wbits) - 1;
+}
+
+/* retrieve a block of bytes for sending
+ * The requested number of bytes is provided as a contiguous block.
+ * If necessary, the frame is filled to the requested number of bytes
+ * with the idle value.
+ * returns offset to frame, < 0 on busy or error
+ */
+int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
+{
+	int read, write, limit, src, dst;
+	unsigned char pbyte;
+
+	read = atomic_read(&iwb->nextread);
+	write = atomic_read(&iwb->write);
+	if (likely(read == write)) {
+		//dbg(DEBUG_STREAM, "%s: send buffer empty", __func__);
+		/* return idle frame */
+		return read < BAS_OUTBUFPAD ?
+		        BAS_OUTBUFSIZE : read - BAS_OUTBUFPAD;
+	}
+
+	limit = read + size;
+	dbg(DEBUG_STREAM,
+	    "%s: read=%d write=%d limit=%d", __func__, read, write, limit);
+#ifdef CONFIG_GIGASET_DEBUG
+	if (unlikely(size < 0 || size > BAS_OUTBUFPAD)) {
+		err("invalid size %d", size);
+		return -EINVAL;
+	}
+	src = atomic_read(&iwb->read);
+	if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD ||
+		     (read < src && limit >= src))) {
+		err("isoc write buffer frame reservation violated");
+		return -EFAULT;
+	}
+#endif
+
+	if (read < write) {
+		/* no wraparound in valid data */
+		if (limit >= write) {
+			/* append idle frame */
+			if (!isowbuf_startwrite(iwb))
+				return -EBUSY;
+			/* write position could have changed */
+			if (limit >= (write = atomic_read(&iwb->write))) {
+				pbyte = iwb->data[write]; /* save partial byte */
+				limit = write + BAS_OUTBUFPAD;
+				dbg(DEBUG_STREAM,
+				    "%s: filling %d->%d with %02x",
+				    __func__, write, limit, iwb->idle);
+				if (write + BAS_OUTBUFPAD < BAS_OUTBUFSIZE)
+					memset(iwb->data + write, iwb->idle,
+					       BAS_OUTBUFPAD);
+				else {
+					/* wraparound, fill entire pad area */
+					memset(iwb->data + write, iwb->idle,
+					       BAS_OUTBUFSIZE + BAS_OUTBUFPAD
+					       - write);
+					limit = 0;
+				}
+				dbg(DEBUG_STREAM, "%s: restoring %02x at %d",
+				    __func__, pbyte, limit);
+				iwb->data[limit] = pbyte; /* restore partial byte */
+				atomic_set(&iwb->write, limit);
+			}
+			isowbuf_donewrite(iwb);
+		}
+	} else {
+		/* valid data wraparound */
+		if (limit >= BAS_OUTBUFSIZE) {
+			/* copy wrapped part into pad area */
+			src = 0;
+			dst = BAS_OUTBUFSIZE;
+			while (dst < limit && src < write)
+				iwb->data[dst++] = iwb->data[src++];
+			if (dst <= limit) {
+				/* fill pad area with idle byte */
+				memset(iwb->data + dst, iwb->idle,
+				       BAS_OUTBUFSIZE + BAS_OUTBUFPAD - dst);
+			}
+			limit = src;
+		}
+	}
+	atomic_set(&iwb->nextread, limit);
+	return read;
+}
+
+/* dump_bytes
+ * write hex bytes to syslog for debugging
+ */
+static inline void dump_bytes(enum debuglevel level, const char *tag,
+                              unsigned char *bytes, int count)
+{
+#ifdef CONFIG_GIGASET_DEBUG
+	unsigned char c;
+	static char dbgline[3 * 32 + 1];
+	static const char hexdigit[] = "0123456789abcdef";
+	int i = 0;
+	IFNULLRET(tag);
+	IFNULLRET(bytes);
+	while (count-- > 0) {
+		if (i > sizeof(dbgline) - 4) {
+			dbgline[i] = '\0';
+			dbg(level, "%s:%s", tag, dbgline);
+			i = 0;
+		}
+		c = *bytes++;
+		dbgline[i] = (i && !(i % 12)) ? '-' : ' ';
+		i++;
+		dbgline[i++] = hexdigit[(c >> 4) & 0x0f];
+		dbgline[i++] = hexdigit[c & 0x0f];
+	}
+	dbgline[i] = '\0';
+	dbg(level, "%s:%s", tag, dbgline);
+#endif
+}
+
+/*============================================================================*/
+
+/* bytewise HDLC bitstuffing via table lookup
+ * lookup table: 5 subtables for 0..4 preceding consecutive '1' bits
+ * index: 256*(number of preceding '1' bits) + (next byte to stuff)
+ * value: bit  9.. 0 = result bits
+ *        bit 12..10 = number of trailing '1' bits in result
+ *        bit 14..13 = number of bits added by stuffing
+ */
+static u16 stufftab[5 * 256] = {
+// previous 1s = 0:
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x201f,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x205f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x209f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20df,
+ 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x048f,
+ 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x251f,
+ 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x04af,
+ 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x255f,
+ 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x08cf,
+ 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x299f,
+ 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x0cef,
+ 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x2ddf,
+
+// previous 1s = 1:
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x200f,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x202f,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x204f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x206f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x208f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20af,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20cf,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20ef,
+ 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x250f,
+ 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x252f,
+ 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x254f,
+ 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x256f,
+ 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x298f,
+ 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29af,
+ 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dcf,
+ 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x31ef,
+
+// previous 1s = 2:
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x2007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x2017,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x2027, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x2037,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2047, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x2057,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x2067, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x2077,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x2087, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x2097,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x20a7, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20b7,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x20c7, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20d7,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x20e7, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20f7,
+ 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x2507, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x2517,
+ 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x2527, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x2537,
+ 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x2547, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x2557,
+ 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x2567, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x2577,
+ 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x2987, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x2997,
+ 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x29a7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29b7,
+ 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dc7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dd7,
+ 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x31e7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x41f7,
+
+// previous 1s = 3:
+ 0x0000, 0x0001, 0x0002, 0x2003, 0x0004, 0x0005, 0x0006, 0x200b, 0x0008, 0x0009, 0x000a, 0x2013, 0x000c, 0x000d, 0x000e, 0x201b,
+ 0x0010, 0x0011, 0x0012, 0x2023, 0x0014, 0x0015, 0x0016, 0x202b, 0x0018, 0x0019, 0x001a, 0x2033, 0x001c, 0x001d, 0x001e, 0x203b,
+ 0x0020, 0x0021, 0x0022, 0x2043, 0x0024, 0x0025, 0x0026, 0x204b, 0x0028, 0x0029, 0x002a, 0x2053, 0x002c, 0x002d, 0x002e, 0x205b,
+ 0x0030, 0x0031, 0x0032, 0x2063, 0x0034, 0x0035, 0x0036, 0x206b, 0x0038, 0x0039, 0x003a, 0x2073, 0x003c, 0x003d, 0x203e, 0x207b,
+ 0x0040, 0x0041, 0x0042, 0x2083, 0x0044, 0x0045, 0x0046, 0x208b, 0x0048, 0x0049, 0x004a, 0x2093, 0x004c, 0x004d, 0x004e, 0x209b,
+ 0x0050, 0x0051, 0x0052, 0x20a3, 0x0054, 0x0055, 0x0056, 0x20ab, 0x0058, 0x0059, 0x005a, 0x20b3, 0x005c, 0x005d, 0x005e, 0x20bb,
+ 0x0060, 0x0061, 0x0062, 0x20c3, 0x0064, 0x0065, 0x0066, 0x20cb, 0x0068, 0x0069, 0x006a, 0x20d3, 0x006c, 0x006d, 0x006e, 0x20db,
+ 0x0070, 0x0071, 0x0072, 0x20e3, 0x0074, 0x0075, 0x0076, 0x20eb, 0x0078, 0x0079, 0x007a, 0x20f3, 0x207c, 0x207d, 0x20be, 0x40fb,
+ 0x0480, 0x0481, 0x0482, 0x2503, 0x0484, 0x0485, 0x0486, 0x250b, 0x0488, 0x0489, 0x048a, 0x2513, 0x048c, 0x048d, 0x048e, 0x251b,
+ 0x0490, 0x0491, 0x0492, 0x2523, 0x0494, 0x0495, 0x0496, 0x252b, 0x0498, 0x0499, 0x049a, 0x2533, 0x049c, 0x049d, 0x049e, 0x253b,
+ 0x04a0, 0x04a1, 0x04a2, 0x2543, 0x04a4, 0x04a5, 0x04a6, 0x254b, 0x04a8, 0x04a9, 0x04aa, 0x2553, 0x04ac, 0x04ad, 0x04ae, 0x255b,
+ 0x04b0, 0x04b1, 0x04b2, 0x2563, 0x04b4, 0x04b5, 0x04b6, 0x256b, 0x04b8, 0x04b9, 0x04ba, 0x2573, 0x04bc, 0x04bd, 0x253e, 0x257b,
+ 0x08c0, 0x08c1, 0x08c2, 0x2983, 0x08c4, 0x08c5, 0x08c6, 0x298b, 0x08c8, 0x08c9, 0x08ca, 0x2993, 0x08cc, 0x08cd, 0x08ce, 0x299b,
+ 0x08d0, 0x08d1, 0x08d2, 0x29a3, 0x08d4, 0x08d5, 0x08d6, 0x29ab, 0x08d8, 0x08d9, 0x08da, 0x29b3, 0x08dc, 0x08dd, 0x08de, 0x29bb,
+ 0x0ce0, 0x0ce1, 0x0ce2, 0x2dc3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dcb, 0x0ce8, 0x0ce9, 0x0cea, 0x2dd3, 0x0cec, 0x0ced, 0x0cee, 0x2ddb,
+ 0x10f0, 0x10f1, 0x10f2, 0x31e3, 0x10f4, 0x10f5, 0x10f6, 0x31eb, 0x20f8, 0x20f9, 0x20fa, 0x41f3, 0x257c, 0x257d, 0x29be, 0x46fb,
+
+// previous 1s = 4:
+ 0x0000, 0x2001, 0x0002, 0x2005, 0x0004, 0x2009, 0x0006, 0x200d, 0x0008, 0x2011, 0x000a, 0x2015, 0x000c, 0x2019, 0x000e, 0x201d,
+ 0x0010, 0x2021, 0x0012, 0x2025, 0x0014, 0x2029, 0x0016, 0x202d, 0x0018, 0x2031, 0x001a, 0x2035, 0x001c, 0x2039, 0x001e, 0x203d,
+ 0x0020, 0x2041, 0x0022, 0x2045, 0x0024, 0x2049, 0x0026, 0x204d, 0x0028, 0x2051, 0x002a, 0x2055, 0x002c, 0x2059, 0x002e, 0x205d,
+ 0x0030, 0x2061, 0x0032, 0x2065, 0x0034, 0x2069, 0x0036, 0x206d, 0x0038, 0x2071, 0x003a, 0x2075, 0x003c, 0x2079, 0x203e, 0x407d,
+ 0x0040, 0x2081, 0x0042, 0x2085, 0x0044, 0x2089, 0x0046, 0x208d, 0x0048, 0x2091, 0x004a, 0x2095, 0x004c, 0x2099, 0x004e, 0x209d,
+ 0x0050, 0x20a1, 0x0052, 0x20a5, 0x0054, 0x20a9, 0x0056, 0x20ad, 0x0058, 0x20b1, 0x005a, 0x20b5, 0x005c, 0x20b9, 0x005e, 0x20bd,
+ 0x0060, 0x20c1, 0x0062, 0x20c5, 0x0064, 0x20c9, 0x0066, 0x20cd, 0x0068, 0x20d1, 0x006a, 0x20d5, 0x006c, 0x20d9, 0x006e, 0x20dd,
+ 0x0070, 0x20e1, 0x0072, 0x20e5, 0x0074, 0x20e9, 0x0076, 0x20ed, 0x0078, 0x20f1, 0x007a, 0x20f5, 0x207c, 0x40f9, 0x20be, 0x417d,
+ 0x0480, 0x2501, 0x0482, 0x2505, 0x0484, 0x2509, 0x0486, 0x250d, 0x0488, 0x2511, 0x048a, 0x2515, 0x048c, 0x2519, 0x048e, 0x251d,
+ 0x0490, 0x2521, 0x0492, 0x2525, 0x0494, 0x2529, 0x0496, 0x252d, 0x0498, 0x2531, 0x049a, 0x2535, 0x049c, 0x2539, 0x049e, 0x253d,
+ 0x04a0, 0x2541, 0x04a2, 0x2545, 0x04a4, 0x2549, 0x04a6, 0x254d, 0x04a8, 0x2551, 0x04aa, 0x2555, 0x04ac, 0x2559, 0x04ae, 0x255d,
+ 0x04b0, 0x2561, 0x04b2, 0x2565, 0x04b4, 0x2569, 0x04b6, 0x256d, 0x04b8, 0x2571, 0x04ba, 0x2575, 0x04bc, 0x2579, 0x253e, 0x467d,
+ 0x08c0, 0x2981, 0x08c2, 0x2985, 0x08c4, 0x2989, 0x08c6, 0x298d, 0x08c8, 0x2991, 0x08ca, 0x2995, 0x08cc, 0x2999, 0x08ce, 0x299d,
+ 0x08d0, 0x29a1, 0x08d2, 0x29a5, 0x08d4, 0x29a9, 0x08d6, 0x29ad, 0x08d8, 0x29b1, 0x08da, 0x29b5, 0x08dc, 0x29b9, 0x08de, 0x29bd,
+ 0x0ce0, 0x2dc1, 0x0ce2, 0x2dc5, 0x0ce4, 0x2dc9, 0x0ce6, 0x2dcd, 0x0ce8, 0x2dd1, 0x0cea, 0x2dd5, 0x0cec, 0x2dd9, 0x0cee, 0x2ddd,
+ 0x10f0, 0x31e1, 0x10f2, 0x31e5, 0x10f4, 0x31e9, 0x10f6, 0x31ed, 0x20f8, 0x41f1, 0x20fa, 0x41f5, 0x257c, 0x46f9, 0x29be, 0x4b7d
+};
+
+/* hdlc_bitstuff_byte
+ * perform HDLC bitstuffing for one input byte (8 bits, LSB first)
+ * parameters:
+ *	cin	input byte
+ *	ones	number of trailing '1' bits in result before this step
+ *	iwb	pointer to output buffer structure (write semaphore must be held)
+ * return value:
+ *	number of trailing '1' bits in result after this step
+ */
+
+static inline int hdlc_bitstuff_byte(struct isowbuf_t *iwb, unsigned char cin,
+                                     int ones)
+{
+	u16 stuff;
+	int shiftinc, newones;
+
+	/* get stuffing information for input byte
+	 * value: bit  9.. 0 = result bits
+	 *        bit 12..10 = number of trailing '1' bits in result
+	 *        bit 14..13 = number of bits added by stuffing
+	 */
+	stuff = stufftab[256 * ones + cin];
+	shiftinc = (stuff >> 13) & 3;
+	newones = (stuff >> 10) & 7;
+	stuff &= 0x3ff;
+
+	/* append stuffed byte to output stream */
+	isowbuf_putbits(iwb, stuff, 8 + shiftinc);
+	return newones;
+}
+
+/* hdlc_buildframe
+ * Perform HDLC framing with bitstuffing on a byte buffer
+ * The input buffer is regarded as a sequence of bits, starting with the least
+ * significant bit of the first byte and ending with the most significant bit
+ * of the last byte. A 16 bit FCS is appended as defined by RFC 1662.
+ * Whenever five consecutive '1' bits appear in the resulting bit sequence, a
+ * '0' bit is inserted after them.
+ * The resulting bit string and a closing flag pattern (PPP_FLAG, '01111110')
+ * are appended to the output buffer starting at the given bit position, which
+ * is assumed to already contain a leading flag.
+ * The output buffer must have sufficient length; count + count/5 + 6 bytes
+ * starting at *out are safe and are verified to be present.
+ * parameters:
+ *	in	input buffer
+ *	count	number of bytes in input buffer
+ *	iwb	pointer to output buffer structure (write semaphore must be held)
+ * return value:
+ *	position of end of packet in output buffer on success,
+ *	-EAGAIN if write semaphore busy or buffer full
+ */
+
+static inline int hdlc_buildframe(struct isowbuf_t *iwb,
+                                  unsigned char *in, int count)
+{
+	int ones;
+	u16 fcs;
+	int end;
+	unsigned char c;
+
+	if (isowbuf_freebytes(iwb) < count + count / 5 + 6 ||
+	    !isowbuf_startwrite(iwb)) {
+		dbg(DEBUG_ISO, "%s: %d bytes free -> -EAGAIN",
+		    __func__, isowbuf_freebytes(iwb));
+		return -EAGAIN;
+	}
+
+	dump_bytes(DEBUG_STREAM, "snd data", in, count);
+
+	/* bitstuff and checksum input data */
+	fcs = PPP_INITFCS;
+	ones = 0;
+	while (count-- > 0) {
+		c = *in++;
+		ones = hdlc_bitstuff_byte(iwb, c, ones);
+		fcs = crc_ccitt_byte(fcs, c);
+	}
+
+	/* bitstuff and append FCS (complemented, least significant byte first) */
+	fcs ^= 0xffff;
+	ones = hdlc_bitstuff_byte(iwb, fcs & 0x00ff, ones);
+	ones = hdlc_bitstuff_byte(iwb, (fcs >> 8) & 0x00ff, ones);
+
+	/* put closing flag and repeat byte for flag idle */
+	isowbuf_putflag(iwb);
+	end = isowbuf_donewrite(iwb);
+	dump_bytes(DEBUG_STREAM_DUMP, "isowbuf", iwb->data, end + 1);
+	return end;
+}
+
+/* trans_buildframe
+ * Append a block of 'transparent' data to the output buffer,
+ * inverting the bytes.
+ * The output buffer must have sufficient length; count bytes
+ * starting at *out are safe and are verified to be present.
+ * parameters:
+ *	in	input buffer
+ *	count	number of bytes in input buffer
+ *	iwb	pointer to output buffer structure (write semaphore must be held)
+ * return value:
+ *	position of end of packet in output buffer on success,
+ *	-EAGAIN if write semaphore busy or buffer full
+ */
+
+static inline int trans_buildframe(struct isowbuf_t *iwb,
+				   unsigned char *in, int count)
+{
+	int write;
+	unsigned char c;
+
+	if (unlikely(count <= 0))
+		return atomic_read(&iwb->write); /* better ideas? */
+
+	if (isowbuf_freebytes(iwb) < count ||
+	    !isowbuf_startwrite(iwb)) {
+		dbg(DEBUG_ISO, "can't put %d bytes", count);
+		return -EAGAIN;
+	}
+
+	dbg(DEBUG_STREAM, "put %d bytes", count);
+	write = atomic_read(&iwb->write);
+	do {
+		c = gigaset_invtab[*in++];
+		iwb->data[write++] = c;
+		write %= BAS_OUTBUFSIZE;
+	} while (--count > 0);
+	atomic_set(&iwb->write, write);
+	iwb->idle = c;
+
+	return isowbuf_donewrite(iwb);
+}
+
+int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len)
+{
+	int result;
+
+	switch (bcs->proto2) {
+	case ISDN_PROTO_L2_HDLC:
+		result = hdlc_buildframe(bcs->hw.bas->isooutbuf, in, len);
+		dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d", __func__, len, result);
+		break;
+	default:			/* assume transparent */
+		result = trans_buildframe(bcs->hw.bas->isooutbuf, in, len);
+		dbg(DEBUG_ISO, "%s: %d bytes trans -> %d", __func__, len, result);
+	}
+	return result;
+}
+
+/* hdlc_putbyte
+ * append byte c to current skb of B channel structure *bcs, updating fcs
+ */
+static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs)
+{
+	bcs->fcs = crc_ccitt_byte(bcs->fcs, c);
+	if (unlikely(bcs->skb == NULL)) {
+		/* skipping */
+		return;
+	}
+	if (unlikely(bcs->skb->len == SBUFSIZE)) {
+		warn("received oversized packet discarded");
+		bcs->hw.bas->giants++;
+		dev_kfree_skb_any(bcs->skb);
+		bcs->skb = NULL;
+		return;
+	}
+	*gigaset_skb_put_quick(bcs->skb, 1) = c;
+}
+
+/* hdlc_flush
+ * drop partial HDLC data packet
+ */
+static inline void hdlc_flush(struct bc_state *bcs)
+{
+	/* clear skb or allocate new if not skipping */
+	if (likely(bcs->skb != NULL))
+		skb_trim(bcs->skb, 0);
+	else if (!bcs->ignore) {
+		if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
+			skb_reserve(bcs->skb, HW_HDR_LEN);
+		else
+			err("could not allocate skb");
+	}
+
+	/* reset packet state */
+	bcs->fcs = PPP_INITFCS;
+}
+
+/* hdlc_done
+ * process completed HDLC data packet
+ */
+static inline void hdlc_done(struct bc_state *bcs)
+{
+	struct sk_buff *procskb;
+
+	if (unlikely(bcs->ignore)) {
+		bcs->ignore--;
+		hdlc_flush(bcs);
+		return;
+	}
+
+	if ((procskb = bcs->skb) == NULL) {
+		/* previous error */
+		dbg(DEBUG_ISO, "%s: skb=NULL", __func__);
+		gigaset_rcv_error(NULL, bcs->cs, bcs);
+	} else if (procskb->len < 2) {
+		notice("received short frame (%d octets)", procskb->len);
+		bcs->hw.bas->runts++;
+		gigaset_rcv_error(procskb, bcs->cs, bcs);
+	} else if (bcs->fcs != PPP_GOODFCS) {
+		notice("frame check error (0x%04x)", bcs->fcs);
+		bcs->hw.bas->fcserrs++;
+		gigaset_rcv_error(procskb, bcs->cs, bcs);
+	} else {
+		procskb->len -= 2;		/* subtract FCS */
+		procskb->tail -= 2;
+		dbg(DEBUG_ISO,
+		    "%s: good frame (%d octets)", __func__, procskb->len);
+		dump_bytes(DEBUG_STREAM,
+		           "rcv data", procskb->data, procskb->len);
+		bcs->hw.bas->goodbytes += procskb->len;
+		gigaset_rcv_skb(procskb, bcs->cs, bcs);
+	}
+
+	if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
+		skb_reserve(bcs->skb, HW_HDR_LEN);
+	else
+		err("could not allocate skb");
+	bcs->fcs = PPP_INITFCS;
+}
+
+/* hdlc_frag
+ * drop HDLC data packet with non-integral last byte
+ */
+static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits)
+{
+	if (unlikely(bcs->ignore)) {
+		bcs->ignore--;
+		hdlc_flush(bcs);
+		return;
+	}
+
+	notice("received partial byte (%d bits)", inbits);
+	bcs->hw.bas->alignerrs++;
+	gigaset_rcv_error(bcs->skb, bcs->cs, bcs);
+
+	if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
+		skb_reserve(bcs->skb, HW_HDR_LEN);
+	else
+		err("could not allocate skb");
+	bcs->fcs = PPP_INITFCS;
+}
+
+/* bit counts lookup table for HDLC bit unstuffing
+ * index: input byte
+ * value: bit 0..3 = number of consecutive '1' bits starting from LSB
+ *        bit 4..6 = number of consecutive '1' bits starting from MSB
+ *		     (replacing 8 by 7 to make it fit; the algorithm won't care)
+ *        bit 7 set if there are 5 or more "interior" consecutive '1' bits
+ */
+static unsigned char bitcounts[256] = {
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x80, 0x06,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x80, 0x81, 0x80, 0x07,
+  0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14,
+  0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x15,
+  0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14,
+  0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x90, 0x16,
+  0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x24,
+  0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x25,
+  0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x34,
+  0x40, 0x41, 0x40, 0x42, 0x40, 0x41, 0x40, 0x43, 0x50, 0x51, 0x50, 0x52, 0x60, 0x61, 0x70, 0x78
+};
+
+/* hdlc_unpack
+ * perform HDLC frame processing (bit unstuffing, flag detection, FCS calculation)
+ * on a sequence of received data bytes (8 bits each, LSB first)
+ * pass on successfully received, complete frames as SKBs via gigaset_rcv_skb
+ * notify of errors via gigaset_rcv_error
+ * tally frames, errors etc. in BC structure counters
+ * parameters:
+ *	src	received data
+ *	count	number of received bytes
+ *	bcs	receiving B channel structure
+ */
+static inline void hdlc_unpack(unsigned char *src, unsigned count,
+                               struct bc_state *bcs)
+{
+	struct bas_bc_state *ubc;
+	int inputstate;
+	unsigned seqlen, inbyte, inbits;
+
+	IFNULLRET(bcs);
+	ubc = bcs->hw.bas;
+	IFNULLRET(ubc);
+
+	/* load previous state:
+	 * inputstate = set of flag bits:
+	 * - INS_flag_hunt: no complete opening flag received since connection setup or last abort
+	 * - INS_have_data: at least one complete data byte received since last flag
+	 * seqlen = number of consecutive '1' bits in last 7 input stream bits (0..7)
+	 * inbyte = accumulated partial data byte (if !INS_flag_hunt)
+	 * inbits = number of valid bits in inbyte, starting at LSB (0..6)
+	 */
+	inputstate = bcs->inputstate;
+	seqlen = ubc->seqlen;
+	inbyte = ubc->inbyte;
+	inbits = ubc->inbits;
+
+	/* bit unstuffing a byte a time
+	 * Take your time to understand this; it's straightforward but tedious.
+	 * The "bitcounts" lookup table is used to speed up the counting of
+	 * leading and trailing '1' bits.
+	 */
+	while (count--) {
+		unsigned char c = *src++;
+		unsigned char tabentry = bitcounts[c];
+		unsigned lead1 = tabentry & 0x0f;
+		unsigned trail1 = (tabentry >> 4) & 0x0f;
+
+		seqlen += lead1;
+
+		if (unlikely(inputstate & INS_flag_hunt)) {
+			if (c == PPP_FLAG) {
+				/* flag-in-one */
+				inputstate &= ~(INS_flag_hunt | INS_have_data);
+				inbyte = 0;
+				inbits = 0;
+			} else if (seqlen == 6 && trail1 != 7) {
+				/* flag completed & not followed by abort */
+				inputstate &= ~(INS_flag_hunt | INS_have_data);
+				inbyte = c >> (lead1 + 1);
+				inbits = 7 - lead1;
+				if (trail1 >= 8) {
+					/* interior stuffing: omitting the MSB handles most cases */
+					inbits--;
+					/* correct the incorrectly handled cases individually */
+					switch (c) {
+					case 0xbe:
+						inbyte = 0x3f;
+						break;
+					}
+				}
+			}
+			/* else: continue flag-hunting */
+		} else if (likely(seqlen < 5 && trail1 < 7)) {
+			/* streamlined case: 8 data bits, no stuffing */
+			inbyte |= c << inbits;
+			hdlc_putbyte(inbyte & 0xff, bcs);
+			inputstate |= INS_have_data;
+			inbyte >>= 8;
+			/* inbits unchanged */
+		} else if (likely(seqlen == 6 && inbits == 7 - lead1 &&
+				  trail1 + 1 == inbits &&
+				  !(inputstate & INS_have_data))) {
+			/* streamlined case: flag idle - state unchanged */
+		} else if (unlikely(seqlen > 6)) {
+			/* abort sequence */
+			ubc->aborts++;
+			hdlc_flush(bcs);
+			inputstate |= INS_flag_hunt;
+		} else if (seqlen == 6) {
+			/* closing flag, including (6 - lead1) '1's and one '0' from inbits */
+			if (inbits > 7 - lead1) {
+				hdlc_frag(bcs, inbits + lead1 - 7);
+				inputstate &= ~INS_have_data;
+			} else {
+				if (inbits < 7 - lead1)
+					ubc->stolen0s ++;
+				if (inputstate & INS_have_data) {
+					hdlc_done(bcs);
+					inputstate &= ~INS_have_data;
+				}
+			}
+
+			if (c == PPP_FLAG) {
+				/* complete flag, LSB overlaps preceding flag */
+				ubc->shared0s ++;
+				inbits = 0;
+				inbyte = 0;
+			} else if (trail1 != 7) {
+				/* remaining bits */
+				inbyte = c >> (lead1 + 1);
+				inbits = 7 - lead1;
+				if (trail1 >= 8) {
+					/* interior stuffing: omitting the MSB handles most cases */
+					inbits--;
+					/* correct the incorrectly handled cases individually */
+					switch (c) {
+					case 0xbe:
+						inbyte = 0x3f;
+						break;
+					}
+				}
+			} else {
+				/* abort sequence follows, skb already empty anyway */
+				ubc->aborts++;
+				inputstate |= INS_flag_hunt;
+			}
+		} else { /* (seqlen < 6) && (seqlen == 5 || trail1 >= 7) */
+
+			if (c == PPP_FLAG) {
+				/* complete flag */
+				if (seqlen == 5)
+					ubc->stolen0s++;
+				if (inbits) {
+					hdlc_frag(bcs, inbits);
+					inbits = 0;
+					inbyte = 0;
+				} else if (inputstate & INS_have_data)
+					hdlc_done(bcs);
+				inputstate &= ~INS_have_data;
+			} else if (trail1 == 7) {
+				/* abort sequence */
+				ubc->aborts++;
+				hdlc_flush(bcs);
+				inputstate |= INS_flag_hunt;
+			} else {
+				/* stuffed data */
+				if (trail1 < 7) { /* => seqlen == 5 */
+					/* stuff bit at position lead1, no interior stuffing */
+					unsigned char mask = (1 << lead1) - 1;
+					c = (c & mask) | ((c & ~mask) >> 1);
+					inbyte |= c << inbits;
+					inbits += 7;
+				} else if (seqlen < 5) { /* trail1 >= 8 */
+					/* interior stuffing: omitting the MSB handles most cases */
+					/* correct the incorrectly handled cases individually */
+					switch (c) {
+					case 0xbe:
+						c = 0x7e;
+						break;
+					}
+					inbyte |= c << inbits;
+					inbits += 7;
+				} else { /* seqlen == 5 && trail1 >= 8 */
+
+					/* stuff bit at lead1 *and* interior stuffing */
+					switch (c) {	/* unstuff individually */
+					case 0x7d:
+						c = 0x3f;
+						break;
+					case 0xbe:
+						c = 0x3f;
+						break;
+					case 0x3e:
+						c = 0x1f;
+						break;
+					case 0x7c:
+						c = 0x3e;
+						break;
+					}
+					inbyte |= c << inbits;
+					inbits += 6;
+				}
+				if (inbits >= 8) {
+					inbits -= 8;
+					hdlc_putbyte(inbyte & 0xff, bcs);
+					inputstate |= INS_have_data;
+					inbyte >>= 8;
+				}
+			}
+		}
+		seqlen = trail1 & 7;
+	}
+
+	/* save new state */
+	bcs->inputstate = inputstate;
+	ubc->seqlen = seqlen;
+	ubc->inbyte = inbyte;
+	ubc->inbits = inbits;
+}
+
+/* trans_receive
+ * pass on received USB frame transparently as SKB via gigaset_rcv_skb
+ * invert bytes
+ * tally frames, errors etc. in BC structure counters
+ * parameters:
+ *	src	received data
+ *	count	number of received bytes
+ *	bcs	receiving B channel structure
+ */
+static inline void trans_receive(unsigned char *src, unsigned count,
+                                 struct bc_state *bcs)
+{
+	struct sk_buff *skb;
+	int dobytes;
+	unsigned char *dst;
+
+	if (unlikely(bcs->ignore)) {
+		bcs->ignore--;
+		hdlc_flush(bcs);
+		return;
+	}
+	if (unlikely((skb = bcs->skb) == NULL)) {
+		bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
+		if (!skb) {
+			err("could not allocate skb");
+			return;
+		}
+		skb_reserve(skb, HW_HDR_LEN);
+	}
+	bcs->hw.bas->goodbytes += skb->len;
+	dobytes = TRANSBUFSIZE - skb->len;
+	while (count > 0) {
+		dst = skb_put(skb, count < dobytes ? count : dobytes);
+		while (count > 0 && dobytes > 0) {
+			*dst++ = gigaset_invtab[*src++];
+			count--;
+			dobytes--;
+		}
+		if (dobytes == 0) {
+			gigaset_rcv_skb(skb, bcs->cs, bcs);
+			bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
+			if (!skb) {
+				err("could not allocate skb");
+				return;
+			}
+			skb_reserve(bcs->skb, HW_HDR_LEN);
+			dobytes = TRANSBUFSIZE;
+		}
+	}
+}
+
+void gigaset_isoc_receive(unsigned char *src, unsigned count, struct bc_state *bcs)
+{
+	switch (bcs->proto2) {
+	case ISDN_PROTO_L2_HDLC:
+		hdlc_unpack(src, count, bcs);
+		break;
+	default:		/* assume transparent */
+		trans_receive(src, count, bcs);
+	}
+}
+
+/* == data input =========================================================== */
+
+static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf)
+{
+	struct cardstate *cs = inbuf->cs;
+	unsigned cbytes      = cs->cbytes;
+
+	while (numbytes--) {
+		/* copy next character, check for end of line */
+		switch (cs->respdata[cbytes] = *src++) {
+		case '\r':
+		case '\n':
+			/* end of line */
+			dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
+			    __func__, cbytes);
+			cs->cbytes = cbytes;
+			gigaset_handle_modem_response(cs);
+			cbytes = 0;
+			break;
+		default:
+			/* advance in line buffer, checking for overflow */
+			if (cbytes < MAX_RESP_SIZE - 1)
+				cbytes++;
+			else
+				warn("response too large");
+		}
+	}
+
+	/* save state */
+	cs->cbytes = cbytes;
+}
+
+
+/* process a block of data received through the control channel
+ */
+void gigaset_isoc_input(struct inbuf_t *inbuf)
+{
+	struct cardstate *cs = inbuf->cs;
+	unsigned tail, head, numbytes;
+	unsigned char *src;
+
+	head = atomic_read(&inbuf->head);
+	while (head != (tail = atomic_read(&inbuf->tail))) {
+		dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
+		if (head > tail)
+			tail = RBUFSIZE;
+		src = inbuf->data + head;
+		numbytes = tail - head;
+		dbg(DEBUG_INTR, "processing %u bytes", numbytes);
+
+		if (atomic_read(&cs->mstate) == MS_LOCKED) {
+			gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
+			                   numbytes, src, 0);
+			gigaset_if_receive(inbuf->cs, src, numbytes);
+		} else {
+			gigaset_dbg_buffer(DEBUG_CMD, "received response",
+			                   numbytes, src, 0);
+			cmd_loop(src, numbytes, inbuf);
+		}
+
+		head += numbytes;
+		if (head == RBUFSIZE)
+			head = 0;
+		dbg(DEBUG_INTR, "setting head to %u", head);
+		atomic_set(&inbuf->head, head);
+	}
+}
+
+
+/* == data output ========================================================== */
+
+/* gigaset_send_skb
+ * called by common.c to queue an skb for sending
+ * and start transmission if necessary
+ * parameters:
+ *	B Channel control structure
+ *	skb
+ * return value:
+ *	number of bytes accepted for sending
+ *	(skb->len if ok, 0 if out of buffer space)
+ *	or error code (< 0, eg. -EINVAL)
+ */
+int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb)
+{
+	int len;
+
+	IFNULLRETVAL(bcs, -EFAULT);
+	IFNULLRETVAL(skb, -EFAULT);
+	len = skb->len;
+
+	skb_queue_tail(&bcs->squeue, skb);
+	dbg(DEBUG_ISO,
+	    "%s: skb queued, qlen=%d", __func__, skb_queue_len(&bcs->squeue));
+
+	/* tasklet submits URB if necessary */
+	tasklet_schedule(&bcs->hw.bas->sent_tasklet);
+
+	return len;	/* ok so far */
+}
diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c
new file mode 100644
index 0000000..c6915fa
--- /dev/null
+++ b/drivers/isdn/gigaset/proc.c
@@ -0,0 +1,81 @@
+/*
+ * Stuff used by all variants of the driver
+ *
+ * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>,
+ *                       Hansjoerg Lipp <hjlipp@web.de>,
+ *                       Tilman Schmidt <tilman@imap.cc>.
+ *
+ * =====================================================================
+ *	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.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: proc.c,v 1.5.2.13 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+#include <linux/ctype.h>
+
+static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct cardstate *cs = usb_get_intfdata(intf);
+	return sprintf(buf, "%d\n", atomic_read(&cs->cidmode)); // FIXME use scnprintf for 13607 bit architectures (if PAGE_SIZE==4096)
+}
+
+static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct cardstate *cs = usb_get_intfdata(intf);
+	long int value;
+	char *end;
+
+	value = simple_strtol(buf, &end, 0);
+	while (*end)
+		if (!isspace(*end++))
+			return -EINVAL;
+	if (value < 0 || value > 1)
+			return -EINVAL;
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	cs->waiting = 1;
+	if (!gigaset_add_event(cs, &cs->at_state, EV_PROC_CIDMODE,
+		               NULL, value, NULL)) {
+		cs->waiting = 0;
+		up(&cs->sem);
+		return -ENOMEM;
+	}
+
+	dbg(DEBUG_CMD, "scheduling PROC_CIDMODE");
+	gigaset_schedule_event(cs);
+
+	wait_event(cs->waitqueue, !cs->waiting);
+
+	up(&cs->sem);
+
+	return count;
+}
+
+static DEVICE_ATTR(cidmode, S_IRUGO|S_IWUSR, show_cidmode, set_cidmode);
+
+/* free sysfs for device */
+void gigaset_free_dev_sysfs(struct usb_interface *interface)
+{
+	dbg(DEBUG_INIT, "removing sysfs entries");
+	device_remove_file(&interface->dev, &dev_attr_cidmode);
+}
+EXPORT_SYMBOL_GPL(gigaset_free_dev_sysfs);
+
+/* initialize sysfs for device */
+void gigaset_init_dev_sysfs(struct usb_interface *interface)
+{
+	dbg(DEBUG_INIT, "setting up sysfs");
+	device_create_file(&interface->dev, &dev_attr_cidmode);
+}
+EXPORT_SYMBOL_GPL(gigaset_init_dev_sysfs);
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
new file mode 100644
index 0000000..323fc73
--- /dev/null
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -0,0 +1,1008 @@
+/*
+ * USB driver for Gigaset 307x directly or using M105 Data.
+ *
+ * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>
+ *                   and Hansjoerg Lipp <hjlipp@web.de>.
+ *
+ * This driver was derived from the USB skeleton driver by
+ * Greg Kroah-Hartman <greg@kroah.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.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: usb-gigaset.c,v 1.85.4.18 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+/* Version Information */
+#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers <Eilers.Stefan@epost.de>"
+#define DRIVER_DESC "USB Driver for Gigaset 307x using M105"
+
+/* Module parameters */
+
+static int startmode = SM_ISDN;
+static int cidmode = 1;
+
+module_param(startmode, int, S_IRUGO);
+module_param(cidmode, int, S_IRUGO);
+MODULE_PARM_DESC(startmode, "start in isdn4linux mode");
+MODULE_PARM_DESC(cidmode, "Call-ID mode");
+
+#define GIGASET_MINORS     1
+#define GIGASET_MINOR      8
+#define GIGASET_MODULENAME "usb_gigaset"
+#define GIGASET_DEVFSNAME  "gig/usb/"
+#define GIGASET_DEVNAME    "ttyGU"
+
+#define IF_WRITEBUF 2000 //FIXME  // WAKEUP_CHARS: 256
+
+/* Values for the Gigaset M105 Data */
+#define USB_M105_VENDOR_ID	0x0681
+#define USB_M105_PRODUCT_ID	0x0009
+
+/* table of devices that work with this driver */
+static struct usb_device_id gigaset_table [] = {
+	{ USB_DEVICE(USB_M105_VENDOR_ID, USB_M105_PRODUCT_ID) },
+	{ }					/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, gigaset_table);
+
+/* Get a minor range for your devices from the usb maintainer */
+#define USB_SKEL_MINOR_BASE	200
+
+
+/*
+ * Control requests (empty fields: 00)
+ *
+ *       RT|RQ|VALUE|INDEX|LEN  |DATA
+ * In:
+ *       C1 08             01
+ *            Get flags (1 byte). Bits: 0=dtr,1=rts,3-7:?
+ *       C1 0F             ll ll
+ *            Get device information/status (llll: 0x200 and 0x40 seen).
+ *            Real size: I only saw MIN(llll,0x64).
+ *            Contents: seems to be always the same...
+ *              offset 0x00: Length of this structure (0x64) (len: 1,2,3 bytes)
+ *              offset 0x3c: String (16 bit chars): "MCCI USB Serial V2.0"
+ *              rest:        ?
+ * Out:
+ *       41 11
+ *            Initialize/reset device ?
+ *       41 00 xx 00
+ *            ? (xx=00 or 01; 01 on start, 00 on close)
+ *       41 07 vv mm
+ *            Set/clear flags vv=value, mm=mask (see RQ 08)
+ *       41 12 xx
+ *            Used before the following configuration requests are issued
+ *            (with xx=0x0f). I've seen other values<0xf, though.
+ *       41 01 xx xx
+ *            Set baud rate. xxxx=ceil(0x384000/rate)=trunc(0x383fff/rate)+1.
+ *       41 03 ps bb
+ *            Set byte size and parity. p:  0x20=even,0x10=odd,0x00=no parity
+ *                                     [    0x30: m, 0x40: s           ]
+ *                                     [s:  0: 1 stop bit; 1: 1.5; 2: 2]
+ *                                      bb: bits/byte (seen 7 and 8)
+ *       41 13 -- -- -- -- 10 00 ww 00 00 00 xx 00 00 00 yy 00 00 00 zz 00 00 00
+ *            ??
+ *            Initialization: 01, 40, 00, 00
+ *            Open device:    00  40, 00, 00
+ *            yy and zz seem to be equal, either 0x00 or 0x0a
+ *            (ww,xx) pairs seen: (00,00), (00,40), (01,40), (09,80), (19,80)
+ *       41 19 -- -- -- -- 06 00 00 00 00 xx 11 13
+ *            Used after every "configuration sequence" (RQ 12, RQs 01/03/13).
+ *            xx is usually 0x00 but was 0x7e before starting data transfer
+ *            in unimodem mode. So, this might be an array of characters that need
+ *            special treatment ("commit all bufferd data"?), 11=^Q, 13=^S.
+ *
+ * Unimodem mode: use "modprobe ppp_async flag_time=0" as the device _needs_ two
+ * flags per packet.
+ */
+
+static int gigaset_probe(struct usb_interface *interface,
+                         const struct usb_device_id *id);
+static void gigaset_disconnect(struct usb_interface *interface);
+
+static struct gigaset_driver *driver = NULL;
+static struct cardstate *cardstate = NULL;
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver gigaset_usb_driver = {
+	.name =         GIGASET_MODULENAME,
+	.probe =        gigaset_probe,
+	.disconnect =   gigaset_disconnect,
+	.id_table =     gigaset_table,
+};
+
+struct usb_cardstate {
+	struct usb_device       *udev;                  /* save off the usb device pointer */
+	struct usb_interface    *interface;             /* the interface for this device */
+	atomic_t                busy;                   /* bulk output in progress */
+
+	/* Output buffer for commands (M105: and data)*/
+	unsigned char           *bulk_out_buffer;       /* the buffer to send data */
+	int                     bulk_out_size;          /* the size of the send buffer */
+	__u8                    bulk_out_endpointAddr;  /* the address of the bulk out endpoint */
+	struct urb              *bulk_out_urb;          /* the urb used to transmit data */
+
+	/* Input buffer for command responses (M105: and data)*/
+	int                     rcvbuf_size;            /* the size of the receive buffer */
+	struct urb              *read_urb;              /* the urb used to receive data */
+	__u8                    int_in_endpointAddr;    /* the address of the bulk in endpoint */
+
+	char                    bchars[6];              /* req. 0x19 */
+};
+
+struct usb_bc_state {};
+
+static inline unsigned tiocm_to_gigaset(unsigned state)
+{
+	return ((state & TIOCM_DTR) ? 1 : 0) | ((state & TIOCM_RTS) ? 2 : 0);
+}
+
+#ifdef CONFIG_GIGASET_UNDOCREQ
+/* WARNING: EXPERIMENTAL! */
+static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
+                                  unsigned new_state)
+{
+	unsigned mask, val;
+	int r;
+
+	mask = tiocm_to_gigaset(old_state ^ new_state);
+	val = tiocm_to_gigaset(new_state);
+
+	dbg(DEBUG_USBREQ, "set flags 0x%02x with mask 0x%02x", val, mask);
+	r = usb_control_msg(cs->hw.usb->udev,
+	                    usb_sndctrlpipe(cs->hw.usb->udev, 0), 7, 0x41,
+	                    (val & 0xff) | ((mask & 0xff) << 8), 0,
+	                    NULL, 0, 2000 /*timeout??*/); // don't use this in an interrupt/BH
+	if (r < 0)
+		return r;
+	//..
+	return 0;
+}
+
+static int set_value(struct cardstate *cs, u8 req, u16 val)
+{
+	int r, r2;
+
+	dbg(DEBUG_USBREQ, "request %02x (%04x)", (unsigned)req, (unsigned)val);
+	r = usb_control_msg(cs->hw.usb->udev,
+	                    usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x12, 0x41,
+	                    0xf /*?*/, 0,
+	                    NULL, 0, 2000 /*?*/); /* no idea, what this does */
+	if (r < 0) {
+		err("error %d on request 0x12", -r);
+		return r;
+	}
+
+	r = usb_control_msg(cs->hw.usb->udev,
+	                    usb_sndctrlpipe(cs->hw.usb->udev, 0), req, 0x41,
+	                    val, 0,
+	                    NULL, 0, 2000 /*?*/);
+	if (r < 0)
+		err("error %d on request 0x%02x", -r, (unsigned)req);
+
+	r2 = usb_control_msg(cs->hw.usb->udev,
+	                     usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x19, 0x41,
+	                     0, 0, cs->hw.usb->bchars, 6, 2000 /*?*/);
+	if (r2 < 0)
+		err("error %d on request 0x19", -r2);
+
+	return r < 0 ? r : (r2 < 0 ? r2 : 0);
+}
+
+/* WARNING: HIGHLY EXPERIMENTAL! */
+// don't use this in an interrupt/BH
+static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
+{
+	u16 val;
+	u32 rate;
+
+	cflag &= CBAUD;
+
+	switch (cflag) {
+	//FIXME more values?
+	case    B300: rate =     300; break;
+	case    B600: rate =     600; break;
+	case   B1200: rate =    1200; break;
+	case   B2400: rate =    2400; break;
+	case   B4800: rate =    4800; break;
+	case   B9600: rate =    9600; break;
+	case  B19200: rate =   19200; break;
+	case  B38400: rate =   38400; break;
+	case  B57600: rate =   57600; break;
+	case B115200: rate =  115200; break;
+	default:
+		rate =  9600;
+		err("unsupported baudrate request 0x%x,"
+		    " using default of B9600", cflag);
+	}
+
+	val = 0x383fff / rate + 1;
+
+	return set_value(cs, 1, val);
+}
+
+/* WARNING: HIGHLY EXPERIMENTAL! */
+// don't use this in an interrupt/BH
+static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
+{
+	u16 val = 0;
+
+	/* set the parity */
+	if (cflag & PARENB)
+		val |= (cflag & PARODD) ? 0x10 : 0x20;
+
+	/* set the number of data bits */
+	switch (cflag & CSIZE) {
+	case CS5:
+		val |= 5 << 8; break;
+	case CS6:
+		val |= 6 << 8; break;
+	case CS7:
+		val |= 7 << 8; break;
+	case CS8:
+		val |= 8 << 8; break;
+	default:
+		err("CSIZE was not CS5-CS8, using default of 8");
+		val |= 8 << 8;
+		break;
+	}
+
+	/* set the number of stop bits */
+	if (cflag & CSTOPB) {
+		if ((cflag & CSIZE) == CS5)
+			val |= 1; /* 1.5 stop bits */ //FIXME is this okay?
+		else
+			val |= 2; /* 2 stop bits */
+	}
+
+	return set_value(cs, 3, val);
+}
+
+#else
+static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
+                                  unsigned new_state)
+{
+	return -EINVAL;
+}
+
+static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
+{
+	return -EINVAL;
+}
+
+static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
+{
+	return -EINVAL;
+}
+#endif
+
+
+ /*================================================================================================================*/
+static int gigaset_init_bchannel(struct bc_state *bcs)
+{
+	/* nothing to do for M10x */
+	gigaset_bchannel_up(bcs);
+	return 0;
+}
+
+static int gigaset_close_bchannel(struct bc_state *bcs)
+{
+	/* nothing to do for M10x */
+	gigaset_bchannel_down(bcs);
+	return 0;
+}
+
+//void send_ack_to_LL(void *data);
+static int write_modem(struct cardstate *cs);
+static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb);
+
+
+/* Handling of send queue. If there is already a skb opened, put data to
+ * the transfer buffer by calling "write_modem". Otherwise take a new skb out of the queue.
+ * This function will be called by the ISR via "transmit_chars" (USB: B-Channel Bulk callback handler
+ * via immediate task queue) or by writebuf_from_LL if the LL wants to transmit data.
+ */
+static void gigaset_modem_fill(unsigned long data)
+{
+	struct cardstate *cs = (struct cardstate *) data;
+	struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
+	struct cmdbuf_t *cb;
+	unsigned long flags;
+	int again;
+
+	dbg(DEBUG_OUTPUT, "modem_fill");
+
+	if (atomic_read(&cs->hw.usb->busy)) {
+		dbg(DEBUG_OUTPUT, "modem_fill: busy");
+		return;
+	}
+
+	do {
+		again = 0;
+		if (!bcs->tx_skb) { /* no skb is being sent */
+			spin_lock_irqsave(&cs->cmdlock, flags);
+			cb = cs->cmdbuf;
+			spin_unlock_irqrestore(&cs->cmdlock, flags);
+			if (cb) { /* commands to send? */
+				dbg(DEBUG_OUTPUT, "modem_fill: cb");
+				if (send_cb(cs, cb) < 0) {
+					dbg(DEBUG_OUTPUT,
+					    "modem_fill: send_cb failed");
+					again = 1; /* no callback will be called! */
+				}
+			} else { /* skbs to send? */
+				bcs->tx_skb = skb_dequeue(&bcs->squeue);
+				if (bcs->tx_skb)
+					dbg(DEBUG_INTR,
+					    "Dequeued skb (Adr: %lx)!",
+					    (unsigned long) bcs->tx_skb);
+			}
+		}
+
+		if (bcs->tx_skb) {
+			dbg(DEBUG_OUTPUT, "modem_fill: tx_skb");
+			if (write_modem(cs) < 0) {
+				dbg(DEBUG_OUTPUT,
+				    "modem_fill: write_modem failed");
+				// FIXME should we tell the LL?
+				again = 1; /* no callback will be called! */
+			}
+		}
+	} while (again);
+}
+
+/**
+ *	gigaset_read_int_callback
+ *
+ *      It is called if the data was received from the device. This is almost similiar to
+ *      the interrupt service routine in the serial device.
+ */
+static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs)
+{
+	int resubmit = 0;
+	int r;
+	struct cardstate *cs;
+	unsigned numbytes;
+	unsigned char *src;
+	//unsigned long flags;
+	struct inbuf_t *inbuf;
+
+	IFNULLRET(urb);
+	inbuf = (struct inbuf_t *) urb->context;
+	IFNULLRET(inbuf);
+	//spin_lock_irqsave(&inbuf->lock, flags);
+	cs = inbuf->cs;
+	IFNULLGOTO(cs, exit);
+	IFNULLGOTO(cardstate, exit);
+
+	if (!atomic_read(&cs->connected)) {
+		err("%s: disconnected", __func__);
+		goto exit;
+	}
+
+	if (!urb->status) {
+		numbytes = urb->actual_length;
+
+		if (numbytes) {
+			src = inbuf->rcvbuf;
+			if (unlikely(*src))
+				warn("%s: There was no leading 0, but 0x%02x!",
+				     __func__, (unsigned) *src);
+			++src; /* skip leading 0x00 */
+			--numbytes;
+			if (gigaset_fill_inbuf(inbuf, src, numbytes)) {
+				dbg(DEBUG_INTR, "%s-->BH", __func__);
+				gigaset_schedule_event(inbuf->cs);
+			}
+		} else
+			dbg(DEBUG_INTR, "Received zero block length");
+		resubmit = 1;
+	} else {
+		/* The urb might have been killed. */
+		dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d",
+		    __func__, urb->status);
+		if (urb->status != -ENOENT) /* not killed */
+			resubmit = 1;
+	}
+exit:
+	//spin_unlock_irqrestore(&inbuf->lock, flags);
+	if (resubmit) {
+		r = usb_submit_urb(urb, SLAB_ATOMIC);
+		if (r)
+			err("error %d when resubmitting urb.", -r);
+	}
+}
+
+
+/* This callback routine is called when data was transmitted to a B-Channel.
+ * Therefore it has to check if there is still data to transmit. This
+ * happens by calling modem_fill via task queue.
+ *
+ */
+static void gigaset_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct cardstate *cs = (struct cardstate *) urb->context;
+
+	IFNULLRET(cs);
+#ifdef CONFIG_GIGASET_DEBUG
+	if (!atomic_read(&cs->connected)) {
+		err("%s:not connected", __func__);
+		return;
+	}
+#endif
+	if (urb->status)
+		err("bulk transfer failed (status %d)", -urb->status); /* That's all we can do. Communication problems
+		                                                           are handeled by timeouts or network protocols */
+
+	atomic_set(&cs->hw.usb->busy, 0);
+	tasklet_schedule(&cs->write_tasklet);
+}
+
+static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
+{
+	struct cmdbuf_t *tcb;
+	unsigned long flags;
+	int count;
+	int status = -ENOENT; // FIXME
+	struct usb_cardstate *ucs = cs->hw.usb;
+
+	do {
+		if (!cb->len) {
+			tcb = cb;
+
+			spin_lock_irqsave(&cs->cmdlock, flags);
+			cs->cmdbytes -= cs->curlen;
+			dbg(DEBUG_OUTPUT, "send_cb: sent %u bytes, %u left",
+			    cs->curlen, cs->cmdbytes);
+			cs->cmdbuf = cb = cb->next;
+			if (cb) {
+				cb->prev = NULL;
+				cs->curlen = cb->len;
+			} else {
+				cs->lastcmdbuf = NULL;
+				cs->curlen = 0;
+			}
+			spin_unlock_irqrestore(&cs->cmdlock, flags);
+
+			if (tcb->wake_tasklet)
+				tasklet_schedule(tcb->wake_tasklet);
+			kfree(tcb);
+		}
+		if (cb) {
+			count = min(cb->len, ucs->bulk_out_size);
+			usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
+			                  usb_sndbulkpipe(ucs->udev,
+			                     ucs->bulk_out_endpointAddr & 0x0f),
+			                  cb->buf + cb->offset, count,
+			                  gigaset_write_bulk_callback, cs);
+
+			cb->offset += count;
+			cb->len -= count;
+			atomic_set(&ucs->busy, 1);
+			dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count);
+
+			status = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC);
+			if (status) {
+				atomic_set(&ucs->busy, 0);
+				err("could not submit urb (error %d).",
+				    -status);
+				cb->len = 0; /* skip urb => remove cb+wakeup in next loop cycle */
+			}
+		}
+	} while (cb && status); /* bei Fehler naechster Befehl //FIXME: ist das OK? */
+
+	return status;
+}
+
+/* Write string into transbuf and send it to modem.
+ */
+static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
+                             int len, struct tasklet_struct *wake_tasklet)
+{
+	struct cmdbuf_t *cb;
+	unsigned long flags;
+
+	gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+	                     DEBUG_TRANSCMD : DEBUG_LOCKCMD,
+	                   "CMD Transmit", len, buf, 0);
+
+	if (!atomic_read(&cs->connected)) {
+		err("%s: not connected", __func__);
+		return -ENODEV;
+	}
+
+	if (len <= 0)
+		return 0;
+
+	if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) {
+		err("%s: out of memory", __func__);
+		return -ENOMEM;
+	}
+
+	memcpy(cb->buf, buf, len);
+	cb->len = len;
+	cb->offset = 0;
+	cb->next = NULL;
+	cb->wake_tasklet = wake_tasklet;
+
+	spin_lock_irqsave(&cs->cmdlock, flags);
+	cb->prev = cs->lastcmdbuf;
+	if (cs->lastcmdbuf)
+		cs->lastcmdbuf->next = cb;
+	else {
+		cs->cmdbuf = cb;
+		cs->curlen = len;
+	}
+	cs->cmdbytes += len;
+	cs->lastcmdbuf = cb;
+	spin_unlock_irqrestore(&cs->cmdlock, flags);
+
+	tasklet_schedule(&cs->write_tasklet);
+	return len;
+}
+
+static int gigaset_write_room(struct cardstate *cs)
+{
+	unsigned long flags;
+	unsigned bytes;
+
+	spin_lock_irqsave(&cs->cmdlock, flags);
+	bytes = cs->cmdbytes;
+	spin_unlock_irqrestore(&cs->cmdlock, flags);
+
+	return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0;
+}
+
+static int gigaset_chars_in_buffer(struct cardstate *cs)
+{
+	return cs->cmdbytes;
+}
+
+static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])
+{
+#ifdef CONFIG_GIGASET_UNDOCREQ
+	gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf, 0);
+	memcpy(cs->hw.usb->bchars, buf, 6);
+	return usb_control_msg(cs->hw.usb->udev,
+	                       usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x19, 0x41,
+	                       0, 0, &buf, 6, 2000);
+#else
+	return -EINVAL;
+#endif
+}
+
+static int gigaset_freebcshw(struct bc_state *bcs)
+{
+	if (!bcs->hw.usb)
+		return 0;
+	//FIXME
+	kfree(bcs->hw.usb);
+	return 1;
+}
+
+/* Initialize the b-channel structure */
+static int gigaset_initbcshw(struct bc_state *bcs)
+{
+	bcs->hw.usb = kmalloc(sizeof(struct usb_bc_state), GFP_KERNEL);
+	if (!bcs->hw.usb)
+		return 0;
+
+	//bcs->hw.usb->trans_flg = READY_TO_TRNSMIT; /* B-Channel ready to transmit */
+	return 1;
+}
+
+static void gigaset_reinitbcshw(struct bc_state *bcs)
+{
+}
+
+static void gigaset_freecshw(struct cardstate *cs)
+{
+	//FIXME
+	tasklet_kill(&cs->write_tasklet);
+	kfree(cs->hw.usb);
+}
+
+static int gigaset_initcshw(struct cardstate *cs)
+{
+	struct usb_cardstate *ucs;
+
+	cs->hw.usb = ucs =
+		kmalloc(sizeof(struct usb_cardstate), GFP_KERNEL);
+	if (!ucs)
+		return 0;
+
+	ucs->bchars[0] = 0;
+	ucs->bchars[1] = 0;
+	ucs->bchars[2] = 0;
+	ucs->bchars[3] = 0;
+	ucs->bchars[4] = 0x11;
+	ucs->bchars[5] = 0x13;
+	ucs->bulk_out_buffer = NULL;
+	ucs->bulk_out_urb = NULL;
+	//ucs->urb_cmd_out = NULL;
+	ucs->read_urb = NULL;
+	tasklet_init(&cs->write_tasklet,
+	             &gigaset_modem_fill, (unsigned long) cs);
+
+	return 1;
+}
+
+/* Writes the data of the current open skb into the modem.
+ * We have to protect against multiple calls until the
+ * callback handler () is called , due to the fact that we
+ * are just allowed to send data once to an endpoint. Therefore
+ * we using "trans_flg" to synchonize ...
+ */
+static int write_modem(struct cardstate *cs)
+{
+	int ret;
+	int count;
+	struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
+	struct usb_cardstate *ucs = cs->hw.usb;
+	//unsigned long flags;
+
+	IFNULLRETVAL(bcs->tx_skb, -EINVAL);
+
+	dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len);
+
+	ret = -ENODEV;
+	IFNULLGOTO(ucs->bulk_out_buffer, error);
+	IFNULLGOTO(ucs->bulk_out_urb, error);
+	ret = 0;
+
+	if (!bcs->tx_skb->len) {
+		dev_kfree_skb_any(bcs->tx_skb);
+		bcs->tx_skb = NULL;
+		return -EINVAL;
+	}
+
+	/* Copy data to bulk out buffer and  // FIXME copying not necessary
+	 * transmit data
+	 */
+	count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
+	memcpy(ucs->bulk_out_buffer, bcs->tx_skb->data, count);
+	skb_pull(bcs->tx_skb, count);
+
+	usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
+	                  usb_sndbulkpipe(ucs->udev,
+	                                  ucs->bulk_out_endpointAddr & 0x0f),
+	                  ucs->bulk_out_buffer, count,
+	                  gigaset_write_bulk_callback, cs);
+	atomic_set(&ucs->busy, 1);
+	dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
+
+	ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC);
+	if (ret) {
+		err("could not submit urb (error %d).", -ret);
+		atomic_set(&ucs->busy, 0);
+	}
+	if (!bcs->tx_skb->len) {
+		/* skb sent completely */
+		gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0?
+
+		dbg(DEBUG_INTR,
+		    "kfree skb (Adr: %lx)!", (unsigned long) bcs->tx_skb);
+		dev_kfree_skb_any(bcs->tx_skb);
+		bcs->tx_skb = NULL;
+	}
+
+	return ret;
+error:
+	dev_kfree_skb_any(bcs->tx_skb);
+	bcs->tx_skb = NULL;
+	return ret;
+
+}
+
+static int gigaset_probe(struct usb_interface *interface,
+                         const struct usb_device_id *id)
+{
+	int retval;
+	struct usb_device *udev = interface_to_usbdev(interface);
+	unsigned int ifnum;
+	struct usb_host_interface *hostif;
+	struct cardstate *cs = NULL;
+	struct usb_cardstate *ucs = NULL;
+	//struct usb_interface_descriptor *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	//isdn_ctrl command;
+	int buffer_size;
+	int alt;
+	//unsigned long flags;
+
+	info("%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
+	    __func__, le16_to_cpu(udev->descriptor.idVendor),
+	    le16_to_cpu(udev->descriptor.idProduct));
+
+	retval = -ENODEV; //FIXME
+
+	/* See if the device offered us matches what we can accept */
+	if ((le16_to_cpu(udev->descriptor.idVendor  != USB_M105_VENDOR_ID)) ||
+	    (le16_to_cpu(udev->descriptor.idProduct != USB_M105_PRODUCT_ID)))
+		return -ENODEV;
+
+	/* this starts to become ascii art... */
+	hostif = interface->cur_altsetting;
+	alt = hostif->desc.bAlternateSetting;
+	ifnum = hostif->desc.bInterfaceNumber; // FIXME ?
+
+	if (alt != 0 || ifnum != 0) {
+		warn("ifnum %d, alt %d", ifnum, alt);
+		return -ENODEV;
+	}
+
+	/* Reject application specific intefaces
+	 *
+	 */
+	if (hostif->desc.bInterfaceClass != 255) {
+		info("%s: Device matched, but iface_desc[%d]->bInterfaceClass==%d !",
+		       __func__, ifnum, hostif->desc.bInterfaceClass);
+		return -ENODEV;
+	}
+
+	info("%s: Device matched ... !", __func__);
+
+	cs = gigaset_getunassignedcs(driver);
+	if (!cs) {
+		warn("No free cardstate!");
+		return -ENODEV;
+	}
+	ucs = cs->hw.usb;
+
+#if 0
+	if (usb_set_configuration(udev, udev->config[0].desc.bConfigurationValue) < 0) {
+		warn("set_configuration failed");
+		goto error;
+	}
+
+
+	if (usb_set_interface(udev, ifnum/*==0*/, alt/*==0*/) < 0) {
+		warn("usb_set_interface failed, device %d interface %d altsetting %d",
+		     udev->devnum, ifnum, alt);
+		goto error;
+	}
+#endif
+
+	/* set up the endpoint information */
+	/* check out the endpoints */
+	/* We will get 2 endpoints: One for sending commands to the device (bulk out) and one to
+	 * poll messages from the device(int in).
+	 * Therefore we will have an almost similiar situation as with our serial port handler.
+	 * If an connection will be established, we will have to create data in/out pipes
+	 * dynamically...
+	 */
+
+	endpoint = &hostif->endpoint[0].desc;
+
+	buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+	ucs->bulk_out_size = buffer_size;
+	ucs->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+	ucs->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
+	if (!ucs->bulk_out_buffer) {
+		err("Couldn't allocate bulk_out_buffer");
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	ucs->bulk_out_urb = usb_alloc_urb(0, SLAB_KERNEL);
+	if (!ucs->bulk_out_urb) {
+		err("Couldn't allocate bulk_out_buffer");
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	endpoint = &hostif->endpoint[1].desc;
+
+	atomic_set(&ucs->busy, 0);
+	ucs->udev = udev;
+	ucs->interface = interface;
+
+	ucs->read_urb = usb_alloc_urb(0, SLAB_KERNEL);
+	if (!ucs->read_urb) {
+		err("No free urbs available");
+		retval = -ENOMEM;
+		goto error;
+	}
+	buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+	ucs->rcvbuf_size = buffer_size;
+	ucs->int_in_endpointAddr = endpoint->bEndpointAddress;
+	cs->inbuf[0].rcvbuf = kmalloc(buffer_size, GFP_KERNEL);
+	if (!cs->inbuf[0].rcvbuf) {
+		err("Couldn't allocate rcvbuf");
+		retval = -ENOMEM;
+		goto error;
+	}
+	/* Fill the interrupt urb and send it to the core */
+	usb_fill_int_urb(ucs->read_urb, udev,
+	                 usb_rcvintpipe(udev,
+	                                endpoint->bEndpointAddress & 0x0f),
+	                 cs->inbuf[0].rcvbuf, buffer_size,
+	                 gigaset_read_int_callback,
+	                 cs->inbuf + 0, endpoint->bInterval);
+
+	retval = usb_submit_urb(ucs->read_urb, SLAB_KERNEL);
+	if (retval) {
+		err("Could not submit URB!");
+		goto error;
+	}
+
+	/* tell common part that the device is ready */
+	if (startmode == SM_LOCKED)
+		atomic_set(&cs->mstate, MS_LOCKED);
+	if (!gigaset_start(cs)) {
+		tasklet_kill(&cs->write_tasklet);
+		retval = -ENODEV; //FIXME
+		goto error;
+	}
+
+	/* save address of controller structure */
+	usb_set_intfdata(interface, cs);
+
+	/* set up device sysfs */
+	gigaset_init_dev_sysfs(interface);
+	return 0;
+
+error:
+	if (ucs->read_urb)
+		usb_kill_urb(ucs->read_urb);
+	kfree(ucs->bulk_out_buffer);
+	if (ucs->bulk_out_urb != NULL)
+		usb_free_urb(ucs->bulk_out_urb);
+	kfree(cs->inbuf[0].rcvbuf);
+	if (ucs->read_urb != NULL)
+		usb_free_urb(ucs->read_urb);
+	ucs->read_urb = ucs->bulk_out_urb = NULL;
+	cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL;
+	gigaset_unassign(cs);
+	return retval;
+}
+
+/**
+ *	skel_disconnect
+ */
+static void gigaset_disconnect(struct usb_interface *interface)
+{
+	struct cardstate *cs;
+	struct usb_cardstate *ucs;
+
+	cs = usb_get_intfdata(interface);
+
+	/* clear device sysfs */
+	gigaset_free_dev_sysfs(interface);
+
+	usb_set_intfdata(interface, NULL);
+	ucs = cs->hw.usb;
+	usb_kill_urb(ucs->read_urb);
+	//info("GigaSet USB device #%d will be disconnected", minor);
+
+	gigaset_stop(cs);
+
+	tasklet_kill(&cs->write_tasklet);
+
+	usb_kill_urb(ucs->bulk_out_urb);  /* FIXME: nur, wenn noetig */
+	//usb_kill_urb(ucs->urb_cmd_out);  /* FIXME: nur, wenn noetig */
+
+	kfree(ucs->bulk_out_buffer);
+	if (ucs->bulk_out_urb != NULL)
+		usb_free_urb(ucs->bulk_out_urb);
+	//if(ucs->urb_cmd_out != NULL)
+	//	usb_free_urb(ucs->urb_cmd_out);
+	kfree(cs->inbuf[0].rcvbuf);
+	if (ucs->read_urb != NULL)
+		usb_free_urb(ucs->read_urb);
+	ucs->read_urb = ucs->bulk_out_urb/*=ucs->urb_cmd_out*/=NULL;
+	cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL;
+
+	gigaset_unassign(cs);
+}
+
+static struct gigaset_ops ops = {
+	gigaset_write_cmd,
+	gigaset_write_room,
+	gigaset_chars_in_buffer,
+	gigaset_brkchars,
+	gigaset_init_bchannel,
+	gigaset_close_bchannel,
+	gigaset_initbcshw,
+	gigaset_freebcshw,
+	gigaset_reinitbcshw,
+	gigaset_initcshw,
+	gigaset_freecshw,
+	gigaset_set_modem_ctrl,
+	gigaset_baud_rate,
+	gigaset_set_line_ctrl,
+	gigaset_m10x_send_skb,
+	gigaset_m10x_input,
+};
+
+/**
+ *	usb_gigaset_init
+ * This function is called while kernel-module is loaded
+ */
+static int __init usb_gigaset_init(void)
+{
+	int result;
+
+	/* allocate memory for our driver state and intialize it */
+	if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
+	                               GIGASET_MODULENAME, GIGASET_DEVNAME,
+	                               GIGASET_DEVFSNAME, &ops,
+	                               THIS_MODULE)) == NULL)
+		goto error;
+
+	/* allocate memory for our device state and intialize it */
+	cardstate = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
+	if (!cardstate)
+		goto error;
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&gigaset_usb_driver);
+	if (result < 0) {
+		err("usb_gigaset: usb_register failed (error %d)",
+		    -result);
+		goto error;
+	}
+
+	info(DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+	return 0;
+
+error:	if (cardstate)
+		gigaset_freecs(cardstate);
+	cardstate = NULL;
+	if (driver)
+		gigaset_freedriver(driver);
+	driver = NULL;
+	return -1;
+}
+
+
+/**
+ *	usb_gigaset_exit
+ * This function is called while unloading the kernel-module
+ */
+static void __exit usb_gigaset_exit(void)
+{
+	gigaset_blockdriver(driver); /* => probe will fail
+	                              * => no gigaset_start any more
+	                              */
+
+	gigaset_shutdown(cardstate);
+	/* from now on, no isdn callback should be possible */
+
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&gigaset_usb_driver);
+	/* this will call the disconnect-callback */
+	/* from now on, no disconnect/probe callback should be running */
+
+	gigaset_freecs(cardstate);
+	cardstate = NULL;
+	gigaset_freedriver(driver);
+	driver = NULL;
+}
+
+
+module_init(usb_gigaset_init);
+module_exit(usb_gigaset_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h
index 296d6a6..3b43172 100644
--- a/drivers/isdn/hardware/avm/avmcard.h
+++ b/drivers/isdn/hardware/avm/avmcard.h
@@ -437,9 +437,7 @@
 #endif
 					dp += i;
 					i = 0;
-					if (i == 0)
-						break;
-					/* fall through */
+					break;
 				default:
 					*dp++ = b1_get_byte(base);
 					i--;
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
index dc7ef95..dbcca28 100644
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c
@@ -387,8 +387,7 @@
 
 	DBG(0x40, "hdlc_fill_fifo");
 
-	if (skb->len == 0)
-		BUG();
+	BUG_ON(skb->len == 0);
 
 	bcs->ctrl.sr.cmd &= ~HDLC_CMD_XME;
 	if (bcs->tx_skb->len > bcs->fifo_size) {
@@ -630,9 +629,7 @@
 
 	switch (pr) {
 	case PH_DATA | REQUEST:
-		if (bcs->tx_skb)
-			BUG();
-		
+		BUG_ON(bcs->tx_skb);
 		bcs->tx_skb = skb;
 		DBG_SKB(1, skb);
 		hdlc_fill_fifo(bcs);
diff --git a/drivers/isdn/hisax/hisax_isac.c b/drivers/isdn/hisax/hisax_isac.c
index f4972f6..81eac34 100644
--- a/drivers/isdn/hisax/hisax_isac.c
+++ b/drivers/isdn/hisax/hisax_isac.c
@@ -476,12 +476,10 @@
 	unsigned char cmd;
 	u_char *ptr;
 
-	if (!isac->tx_skb)
-		BUG();
+	BUG_ON(!isac->tx_skb);
 
 	count = isac->tx_skb->len;
-	if (count <= 0)
-		BUG();
+	BUG_ON(count <= 0);
 
 	DBG(DBG_IRQ, "count %d", count);
 
@@ -859,8 +857,7 @@
 			dev_kfree_skb(skb);
 			break;
 		}
-		if (isac->tx_skb)
-			BUG();
+		BUG_ON(isac->tx_skb);
 
 		isac->tx_skb = skb;
 		isac_fill_fifo(isac);
diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c
index 657817a..22fd5db 100644
--- a/drivers/isdn/hisax/st5481_b.c
+++ b/drivers/isdn/hisax/st5481_b.c
@@ -356,9 +356,7 @@
 
 	switch (pr) {
 	case PH_DATA | REQUEST:
-		if (bcs->b_out.tx_skb)
-			BUG();
-		
+		BUG_ON(bcs->b_out.tx_skb);
 		bcs->b_out.tx_skb = skb;
 		break;
 	case PH_ACTIVATE | REQUEST:
diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
index 941f702..493dc94 100644
--- a/drivers/isdn/hisax/st5481_d.c
+++ b/drivers/isdn/hisax/st5481_d.c
@@ -596,9 +596,7 @@
 		break;
 	case PH_DATA | REQUEST:
 		DBG(2, "PH_DATA REQUEST len %d", skb->len);
-		if (adapter->d_out.tx_skb)
-			BUG();
-
+		BUG_ON(adapter->d_out.tx_skb);
 		adapter->d_out.tx_skb = skb;
 		FsmEvent(&adapter->d_out.fsm, EV_DOUT_START_XMIT, NULL);
 		break;
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
index 1789b60..a4f7288 100644
--- a/drivers/isdn/i4l/Kconfig
+++ b/drivers/isdn/i4l/Kconfig
@@ -139,3 +139,4 @@
 
 endmenu
 
+source "drivers/isdn/gigaset/Kconfig"
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index b9fed8a..a0927d1 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -974,8 +974,7 @@
 	int slot;
 	int proto;
 
-	if (net_dev->local->master)
-		BUG(); // we're called with the master device always
+	BUG_ON(net_dev->local->master); // we're called with the master device always
 
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
@@ -2527,8 +2526,7 @@
 		printk(KERN_DEBUG "ippp: no decompressor defined!\n");
 		return skb;
 	}
-	if (!stat) // if we have a compressor, stat has been set as well
-		BUG();
+	BUG_ON(!stat); // if we have a compressor, stat has been set as well
 
 	if((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG) ) {
 		// compressed packets are compressed by their protocol type
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
index 94c9afb..f4f7122 100644
--- a/drivers/isdn/sc/ioctl.c
+++ b/drivers/isdn/sc/ioctl.c
@@ -46,7 +46,8 @@
 		pr_debug("%s: SCIOCRESET: ioctl received\n",
 			sc_adapter[card]->devicename);
 		sc_adapter[card]->StartOnReset = 0;
-		return (reset(card));
+		kfree(rcvmsg);
+		return reset(card);
 	}
 
 	case SCIOCLOAD:
@@ -183,7 +184,7 @@
 				sc_adapter[card]->devicename);
 
 		spid = kmalloc(SCIOC_SPIDSIZE, GFP_KERNEL);
-		if(!spid) {
+		if (!spid) {
 			kfree(rcvmsg);
 			return -ENOMEM;
 		}
@@ -195,10 +196,10 @@
 		if (!status) {
 			pr_debug("%s: SCIOCGETSPID: command successful\n",
 					sc_adapter[card]->devicename);
-		}
-		else {
+		} else {
 			pr_debug("%s: SCIOCGETSPID: command failed (status = %d)\n",
 				sc_adapter[card]->devicename, status);
+			kfree(spid);
 			kfree(rcvmsg);
 			return status;
 		}
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
new file mode 100644
index 0000000..2c4f20b
--- /dev/null
+++ b/drivers/leds/Kconfig
@@ -0,0 +1,77 @@
+
+menu "LED devices"
+
+config NEW_LEDS
+	bool "LED Support"
+	help
+	  Say Y to enable Linux LED support.  This is not related to standard
+	  keyboard LEDs which are controlled via the input system.
+
+config LEDS_CLASS
+	tristate "LED Class Support"
+	depends 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.
+
+config LEDS_TRIGGERS
+	bool "LED Trigger support"
+	depends NEW_LEDS
+	help
+	  This option enables trigger support for the leds class.
+	  These triggers allow kernel events to drive the LEDs and can
+	  be configured via sysfs. If unsure, say Y.
+
+config LEDS_CORGI
+	tristate "LED Support for the Sharp SL-C7x0 series"
+	depends LEDS_CLASS && PXA_SHARP_C7xx
+	help
+	  This option enables support for the LEDs on Sharp Zaurus
+	  SL-C7x0 series (C700, C750, C760, C860).
+
+config LEDS_LOCOMO
+	tristate "LED Support for Locomo device"
+	depends LEDS_CLASS && SHARP_LOCOMO
+	help
+	  This option enables support for the LEDs on Sharp Locomo.
+	  Zaurus models SL-5500 and SL-5600.
+
+config LEDS_SPITZ
+	tristate "LED Support for the Sharp SL-Cxx00 series"
+	depends LEDS_CLASS && PXA_SHARP_Cxx00
+	help
+	  This option enables support for the LEDs on Sharp Zaurus
+	  SL-Cxx00 series (C1000, C3000, C3100).
+
+config LEDS_IXP4XX
+	tristate "LED Support for GPIO connected LEDs on IXP4XX processors"
+	depends LEDS_CLASS && ARCH_IXP4XX
+	help
+	  This option enables support for the LEDs connected to GPIO
+	  outputs of the Intel IXP4XX processors.  To be useful the
+	  particular board must have LEDs and they must be connected
+	  to the GPIO lines.  If unsure, say Y.
+
+config LEDS_TOSA
+	tristate "LED Support for the Sharp SL-6000 series"
+	depends LEDS_CLASS && PXA_SHARPSL
+	help
+	  This option enables support for the LEDs on Sharp Zaurus
+	  SL-6000 series.
+
+config LEDS_TRIGGER_TIMER
+	tristate "LED Timer Trigger"
+	depends LEDS_TRIGGERS
+	help
+	  This allows LEDs to be controlled by a programmable timer
+	  via sysfs. If unsure, say Y.
+
+config LEDS_TRIGGER_IDE_DISK
+	bool "LED Timer Trigger"
+	depends LEDS_TRIGGERS && BLK_DEV_IDEDISK
+	help
+	  This allows LEDs to be controlled by IDE disk activity.
+	  If unsure, say Y.
+
+endmenu
+
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
new file mode 100644
index 0000000..40699d3
--- /dev/null
+++ b/drivers/leds/Makefile
@@ -0,0 +1,16 @@
+
+# LED Core
+obj-$(CONFIG_NEW_LEDS)			+= led-core.o
+obj-$(CONFIG_LEDS_CLASS)		+= led-class.o
+obj-$(CONFIG_LEDS_TRIGGERS)		+= led-triggers.o
+
+# LED Platform Drivers
+obj-$(CONFIG_LEDS_CORGI)		+= leds-corgi.o
+obj-$(CONFIG_LEDS_LOCOMO)		+= leds-locomo.o
+obj-$(CONFIG_LEDS_SPITZ)		+= leds-spitz.o
+obj-$(CONFIG_LEDS_IXP4XX)		+= leds-ixp4xx-gpio.o
+obj-$(CONFIG_LEDS_TOSA)			+= leds-tosa.o
+
+# LED Triggers
+obj-$(CONFIG_LEDS_TRIGGER_TIMER)	+= ledtrig-timer.o
+obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK)	+= ledtrig-ide-disk.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
new file mode 100644
index 0000000..b0b5d05
--- /dev/null
+++ b/drivers/leds/led-class.c
@@ -0,0 +1,167 @@
+/*
+ * LED Class Core
+ *
+ * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
+ * Copyright (C) 2005-2006 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+static struct class *leds_class;
+
+static ssize_t led_brightness_show(struct class_device *dev, char *buf)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	ssize_t ret = 0;
+
+	/* no lock needed for this */
+	sprintf(buf, "%u\n", led_cdev->brightness);
+	ret = strlen(buf) + 1;
+
+	return ret;
+}
+
+static ssize_t led_brightness_store(struct class_device *dev,
+				const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	ssize_t ret = -EINVAL;
+	char *after;
+	unsigned long state = simple_strtoul(buf, &after, 10);
+
+	if (after - buf > 0) {
+		ret = after - buf;
+		led_set_brightness(led_cdev, state);
+	}
+
+	return ret;
+}
+
+static CLASS_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);
+#endif
+
+/**
+ * led_classdev_suspend - suspend an led_classdev.
+ * @led_cdev: the led_classdev to suspend.
+ */
+void led_classdev_suspend(struct led_classdev *led_cdev)
+{
+	led_cdev->flags |= LED_SUSPENDED;
+	led_cdev->brightness_set(led_cdev, 0);
+}
+EXPORT_SYMBOL_GPL(led_classdev_suspend);
+
+/**
+ * led_classdev_resume - resume an led_classdev.
+ * @led_cdev: the led_classdev to resume.
+ */
+void led_classdev_resume(struct led_classdev *led_cdev)
+{
+	led_cdev->brightness_set(led_cdev, led_cdev->brightness);
+	led_cdev->flags &= ~LED_SUSPENDED;
+}
+EXPORT_SYMBOL_GPL(led_classdev_resume);
+
+/**
+ * led_classdev_register - register a new object of led_classdev class.
+ * @dev: The device to register.
+ * @led_cdev: the led_classdev structure for this device.
+ */
+int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
+{
+	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);
+
+	class_set_devdata(led_cdev->class_dev, led_cdev);
+
+	/* register the attributes */
+	class_device_create_file(led_cdev->class_dev,
+				&class_device_attr_brightness);
+
+	/* add to the list of leds */
+	write_lock(&leds_list_lock);
+	list_add_tail(&led_cdev->node, &leds_list);
+	write_unlock(&leds_list_lock);
+
+#ifdef CONFIG_LEDS_TRIGGERS
+	rwlock_init(&led_cdev->trigger_lock);
+
+	led_trigger_set_default(led_cdev);
+
+	class_device_create_file(led_cdev->class_dev,
+				&class_device_attr_trigger);
+#endif
+
+	printk(KERN_INFO "Registered led device: %s\n",
+			led_cdev->class_dev->class_id);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(led_classdev_register);
+
+/**
+ * led_classdev_unregister - unregisters a object of led_properties class.
+ * @led_cdev: the led device to unreigister
+ *
+ * Unregisters a previously registered via led_classdev_register object.
+ */
+void led_classdev_unregister(struct led_classdev *led_cdev)
+{
+	class_device_remove_file(led_cdev->class_dev,
+				&class_device_attr_brightness);
+#ifdef CONFIG_LEDS_TRIGGERS
+	class_device_remove_file(led_cdev->class_dev,
+				&class_device_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);
+
+	write_lock(&leds_list_lock);
+	list_del(&led_cdev->node);
+	write_unlock(&leds_list_lock);
+}
+EXPORT_SYMBOL_GPL(led_classdev_unregister);
+
+static int __init leds_init(void)
+{
+	leds_class = class_create(THIS_MODULE, "leds");
+	if (IS_ERR(leds_class))
+		return PTR_ERR(leds_class);
+	return 0;
+}
+
+static void __exit leds_exit(void)
+{
+	class_destroy(leds_class);
+}
+
+subsys_initcall(leds_init);
+module_exit(leds_exit);
+
+MODULE_AUTHOR("John Lenz, Richard Purdie");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LED Class Interface");
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
new file mode 100644
index 0000000..fe65413
--- /dev/null
+++ b/drivers/leds/led-core.c
@@ -0,0 +1,25 @@
+/*
+ * LED Class Core
+ *
+ * Copyright 2005-2006 Openedhand Ltd.
+ *
+ * Author: 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
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+rwlock_t leds_list_lock = RW_LOCK_UNLOCKED;
+LIST_HEAD(leds_list);
+
+EXPORT_SYMBOL_GPL(leds_list);
+EXPORT_SYMBOL_GPL(leds_list_lock);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
new file mode 100644
index 0000000..5e2cd8b
--- /dev/null
+++ b/drivers/leds/led-triggers.c
@@ -0,0 +1,239 @@
+/*
+ * LED Triggers Core
+ *
+ * Copyright 2005-2006 Openedhand Ltd.
+ *
+ * Author: 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
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+#include <linux/timer.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+/*
+ * Nests outside led_cdev->trigger_lock
+ */
+static rwlock_t triggers_list_lock = RW_LOCK_UNLOCKED;
+static LIST_HEAD(trigger_list);
+
+ssize_t led_trigger_store(struct class_device *dev, const char *buf,
+			size_t count)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	char trigger_name[TRIG_NAME_MAX];
+	struct led_trigger *trig;
+	size_t len;
+
+	trigger_name[sizeof(trigger_name) - 1] = '\0';
+	strncpy(trigger_name, buf, sizeof(trigger_name) - 1);
+	len = strlen(trigger_name);
+
+	if (len && trigger_name[len - 1] == '\n')
+		trigger_name[len - 1] = '\0';
+
+	if (!strcmp(trigger_name, "none")) {
+		write_lock(&led_cdev->trigger_lock);
+		led_trigger_set(led_cdev, NULL);
+		write_unlock(&led_cdev->trigger_lock);
+		return count;
+	}
+
+	read_lock(&triggers_list_lock);
+	list_for_each_entry(trig, &trigger_list, next_trig) {
+		if (!strcmp(trigger_name, trig->name)) {
+			write_lock(&led_cdev->trigger_lock);
+			led_trigger_set(led_cdev, trig);
+			write_unlock(&led_cdev->trigger_lock);
+
+			read_unlock(&triggers_list_lock);
+			return count;
+		}
+	}
+	read_unlock(&triggers_list_lock);
+
+	return -EINVAL;
+}
+
+
+ssize_t led_trigger_show(struct class_device *dev, char *buf)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_trigger *trig;
+	int len = 0;
+
+	read_lock(&triggers_list_lock);
+	read_lock(&led_cdev->trigger_lock);
+
+	if (!led_cdev->trigger)
+		len += sprintf(buf+len, "[none] ");
+	else
+		len += sprintf(buf+len, "none ");
+
+	list_for_each_entry(trig, &trigger_list, next_trig) {
+		if (led_cdev->trigger && !strcmp(led_cdev->trigger->name,
+							trig->name))
+			len += sprintf(buf+len, "[%s] ", trig->name);
+		else
+			len += sprintf(buf+len, "%s ", trig->name);
+	}
+	read_unlock(&led_cdev->trigger_lock);
+	read_unlock(&triggers_list_lock);
+
+	len += sprintf(len+buf, "\n");
+	return len;
+}
+
+void led_trigger_event(struct led_trigger *trigger,
+			enum led_brightness brightness)
+{
+	struct list_head *entry;
+
+	if (!trigger)
+		return;
+
+	read_lock(&trigger->leddev_list_lock);
+	list_for_each(entry, &trigger->led_cdevs) {
+		struct led_classdev *led_cdev;
+
+		led_cdev = list_entry(entry, struct led_classdev, trig_list);
+		led_set_brightness(led_cdev, brightness);
+	}
+	read_unlock(&trigger->leddev_list_lock);
+}
+
+/* Caller must ensure led_cdev->trigger_lock held */
+void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
+{
+	unsigned long flags;
+
+	/* Remove any existing trigger */
+	if (led_cdev->trigger) {
+		write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
+		list_del(&led_cdev->trig_list);
+		write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags);
+		if (led_cdev->trigger->deactivate)
+			led_cdev->trigger->deactivate(led_cdev);
+	}
+	if (trigger) {
+		write_lock_irqsave(&trigger->leddev_list_lock, flags);
+		list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs);
+		write_unlock_irqrestore(&trigger->leddev_list_lock, flags);
+		if (trigger->activate)
+			trigger->activate(led_cdev);
+	}
+	led_cdev->trigger = trigger;
+}
+
+void led_trigger_set_default(struct led_classdev *led_cdev)
+{
+	struct led_trigger *trig;
+
+	if (!led_cdev->default_trigger)
+		return;
+
+	read_lock(&triggers_list_lock);
+	write_lock(&led_cdev->trigger_lock);
+	list_for_each_entry(trig, &trigger_list, next_trig) {
+		if (!strcmp(led_cdev->default_trigger, trig->name))
+			led_trigger_set(led_cdev, trig);
+	}
+	write_unlock(&led_cdev->trigger_lock);
+	read_unlock(&triggers_list_lock);
+}
+
+int led_trigger_register(struct led_trigger *trigger)
+{
+	struct led_classdev *led_cdev;
+
+	rwlock_init(&trigger->leddev_list_lock);
+	INIT_LIST_HEAD(&trigger->led_cdevs);
+
+	/* Add to the list of led triggers */
+	write_lock(&triggers_list_lock);
+	list_add_tail(&trigger->next_trig, &trigger_list);
+	write_unlock(&triggers_list_lock);
+
+	/* Register with any LEDs that have this as a default trigger */
+	read_lock(&leds_list_lock);
+	list_for_each_entry(led_cdev, &leds_list, node) {
+		write_lock(&led_cdev->trigger_lock);
+		if (!led_cdev->trigger && led_cdev->default_trigger &&
+			    !strcmp(led_cdev->default_trigger, trigger->name))
+			led_trigger_set(led_cdev, trigger);
+		write_unlock(&led_cdev->trigger_lock);
+	}
+	read_unlock(&leds_list_lock);
+
+	return 0;
+}
+
+void led_trigger_register_simple(const char *name, struct led_trigger **tp)
+{
+	struct led_trigger *trigger;
+
+	trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
+
+	if (trigger) {
+		trigger->name = name;
+		led_trigger_register(trigger);
+	}
+	*tp = trigger;
+}
+
+void led_trigger_unregister(struct led_trigger *trigger)
+{
+	struct led_classdev *led_cdev;
+
+	/* Remove from the list of led triggers */
+	write_lock(&triggers_list_lock);
+	list_del(&trigger->next_trig);
+	write_unlock(&triggers_list_lock);
+
+	/* Remove anyone actively using this trigger */
+	read_lock(&leds_list_lock);
+	list_for_each_entry(led_cdev, &leds_list, node) {
+		write_lock(&led_cdev->trigger_lock);
+		if (led_cdev->trigger == trigger)
+			led_trigger_set(led_cdev, NULL);
+		write_unlock(&led_cdev->trigger_lock);
+	}
+	read_unlock(&leds_list_lock);
+}
+
+void led_trigger_unregister_simple(struct led_trigger *trigger)
+{
+	led_trigger_unregister(trigger);
+	kfree(trigger);
+}
+
+/* Used by LED Class */
+EXPORT_SYMBOL_GPL(led_trigger_set);
+EXPORT_SYMBOL_GPL(led_trigger_set_default);
+EXPORT_SYMBOL_GPL(led_trigger_show);
+EXPORT_SYMBOL_GPL(led_trigger_store);
+
+/* LED Trigger Interface */
+EXPORT_SYMBOL_GPL(led_trigger_register);
+EXPORT_SYMBOL_GPL(led_trigger_unregister);
+
+/* Simple LED Tigger Interface */
+EXPORT_SYMBOL_GPL(led_trigger_register_simple);
+EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);
+EXPORT_SYMBOL_GPL(led_trigger_event);
+
+MODULE_AUTHOR("Richard Purdie");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LED Triggers Core");
diff --git a/drivers/leds/leds-corgi.c b/drivers/leds/leds-corgi.c
new file mode 100644
index 0000000..bb7d84d
--- /dev/null
+++ b/drivers/leds/leds-corgi.c
@@ -0,0 +1,121 @@
+/*
+ * LED Triggers Core
+ *
+ * Copyright 2005-2006 Openedhand Ltd.
+ *
+ * Author: 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
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <asm/mach-types.h>
+#include <asm/arch/corgi.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/hardware/scoop.h>
+
+static void corgiled_amber_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+	if (value)
+		GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
+	else
+		GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
+}
+
+static void corgiled_green_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+	if (value)
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
+	else
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
+}
+
+static struct led_classdev corgi_amber_led = {
+	.name			= "corgi:amber",
+	.default_trigger	= "sharpsl-charge",
+	.brightness_set		= corgiled_amber_set,
+};
+
+static struct led_classdev corgi_green_led = {
+	.name			= "corgi:green",
+	.default_trigger	= "nand-disk",
+	.brightness_set		= corgiled_green_set,
+};
+
+#ifdef CONFIG_PM
+static int corgiled_suspend(struct platform_device *dev, pm_message_t state)
+{
+#ifdef CONFIG_LEDS_TRIGGERS
+	if (corgi_amber_led.trigger && strcmp(corgi_amber_led.trigger->name, "sharpsl-charge"))
+#endif
+		led_classdev_suspend(&corgi_amber_led);
+	led_classdev_suspend(&corgi_green_led);
+	return 0;
+}
+
+static int corgiled_resume(struct platform_device *dev)
+{
+	led_classdev_resume(&corgi_amber_led);
+	led_classdev_resume(&corgi_green_led);
+	return 0;
+}
+#endif
+
+static int corgiled_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = led_classdev_register(&pdev->dev, &corgi_amber_led);
+	if (ret < 0)
+		return ret;
+
+	ret = led_classdev_register(&pdev->dev, &corgi_green_led);
+	if (ret < 0)
+		led_classdev_unregister(&corgi_amber_led);
+
+	return ret;
+}
+
+static int corgiled_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&corgi_amber_led);
+	led_classdev_unregister(&corgi_green_led);
+	return 0;
+}
+
+static struct platform_driver corgiled_driver = {
+	.probe		= corgiled_probe,
+	.remove		= corgiled_remove,
+#ifdef CONFIG_PM
+	.suspend	= corgiled_suspend,
+	.resume		= corgiled_resume,
+#endif
+	.driver		= {
+		.name		= "corgi-led",
+	},
+};
+
+static int __init corgiled_init(void)
+{
+	return platform_driver_register(&corgiled_driver);
+}
+
+static void __exit corgiled_exit(void)
+{
+ 	platform_driver_unregister(&corgiled_driver);
+}
+
+module_init(corgiled_init);
+module_exit(corgiled_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
+MODULE_DESCRIPTION("Corgi LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-ixp4xx-gpio.c b/drivers/leds/leds-ixp4xx-gpio.c
new file mode 100644
index 0000000..30ced15
--- /dev/null
+++ b/drivers/leds/leds-ixp4xx-gpio.c
@@ -0,0 +1,215 @@
+/*
+ * IXP4XX GPIO driver LED driver
+ *
+ * Author: John Bowler <jbowler@acm.org>
+ *
+ * Copyright (c) 2006 John Bowler
+ *
+ * Permission is hereby granted, free of charge, to any
+ * person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the
+ * Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice
+ * shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+ * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+ * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/leds.h>
+#include <asm/arch/hardware.h>
+
+extern spinlock_t gpio_lock;
+
+/* Up to 16 gpio lines are possible. */
+#define GPIO_MAX 16
+static struct ixp4xxgpioled_device {
+	struct led_classdev ancestor;
+	int               flags;
+} ixp4xxgpioled_devices[GPIO_MAX];
+
+void ixp4xxgpioled_brightness_set(struct led_classdev *pled,
+				enum led_brightness value)
+{
+	const struct ixp4xxgpioled_device *const ixp4xx_dev =
+		container_of(pled, struct ixp4xxgpioled_device, ancestor);
+	const u32 gpio_pin = ixp4xx_dev - ixp4xxgpioled_devices;
+
+	if (gpio_pin < GPIO_MAX && ixp4xx_dev->ancestor.name != 0) {
+		/* Set or clear the 'gpio_pin' bit according to the style
+		 * and the required setting (value > 0 == on)
+		 */
+		const int gpio_value =
+			(value > 0) == (ixp4xx_dev->flags != IXP4XX_GPIO_LOW) ?
+				IXP4XX_GPIO_HIGH : IXP4XX_GPIO_LOW;
+
+		{
+			unsigned long flags;
+			spin_lock_irqsave(&gpio_lock, flags);
+			gpio_line_set(gpio_pin, gpio_value);
+			spin_unlock_irqrestore(&gpio_lock, flags);
+		}
+	}
+}
+
+/* LEDs are described in resources, the following iterates over the valid
+ * LED resources.
+ */
+#define for_all_leds(i, pdev) \
+	for (i=0; i<pdev->num_resources; ++i) \
+		if (pdev->resource[i].start < GPIO_MAX && \
+			pdev->resource[i].name != 0)
+
+/* The following applies 'operation' to each LED from the given platform,
+ * the function always returns 0 to allow tail call elimination.
+ */
+static int apply_to_all_leds(struct platform_device *pdev,
+	void (*operation)(struct led_classdev *pled))
+{
+	int i;
+
+	for_all_leds(i, pdev)
+		operation(&ixp4xxgpioled_devices[pdev->resource[i].start].ancestor);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int ixp4xxgpioled_suspend(struct platform_device *pdev,
+				pm_message_t state)
+{
+	return apply_to_all_leds(pdev, led_classdev_suspend);
+}
+
+static int ixp4xxgpioled_resume(struct platform_device *pdev)
+{
+	return apply_to_all_leds(pdev, led_classdev_resume);
+}
+#endif
+
+static void ixp4xxgpioled_remove_one_led(struct led_classdev *pled)
+{
+	led_classdev_unregister(pled);
+	pled->name = 0;
+}
+
+static int ixp4xxgpioled_remove(struct platform_device *pdev)
+{
+	return apply_to_all_leds(pdev, ixp4xxgpioled_remove_one_led);
+}
+
+static int ixp4xxgpioled_probe(struct platform_device *pdev)
+{
+	/* The board level has to tell the driver where the
+	 * LEDs are connected - there is no way to find out
+	 * electrically.  It must also say whether the GPIO
+	 * lines are active high or active low.
+	 *
+	 * To do this read the num_resources (the number of
+	 * LEDs) and the struct resource (the data for each
+	 * LED).  The name comes from the resource, and it
+	 * isn't copied.
+	 */
+	int i;
+
+	for_all_leds(i, pdev) {
+		const u8 gpio_pin = pdev->resource[i].start;
+		int      rc;
+
+		if (ixp4xxgpioled_devices[gpio_pin].ancestor.name == 0) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&gpio_lock, flags);
+			gpio_line_config(gpio_pin, IXP4XX_GPIO_OUT);
+			/* The config can, apparently, reset the state,
+			 * I suspect the gpio line may be an input and
+			 * the config may cause the line to be latched,
+			 * so the setting depends on how the LED is
+			 * connected to the line (which affects how it
+			 * floats if not driven).
+			 */
+			gpio_line_set(gpio_pin, IXP4XX_GPIO_HIGH);
+			spin_unlock_irqrestore(&gpio_lock, flags);
+
+			ixp4xxgpioled_devices[gpio_pin].flags =
+				pdev->resource[i].flags & IORESOURCE_BITS;
+
+			ixp4xxgpioled_devices[gpio_pin].ancestor.name =
+				pdev->resource[i].name;
+
+			/* This is how a board manufacturer makes the LED
+			 * come on on reset - the GPIO line will be high, so
+			 * make the LED light when the line is low...
+			 */
+			if (ixp4xxgpioled_devices[gpio_pin].flags != IXP4XX_GPIO_LOW)
+				ixp4xxgpioled_devices[gpio_pin].ancestor.brightness = 100;
+			else
+				ixp4xxgpioled_devices[gpio_pin].ancestor.brightness = 0;
+
+			ixp4xxgpioled_devices[gpio_pin].ancestor.flags = 0;
+
+			ixp4xxgpioled_devices[gpio_pin].ancestor.brightness_set =
+				ixp4xxgpioled_brightness_set;
+
+			ixp4xxgpioled_devices[gpio_pin].ancestor.default_trigger = 0;
+		}
+
+		rc = led_classdev_register(&pdev->dev,
+				&ixp4xxgpioled_devices[gpio_pin].ancestor);
+		if (rc < 0) {
+			ixp4xxgpioled_devices[gpio_pin].ancestor.name = 0;
+			ixp4xxgpioled_remove(pdev);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static struct platform_driver ixp4xxgpioled_driver = {
+	.probe   = ixp4xxgpioled_probe,
+	.remove  = ixp4xxgpioled_remove,
+#ifdef CONFIG_PM
+	.suspend = ixp4xxgpioled_suspend,
+	.resume  = ixp4xxgpioled_resume,
+#endif
+	.driver  = {
+		.name = "IXP4XX-GPIO-LED",
+	},
+};
+
+static int __init ixp4xxgpioled_init(void)
+{
+	return platform_driver_register(&ixp4xxgpioled_driver);
+}
+
+static void __exit ixp4xxgpioled_exit(void)
+{
+	platform_driver_unregister(&ixp4xxgpioled_driver);
+}
+
+module_init(ixp4xxgpioled_init);
+module_exit(ixp4xxgpioled_exit);
+
+MODULE_AUTHOR("John Bowler <jbowler@acm.org>");
+MODULE_DESCRIPTION("IXP4XX GPIO LED driver");
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
new file mode 100644
index 0000000..749a86c
--- /dev/null
+++ b/drivers/leds/leds-locomo.c
@@ -0,0 +1,95 @@
+/*
+ * linux/drivers/leds/locomo.c
+ *
+ * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
+ *
+ * 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/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/leds.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/locomo.h>
+
+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);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (value)
+		locomo_writel(LOCOMO_LPT_TOFH, locomo_dev->mapbase + offset);
+	else
+		locomo_writel(LOCOMO_LPT_TOFL, locomo_dev->mapbase + offset);
+	local_irq_restore(flags);
+}
+
+static void locomoled_brightness_set0(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	locomoled_brightness_set(led_cdev, value, LOCOMO_LPT0);
+}
+
+static void locomoled_brightness_set1(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	locomoled_brightness_set(led_cdev, value, LOCOMO_LPT1);
+}
+
+static struct led_classdev locomo_led0 = {
+	.name			= "locomo:amber",
+	.brightness_set		= locomoled_brightness_set0,
+};
+
+static struct led_classdev locomo_led1 = {
+	.name			= "locomo:green",
+	.brightness_set		= locomoled_brightness_set1,
+};
+
+static int locomoled_probe(struct locomo_dev *ldev)
+{
+	int ret;
+
+	ret = led_classdev_register(&ldev->dev, &locomo_led0);
+	if (ret < 0)
+		return ret;
+
+	ret = led_classdev_register(&ldev->dev, &locomo_led1);
+	if (ret < 0)
+		led_classdev_unregister(&locomo_led0);
+
+	return ret;
+}
+
+static int locomoled_remove(struct locomo_dev *dev)
+{
+	led_classdev_unregister(&locomo_led0);
+	led_classdev_unregister(&locomo_led1);
+	return 0;
+}
+
+static struct locomo_driver locomoled_driver = {
+	.drv = {
+		.name = "locomoled"
+	},
+	.devid	= LOCOMO_DEVID_LED,
+	.probe	= locomoled_probe,
+	.remove	= locomoled_remove,
+};
+
+static int __init locomoled_init(void)
+{
+	return locomo_driver_register(&locomoled_driver);
+}
+module_init(locomoled_init);
+
+MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
+MODULE_DESCRIPTION("Locomo LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-spitz.c b/drivers/leds/leds-spitz.c
new file mode 100644
index 0000000..65bbef4
--- /dev/null
+++ b/drivers/leds/leds-spitz.c
@@ -0,0 +1,125 @@
+/*
+ * LED Triggers Core
+ *
+ * Copyright 2005-2006 Openedhand Ltd.
+ *
+ * Author: 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
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <asm/hardware/scoop.h>
+#include <asm/mach-types.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/spitz.h>
+
+static void spitzled_amber_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+	if (value)
+		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
+	else
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
+}
+
+static void spitzled_green_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+	if (value)
+		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
+	else
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
+}
+
+static struct led_classdev spitz_amber_led = {
+	.name			= "spitz:amber",
+	.default_trigger	= "sharpsl-charge",
+	.brightness_set		= spitzled_amber_set,
+};
+
+static struct led_classdev spitz_green_led = {
+	.name			= "spitz:green",
+	.default_trigger	= "ide-disk",
+	.brightness_set		= spitzled_green_set,
+};
+
+#ifdef CONFIG_PM
+static int spitzled_suspend(struct platform_device *dev, pm_message_t state)
+{
+#ifdef CONFIG_LEDS_TRIGGERS
+	if (spitz_amber_led.trigger && strcmp(spitz_amber_led.trigger->name, "sharpsl-charge"))
+#endif
+		led_classdev_suspend(&spitz_amber_led);
+	led_classdev_suspend(&spitz_green_led);
+	return 0;
+}
+
+static int spitzled_resume(struct platform_device *dev)
+{
+	led_classdev_resume(&spitz_amber_led);
+	led_classdev_resume(&spitz_green_led);
+	return 0;
+}
+#endif
+
+static int spitzled_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	if (machine_is_akita())
+		spitz_green_led.default_trigger = "nand-disk";
+
+	ret = led_classdev_register(&pdev->dev, &spitz_amber_led);
+	if (ret < 0)
+		return ret;
+
+	ret = led_classdev_register(&pdev->dev, &spitz_green_led);
+	if (ret < 0)
+		led_classdev_unregister(&spitz_amber_led);
+
+	return ret;
+}
+
+static int spitzled_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&spitz_amber_led);
+	led_classdev_unregister(&spitz_green_led);
+
+	return 0;
+}
+
+static struct platform_driver spitzled_driver = {
+	.probe		= spitzled_probe,
+	.remove		= spitzled_remove,
+#ifdef CONFIG_PM
+	.suspend	= spitzled_suspend,
+	.resume		= spitzled_resume,
+#endif
+	.driver		= {
+		.name		= "spitz-led",
+	},
+};
+
+static int __init spitzled_init(void)
+{
+	return platform_driver_register(&spitzled_driver);
+}
+
+static void __exit spitzled_exit(void)
+{
+ 	platform_driver_unregister(&spitzled_driver);
+}
+
+module_init(spitzled_init);
+module_exit(spitzled_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
+MODULE_DESCRIPTION("Spitz LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-tosa.c b/drivers/leds/leds-tosa.c
new file mode 100644
index 0000000..c9e8cc1
--- /dev/null
+++ b/drivers/leds/leds-tosa.c
@@ -0,0 +1,131 @@
+/*
+ * LED Triggers Core
+ *
+ * Copyright 2005 Dirk Opfer
+ *
+ * Author: Dirk Opfer <Dirk@Opfer-Online.de>
+ *	based on spitz.c
+ *
+ * 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/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <asm/hardware/scoop.h>
+#include <asm/mach-types.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/tosa.h>
+
+static void tosaled_amber_set(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	if (value)
+		set_scoop_gpio(&tosascoop_jc_device.dev,
+				TOSA_SCOOP_JC_CHRG_ERR_LED);
+	else
+		reset_scoop_gpio(&tosascoop_jc_device.dev,
+				TOSA_SCOOP_JC_CHRG_ERR_LED);
+}
+
+static void tosaled_green_set(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	if (value)
+		set_scoop_gpio(&tosascoop_jc_device.dev,
+				TOSA_SCOOP_JC_NOTE_LED);
+	else
+		reset_scoop_gpio(&tosascoop_jc_device.dev,
+				TOSA_SCOOP_JC_NOTE_LED);
+}
+
+static struct led_classdev tosa_amber_led = {
+	.name			= "tosa:amber",
+	.default_trigger	= "sharpsl-charge",
+	.brightness_set		= tosaled_amber_set,
+};
+
+static struct led_classdev tosa_green_led = {
+	.name			= "tosa:green",
+	.default_trigger	= "nand-disk",
+	.brightness_set		= tosaled_green_set,
+};
+
+#ifdef CONFIG_PM
+static int tosaled_suspend(struct platform_device *dev, pm_message_t state)
+{
+#ifdef CONFIG_LEDS_TRIGGERS
+	if (tosa_amber_led.trigger && strcmp(tosa_amber_led.trigger->name,
+						"sharpsl-charge"))
+#endif
+		led_classdev_suspend(&tosa_amber_led);
+	led_classdev_suspend(&tosa_green_led);
+	return 0;
+}
+
+static int tosaled_resume(struct platform_device *dev)
+{
+	led_classdev_resume(&tosa_amber_led);
+	led_classdev_resume(&tosa_green_led);
+	return 0;
+}
+#else
+#define tosaled_suspend NULL
+#define tosaled_resume NULL
+#endif
+
+static int tosaled_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = led_classdev_register(&pdev->dev, &tosa_amber_led);
+	if (ret < 0)
+		return ret;
+
+	ret = led_classdev_register(&pdev->dev, &tosa_green_led);
+	if (ret < 0)
+		led_classdev_unregister(&tosa_amber_led);
+
+	return ret;
+}
+
+static int tosaled_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&tosa_amber_led);
+	led_classdev_unregister(&tosa_green_led);
+
+	return 0;
+}
+
+static struct platform_driver tosaled_driver = {
+	.probe		= tosaled_probe,
+	.remove		= tosaled_remove,
+	.suspend	= tosaled_suspend,
+	.resume		= tosaled_resume,
+	.driver		= {
+		.name		= "tosa-led",
+	},
+};
+
+static int __init tosaled_init(void)
+{
+	return platform_driver_register(&tosaled_driver);
+}
+
+static void __exit tosaled_exit(void)
+{
+ 	platform_driver_unregister(&tosaled_driver);
+}
+
+module_init(tosaled_init);
+module_exit(tosaled_exit);
+
+MODULE_AUTHOR("Dirk Opfer <Dirk@Opfer-Online.de>");
+MODULE_DESCRIPTION("Tosa LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
new file mode 100644
index 0000000..a715c4e
--- /dev/null
+++ b/drivers/leds/leds.h
@@ -0,0 +1,44 @@
+/*
+ * LED Core
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: 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
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef __LEDS_H_INCLUDED
+#define __LEDS_H_INCLUDED
+
+#include <linux/leds.h>
+
+static inline void led_set_brightness(struct led_classdev *led_cdev,
+					enum led_brightness value)
+{
+	if (value > LED_FULL)
+		value = LED_FULL;
+	led_cdev->brightness = value;
+	if (!(led_cdev->flags & LED_SUSPENDED))
+		led_cdev->brightness_set(led_cdev, value);
+}
+
+extern rwlock_t leds_list_lock;
+extern struct list_head leds_list;
+
+#ifdef CONFIG_LEDS_TRIGGERS
+void led_trigger_set_default(struct led_classdev *led_cdev);
+void led_trigger_set(struct led_classdev *led_cdev,
+			struct led_trigger *trigger);
+#else
+#define led_trigger_set_default(x) do {} while(0)
+#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);
+
+#endif	/* __LEDS_H_INCLUDED */
diff --git a/drivers/leds/ledtrig-ide-disk.c b/drivers/leds/ledtrig-ide-disk.c
new file mode 100644
index 0000000..fa65188
--- /dev/null
+++ b/drivers/leds/ledtrig-ide-disk.c
@@ -0,0 +1,62 @@
+/*
+ * LED IDE-Disk Activity Trigger
+ *
+ * Copyright 2006 Openedhand Ltd.
+ *
+ * Author: 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
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/leds.h>
+
+static void ledtrig_ide_timerfunc(unsigned long data);
+
+DEFINE_LED_TRIGGER(ledtrig_ide);
+static DEFINE_TIMER(ledtrig_ide_timer, ledtrig_ide_timerfunc, 0, 0);
+static int ide_activity;
+static int ide_lastactivity;
+
+void ledtrig_ide_activity(void)
+{
+	ide_activity++;
+	if (!timer_pending(&ledtrig_ide_timer))
+		mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10));
+}
+EXPORT_SYMBOL(ledtrig_ide_activity);
+
+static void ledtrig_ide_timerfunc(unsigned long data)
+{
+	if (ide_lastactivity != ide_activity) {
+		ide_lastactivity = ide_activity;
+		led_trigger_event(ledtrig_ide, LED_FULL);
+	    	mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10));
+	} else {
+		led_trigger_event(ledtrig_ide, LED_OFF);
+	}
+}
+
+static int __init ledtrig_ide_init(void)
+{
+	led_trigger_register_simple("ide-disk", &ledtrig_ide);
+	return 0;
+}
+
+static void __exit ledtrig_ide_exit(void)
+{
+	led_trigger_unregister_simple(ledtrig_ide);
+}
+
+module_init(ledtrig_ide_init);
+module_exit(ledtrig_ide_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
+MODULE_DESCRIPTION("LED IDE Disk Activity Trigger");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
new file mode 100644
index 0000000..f484b5d6
--- /dev/null
+++ b/drivers/leds/ledtrig-timer.c
@@ -0,0 +1,170 @@
+/*
+ * LED Kernel Timer Trigger
+ *
+ * Copyright 2005-2006 Openedhand Ltd.
+ *
+ * Author: 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
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+#include <linux/timer.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+struct timer_trig_data {
+	unsigned long delay_on;		/* milliseconds on */
+	unsigned long delay_off;	/* milliseconds off */
+	struct timer_list timer;
+};
+
+static void led_timer_function(unsigned long data)
+{
+	struct led_classdev *led_cdev = (struct led_classdev *) data;
+	struct timer_trig_data *timer_data = led_cdev->trigger_data;
+	unsigned long brightness = LED_OFF;
+	unsigned long delay = timer_data->delay_off;
+
+	if (!timer_data->delay_on || !timer_data->delay_off) {
+		led_set_brightness(led_cdev, LED_OFF);
+		return;
+	}
+
+	if (!led_cdev->brightness) {
+		brightness = LED_FULL;
+		delay = timer_data->delay_on;
+	}
+
+	led_set_brightness(led_cdev, brightness);
+
+	mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay));
+}
+
+static ssize_t led_delay_on_show(struct class_device *dev, char *buf)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct timer_trig_data *timer_data = led_cdev->trigger_data;
+
+	sprintf(buf, "%lu\n", timer_data->delay_on);
+
+	return strlen(buf) + 1;
+}
+
+static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
+				size_t size)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct timer_trig_data *timer_data = led_cdev->trigger_data;
+	int ret = -EINVAL;
+	char *after;
+	unsigned long state = simple_strtoul(buf, &after, 10);
+
+	if (after - buf > 0) {
+		timer_data->delay_on = state;
+		mod_timer(&timer_data->timer, jiffies + 1);
+		ret = after - buf;
+	}
+
+	return ret;
+}
+
+static ssize_t led_delay_off_show(struct class_device *dev, char *buf)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct timer_trig_data *timer_data = led_cdev->trigger_data;
+
+	sprintf(buf, "%lu\n", timer_data->delay_off);
+
+	return strlen(buf) + 1;
+}
+
+static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
+				size_t size)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct timer_trig_data *timer_data = led_cdev->trigger_data;
+	int ret = -EINVAL;
+	char *after;
+	unsigned long state = simple_strtoul(buf, &after, 10);
+
+	if (after - buf > 0) {
+		timer_data->delay_off = state;
+		mod_timer(&timer_data->timer, jiffies + 1);
+		ret = after - buf;
+	}
+
+	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 void timer_trig_activate(struct led_classdev *led_cdev)
+{
+	struct timer_trig_data *timer_data;
+
+	timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL);
+	if (!timer_data)
+		return;
+
+	led_cdev->trigger_data = timer_data;
+
+	init_timer(&timer_data->timer);
+	timer_data->timer.function = led_timer_function;
+	timer_data->timer.data = (unsigned long) led_cdev;
+
+	class_device_create_file(led_cdev->class_dev,
+				&class_device_attr_delay_on);
+	class_device_create_file(led_cdev->class_dev,
+				&class_device_attr_delay_off);
+}
+
+static void timer_trig_deactivate(struct led_classdev *led_cdev)
+{
+	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);
+		del_timer_sync(&timer_data->timer);
+		kfree(timer_data);
+	}
+}
+
+static struct led_trigger timer_led_trigger = {
+	.name     = "timer",
+	.activate = timer_trig_activate,
+	.deactivate = timer_trig_deactivate,
+};
+
+static int __init timer_trig_init(void)
+{
+	return led_trigger_register(&timer_led_trigger);
+}
+
+static void __exit timer_trig_exit(void)
+{
+	led_trigger_unregister(&timer_led_trigger);
+}
+
+module_init(timer_trig_init);
+module_exit(timer_trig_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
+MODULE_DESCRIPTION("Timer LED trigger");
+MODULE_LICENSE("GPL");
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index d2ead17..259fd89 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -42,6 +42,7 @@
 #include <asm/semaphore.h>
 #ifdef CONFIG_PPC
 #include <asm/prom.h>
+#include <asm/machdep.h>
 #endif
 
 
@@ -80,7 +81,7 @@
 static struct class *adb_dev_class;
 
 struct adb_driver *adb_controller;
-struct notifier_block *adb_client_list = NULL;
+BLOCKING_NOTIFIER_HEAD(adb_client_list);
 static int adb_got_sleep;
 static int adb_inited;
 static pid_t adb_probe_task_pid;
@@ -294,7 +295,7 @@
 	int i;
 
 #ifdef CONFIG_PPC32
-	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+	if (!machine_is(chrp) && !machine_is(powermac))
 		return 0;
 #endif
 #ifdef CONFIG_MAC
@@ -354,7 +355,8 @@
 		/* Stop autopoll */
 		if (adb_controller->autopoll)
 			adb_controller->autopoll(0);
-		ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
+		ret = blocking_notifier_call_chain(&adb_client_list,
+				ADB_MSG_POWERDOWN, NULL);
 		if (ret & NOTIFY_STOP_MASK) {
 			up(&adb_probe_mutex);
 			return PBOOK_SLEEP_REFUSE;
@@ -391,7 +393,8 @@
 	if (adb_controller->autopoll)
 		adb_controller->autopoll(0);
 
-	nret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL);
+	nret = blocking_notifier_call_chain(&adb_client_list,
+			ADB_MSG_PRE_RESET, NULL);
 	if (nret & NOTIFY_STOP_MASK) {
 		if (adb_controller->autopoll)
 			adb_controller->autopoll(autopoll_devs);
@@ -426,7 +429,8 @@
 	}
 	up(&adb_handler_sem);
 
-	nret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL);
+	nret = blocking_notifier_call_chain(&adb_client_list,
+			ADB_MSG_POST_RESET, NULL);
 	if (nret & NOTIFY_STOP_MASK)
 		return -EBUSY;
 	
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index c0b46bc..394334e 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -1206,15 +1206,16 @@
 static int __init adbhid_init(void)
 {
 #ifndef CONFIG_MAC
-	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-	    return 0;
+	if (!machine_is(chrp) && !machine_is(powermac))
+		return 0;
 #endif
 
 	led_request.complete = 1;
 
 	adbhid_probe();
 
-	notifier_chain_register(&adb_client_list, &adbhid_adb_notifier);
+	blocking_notifier_chain_register(&adb_client_list,
+			&adbhid_adb_notifier);
 
 	return 0;
 }
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 8dbf285..53c1c79 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -839,8 +839,8 @@
 		media_bays[i].cd_index		= -1;
 #endif
 	}
-	if (_machine != _MACH_Pmac)
-		return -ENODEV;
+	if (!machine_is(powermac))
+		return 0;
 
 	macio_register_driver(&media_bay_driver);	
 
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index 4eb05d7..f4516ca 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -35,6 +35,7 @@
 #include <linux/delay.h>
 #include <linux/sysdev.h>
 #include <linux/poll.h>
+#include <linux/mutex.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -92,7 +93,7 @@
  * for now, just hard code that
  */
 static struct smu_device	*smu;
-static DECLARE_MUTEX(smu_part_access);
+static DEFINE_MUTEX(smu_part_access);
 
 static void smu_i2c_retry(unsigned long data);
 
@@ -976,11 +977,11 @@
 
 	if (interruptible) {
 		int rc;
-		rc = down_interruptible(&smu_part_access);
+		rc = mutex_lock_interruptible(&smu_part_access);
 		if (rc)
 			return ERR_PTR(rc);
 	} else
-		down(&smu_part_access);
+		mutex_lock(&smu_part_access);
 
 	part = (struct smu_sdbp_header *)get_property(smu->of_node,
 						      pname, size);
@@ -990,7 +991,7 @@
 		if (part != NULL && size)
 			*size = part->len << 2;
 	}
-	up(&smu_part_access);
+	mutex_unlock(&smu_part_access);
 	return part;
 }
 
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 4f5f3ab..0b5ff55 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -187,7 +187,7 @@
 
 int __fake_sleep;
 int asleep;
-struct notifier_block *sleep_notifier_list;
+BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
 
 #ifdef CONFIG_ADB
 static int adb_dev_map = 0;
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
index f08e52f..35b7032 100644
--- a/drivers/macintosh/via-pmu68k.c
+++ b/drivers/macintosh/via-pmu68k.c
@@ -102,7 +102,7 @@
 static int pmu_fully_inited = 0;
 
 int asleep;
-struct notifier_block *sleep_notifier_list;
+BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
 
 static int pmu_probe(void);
 static int pmu_init(void);
@@ -913,7 +913,8 @@
 	struct adb_request sleep_req;
 
 	/* Notify device drivers */
-	ret = notifier_call_chain(&sleep_notifier_list, PBOOK_SLEEP, NULL);
+	ret = blocking_notifier_call_chain(&sleep_notifier_list,
+			PBOOK_SLEEP, NULL);
 	if (ret & NOTIFY_STOP_MASK)
 		return -EBUSY;
 
@@ -984,7 +985,7 @@
 			enable_irq(i);
 
 	/* Notify drivers */
-	notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL);
+	blocking_notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL);
 
 	/* reenable ADB autopoll */
 	pmu_adb_autopoll(adb_dev_map);
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index 6c0ba04..ab3faa7 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -52,7 +52,7 @@
 static LIST_HEAD(wf_controls);
 static LIST_HEAD(wf_sensors);
 static DEFINE_MUTEX(wf_lock);
-static struct notifier_block *wf_client_list;
+static BLOCKING_NOTIFIER_HEAD(wf_client_list);
 static int wf_client_count;
 static unsigned int wf_overtemp;
 static unsigned int wf_overtemp_counter;
@@ -68,7 +68,7 @@
 
 static inline void wf_notify(int event, void *param)
 {
-	notifier_call_chain(&wf_client_list, event, param);
+	blocking_notifier_call_chain(&wf_client_list, event, param);
 }
 
 int wf_critical_overtemp(void)
@@ -398,7 +398,7 @@
 	struct wf_sensor *sr;
 
 	mutex_lock(&wf_lock);
-	rc = notifier_chain_register(&wf_client_list, nb);
+	rc = blocking_notifier_chain_register(&wf_client_list, nb);
 	if (rc != 0)
 		goto bail;
 	wf_client_count++;
@@ -417,7 +417,7 @@
 int wf_unregister_client(struct notifier_block *nb)
 {
 	mutex_lock(&wf_lock);
-	notifier_chain_unregister(&wf_client_list, nb);
+	blocking_notifier_chain_unregister(&wf_client_list, nb);
 	wf_client_count++;
 	if (wf_client_count == 0)
 		wf_stop_thread();
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index ac43f98..fd2aae1 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -127,6 +127,32 @@
 
 	  If unsure, say Y.
 
+config MD_RAID5_RESHAPE
+	bool "Support adding drives to a raid-5 array (experimental)"
+	depends on MD_RAID5 && EXPERIMENTAL
+	---help---
+	  A RAID-5 set can be expanded by adding extra drives. This
+	  requires "restriping" the array which means (almost) every
+	  block must be written to a different place.
+
+          This option allows such restriping to be done while the array
+	  is online.  However it is still EXPERIMENTAL code.  It should
+	  work, but please be sure that you have backups.
+
+	  You will need a version of mdadm newer than 2.3.1.   During the
+	  early stage of reshape there is a critical section where live data
+	  is being over-written.  A crash during this time needs extra care
+	  for recovery.  The newer mdadm takes a copy of the data in the
+	  critical section and will restore it, if necessary, after a crash.
+
+	  The mdadm usage is e.g.
+	       mdadm --grow /dev/md1 --raid-disks=6
+	  to grow '/dev/md1' to having 6 disks.
+
+	  Note: The array can only be expanded, not contracted.
+	  There should be enough spares already present to make the new
+	  array workable.
+
 config MD_RAID6
 	tristate "RAID-6 mode"
 	depends on BLK_DEV_MD
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index e1c18aa..f8ffaee 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -89,16 +89,6 @@
 }
 
 #define WRITE_POOL_SIZE 256
-/* mempool for queueing pending writes on the bitmap file */
-static void *write_pool_alloc(gfp_t gfp_flags, void *data)
-{
-	return kmalloc(sizeof(struct page_list), gfp_flags);
-}
-
-static void write_pool_free(void *ptr, void *data)
-{
-	kfree(ptr);
-}
 
 /*
  * just a placeholder - calls kmalloc for bitmap pages
@@ -1564,8 +1554,8 @@
 	spin_lock_init(&bitmap->write_lock);
 	INIT_LIST_HEAD(&bitmap->complete_pages);
 	init_waitqueue_head(&bitmap->write_wait);
-	bitmap->write_pool = mempool_create(WRITE_POOL_SIZE, write_pool_alloc,
-				write_pool_free, NULL);
+	bitmap->write_pool = mempool_create_kmalloc_pool(WRITE_POOL_SIZE,
+						sizeof(struct page_list));
 	err = -ENOMEM;
 	if (!bitmap->write_pool)
 		goto error;
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index e7a650f..61a590b 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -94,20 +94,6 @@
 static kmem_cache_t *_crypt_io_pool;
 
 /*
- * Mempool alloc and free functions for the page
- */
-static void *mempool_alloc_page(gfp_t gfp_mask, void *data)
-{
-	return alloc_page(gfp_mask);
-}
-
-static void mempool_free_page(void *page, void *data)
-{
-	__free_page(page);
-}
-
-
-/*
  * Different IV generation algorithms:
  *
  * plain: the initial vector is the 32-bit low-endian version of the sector
@@ -532,6 +518,7 @@
 	char *ivopts;
 	unsigned int crypto_flags;
 	unsigned int key_size;
+	unsigned long long tmpll;
 
 	if (argc != 5) {
 		ti->error = PFX "Not enough arguments";
@@ -630,15 +617,13 @@
 		}
 	}
 
-	cc->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
-				     mempool_free_slab, _crypt_io_pool);
+	cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool);
 	if (!cc->io_pool) {
 		ti->error = PFX "Cannot allocate crypt io mempool";
 		goto bad3;
 	}
 
-	cc->page_pool = mempool_create(MIN_POOL_PAGES, mempool_alloc_page,
-				       mempool_free_page, NULL);
+	cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
 	if (!cc->page_pool) {
 		ti->error = PFX "Cannot allocate page mempool";
 		goto bad4;
@@ -649,15 +634,17 @@
 		goto bad5;
 	}
 
-	if (sscanf(argv[2], SECTOR_FORMAT, &cc->iv_offset) != 1) {
+	if (sscanf(argv[2], "%llu", &tmpll) != 1) {
 		ti->error = PFX "Invalid iv_offset sector";
 		goto bad5;
 	}
+	cc->iv_offset = tmpll;
 
-	if (sscanf(argv[4], SECTOR_FORMAT, &cc->start) != 1) {
+	if (sscanf(argv[4], "%llu", &tmpll) != 1) {
 		ti->error = PFX "Invalid device sector";
 		goto bad5;
 	}
+	cc->start = tmpll;
 
 	if (dm_get_device(ti, argv[3], cc->start, ti->len,
 	                  dm_table_get_mode(ti->table), &cc->dev)) {
@@ -901,8 +888,8 @@
 			result[sz++] = '-';
 		}
 
-		DMEMIT(" " SECTOR_FORMAT " %s " SECTOR_FORMAT,
-		       cc->iv_offset, cc->dev->name, cc->start);
+		DMEMIT(" %llu %s %llu", (unsigned long long)cc->iv_offset,
+				cc->dev->name, (unsigned long long)cc->start);
 		break;
 	}
 	return 0;
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 4809b20..da663d2 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -32,16 +32,6 @@
 static unsigned _num_ios;
 static mempool_t *_io_pool;
 
-static void *alloc_io(gfp_t gfp_mask, void *pool_data)
-{
-	return kmalloc(sizeof(struct io), gfp_mask);
-}
-
-static void free_io(void *element, void *pool_data)
-{
-	kfree(element);
-}
-
 static unsigned int pages_to_ios(unsigned int pages)
 {
 	return 4 * pages;	/* too many ? */
@@ -65,7 +55,8 @@
 
 	} else {
 		/* create new pool */
-		_io_pool = mempool_create(new_ios, alloc_io, free_io, NULL);
+		_io_pool = mempool_create_kmalloc_pool(new_ios,
+						       sizeof(struct io));
 		if (!_io_pool)
 			return -ENOMEM;
 
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 442e2be..8edd643 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/dm-ioctl.h>
+#include <linux/hdreg.h>
 
 #include <asm/uaccess.h>
 
@@ -244,9 +245,9 @@
 		dm_table_put(table);
 	}
 
-	dm_put(hc->md);
 	if (hc->new_map)
 		dm_table_put(hc->new_map);
+	dm_put(hc->md);
 	free_cell(hc);
 }
 
@@ -600,12 +601,22 @@
  */
 static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
 {
+	struct mapped_device *md;
+	void *mdptr = NULL;
+
 	if (*param->uuid)
 		return __get_uuid_cell(param->uuid);
-	else if (*param->name)
+
+	if (*param->name)
 		return __get_name_cell(param->name);
-	else
-		return dm_get_mdptr(huge_decode_dev(param->dev));
+
+	md = dm_get_md(huge_decode_dev(param->dev));
+	if (md) {
+		mdptr = dm_get_mdptr(md);
+		dm_put(md);
+	}
+
+	return mdptr;
 }
 
 static struct mapped_device *find_device(struct dm_ioctl *param)
@@ -690,6 +701,54 @@
 	return dm_hash_rename(param->name, new_name);
 }
 
+static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
+{
+	int r = -EINVAL, x;
+	struct mapped_device *md;
+	struct hd_geometry geometry;
+	unsigned long indata[4];
+	char *geostr = (char *) param + param->data_start;
+
+	md = find_device(param);
+	if (!md)
+		return -ENXIO;
+
+	if (geostr < (char *) (param + 1) ||
+	    invalid_str(geostr, (void *) param + param_size)) {
+		DMWARN("Invalid geometry supplied.");
+		goto out;
+	}
+
+	x = sscanf(geostr, "%lu %lu %lu %lu", indata,
+		   indata + 1, indata + 2, indata + 3);
+
+	if (x != 4) {
+		DMWARN("Unable to interpret geometry settings.");
+		goto out;
+	}
+
+	if (indata[0] > 65535 || indata[1] > 255 ||
+	    indata[2] > 255 || indata[3] > ULONG_MAX) {
+		DMWARN("Geometry exceeds range limits.");
+		goto out;
+	}
+
+	geometry.cylinders = indata[0];
+	geometry.heads = indata[1];
+	geometry.sectors = indata[2];
+	geometry.start = indata[3];
+
+	r = dm_set_geometry(md, &geometry);
+	if (!r)
+		r = __dev_status(md, param);
+
+	param->data_size = 0;
+
+out:
+	dm_put(md);
+	return r;
+}
+
 static int do_suspend(struct dm_ioctl *param)
 {
 	int r = 0;
@@ -975,33 +1034,43 @@
 	int r;
 	struct hash_cell *hc;
 	struct dm_table *t;
+	struct mapped_device *md;
 
-	r = dm_table_create(&t, get_mode(param), param->target_count);
+	md = find_device(param);
+	if (!md)
+		return -ENXIO;
+
+	r = dm_table_create(&t, get_mode(param), param->target_count, md);
 	if (r)
-		return r;
+		goto out;
 
 	r = populate_table(t, param, param_size);
 	if (r) {
 		dm_table_put(t);
-		return r;
+		goto out;
 	}
 
 	down_write(&_hash_lock);
-	hc = __find_device_hash_cell(param);
-	if (!hc) {
-		DMWARN("device doesn't appear to be in the dev hash table.");
-		up_write(&_hash_lock);
+	hc = dm_get_mdptr(md);
+	if (!hc || hc->md != md) {
+		DMWARN("device has been removed from the dev hash table.");
 		dm_table_put(t);
-		return -ENXIO;
+		up_write(&_hash_lock);
+		r = -ENXIO;
+		goto out;
 	}
 
 	if (hc->new_map)
 		dm_table_put(hc->new_map);
 	hc->new_map = t;
-	param->flags |= DM_INACTIVE_PRESENT_FLAG;
-
-	r = __dev_status(hc->md, param);
 	up_write(&_hash_lock);
+
+	param->flags |= DM_INACTIVE_PRESENT_FLAG;
+	r = __dev_status(md, param);
+
+out:
+	dm_put(md);
+
 	return r;
 }
 
@@ -1214,7 +1283,8 @@
 
 		{DM_LIST_VERSIONS_CMD, list_versions},
 
-		{DM_TARGET_MSG_CMD, target_message}
+		{DM_TARGET_MSG_CMD, target_message},
+		{DM_DEV_SET_GEOMETRY_CMD, dev_set_geometry}
 	};
 
 	return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn;
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 6a2cd5d..daf586c 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -26,6 +26,7 @@
 static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
 	struct linear_c *lc;
+	unsigned long long tmp;
 
 	if (argc != 2) {
 		ti->error = "dm-linear: Invalid argument count";
@@ -38,10 +39,11 @@
 		return -ENOMEM;
 	}
 
-	if (sscanf(argv[1], SECTOR_FORMAT, &lc->start) != 1) {
+	if (sscanf(argv[1], "%llu", &tmp) != 1) {
 		ti->error = "dm-linear: Invalid device sector";
 		goto bad;
 	}
+	lc->start = tmp;
 
 	if (dm_get_device(ti, argv[0], lc->start, ti->len,
 			  dm_table_get_mode(ti->table), &lc->dev)) {
@@ -87,8 +89,8 @@
 		break;
 
 	case STATUSTYPE_TABLE:
-		snprintf(result, maxlen, "%s " SECTOR_FORMAT, lc->dev->name,
-			 lc->start);
+		snprintf(result, maxlen, "%s %llu", lc->dev->name,
+				(unsigned long long)lc->start);
 		break;
 	}
 	return 0;
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index f72a82f..1816f30 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -179,8 +179,7 @@
 		m->queue_io = 1;
 		INIT_WORK(&m->process_queued_ios, process_queued_ios, m);
 		INIT_WORK(&m->trigger_event, trigger_event, m);
-		m->mpio_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
-					      mempool_free_slab, _mpio_cache);
+		m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache);
 		if (!m->mpio_pool) {
 			kfree(m);
 			return NULL;
diff --git a/drivers/md/dm-path-selector.c b/drivers/md/dm-path-selector.c
index a28c1c2..f10a0c8 100644
--- a/drivers/md/dm-path-selector.c
+++ b/drivers/md/dm-path-selector.c
@@ -86,8 +86,7 @@
 	if (--psi->use == 0)
 		module_put(psi->pst.module);
 
-	if (psi->use < 0)
-		BUG();
+	BUG_ON(psi->use < 0);
 
 out:
 	up_read(&_ps_lock);
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 6cfa8d4..d12cf3e 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -122,16 +122,6 @@
 /* FIXME move this */
 static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw);
 
-static void *region_alloc(gfp_t gfp_mask, void *pool_data)
-{
-	return kmalloc(sizeof(struct region), gfp_mask);
-}
-
-static void region_free(void *element, void *pool_data)
-{
-	kfree(element);
-}
-
 #define MIN_REGIONS 64
 #define MAX_RECOVERY 1
 static int rh_init(struct region_hash *rh, struct mirror_set *ms,
@@ -173,8 +163,8 @@
 	INIT_LIST_HEAD(&rh->quiesced_regions);
 	INIT_LIST_HEAD(&rh->recovered_regions);
 
-	rh->region_pool = mempool_create(MIN_REGIONS, region_alloc,
-					 region_free, NULL);
+	rh->region_pool = mempool_create_kmalloc_pool(MIN_REGIONS,
+						      sizeof(struct region));
 	if (!rh->region_pool) {
 		vfree(rh->buckets);
 		rh->buckets = NULL;
@@ -412,9 +402,21 @@
 
 	spin_lock_irqsave(&rh->region_lock, flags);
 	if (atomic_dec_and_test(&reg->pending)) {
+		/*
+		 * There is no pending I/O for this region.
+		 * We can move the region to corresponding list for next action.
+		 * At this point, the region is not yet connected to any list.
+		 *
+		 * If the state is RH_NOSYNC, the region should be kept off
+		 * from clean list.
+		 * The hash entry for RH_NOSYNC will remain in memory
+		 * until the region is recovered or the map is reloaded.
+		 */
+
+		/* do nothing for RH_NOSYNC */
 		if (reg->state == RH_RECOVERING) {
 			list_add_tail(&reg->list, &rh->quiesced_regions);
-		} else {
+		} else if (reg->state == RH_DIRTY) {
 			reg->state = RH_CLEAN;
 			list_add(&reg->list, &rh->clean_regions);
 		}
@@ -932,9 +934,9 @@
 static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
 		      unsigned int mirror, char **argv)
 {
-	sector_t offset;
+	unsigned long long offset;
 
-	if (sscanf(argv[1], SECTOR_FORMAT, &offset) != 1) {
+	if (sscanf(argv[1], "%llu", &offset) != 1) {
 		ti->error = "dm-mirror: Invalid offset";
 		return -EINVAL;
 	}
@@ -1201,16 +1203,17 @@
 		for (m = 0; m < ms->nr_mirrors; m++)
 			DMEMIT("%s ", ms->mirror[m].dev->name);
 
-		DMEMIT(SECTOR_FORMAT "/" SECTOR_FORMAT,
-		       ms->rh.log->type->get_sync_count(ms->rh.log),
-		       ms->nr_regions);
+		DMEMIT("%llu/%llu",
+			(unsigned long long)ms->rh.log->type->
+				get_sync_count(ms->rh.log),
+			(unsigned long long)ms->nr_regions);
 		break;
 
 	case STATUSTYPE_TABLE:
 		DMEMIT("%d ", ms->nr_mirrors);
 		for (m = 0; m < ms->nr_mirrors; m++)
-			DMEMIT("%s " SECTOR_FORMAT " ",
-			       ms->mirror[m].dev->name, ms->mirror[m].offset);
+			DMEMIT("%s %llu ", ms->mirror[m].dev->name,
+				(unsigned long long)ms->mirror[m].offset);
 	}
 
 	return 0;
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index f3759dd..08312b4 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -49,11 +49,26 @@
 	struct bio_list snapshot_bios;
 
 	/*
-	 * Other pending_exceptions that are processing this
-	 * chunk.  When this list is empty, we know we can
-	 * complete the origins.
+	 * Short-term queue of pending exceptions prior to submission.
 	 */
-	struct list_head siblings;
+	struct list_head list;
+
+	/*
+	 * The primary pending_exception is the one that holds
+	 * the sibling_count and the list of origin_bios for a
+	 * group of pending_exceptions.  It is always last to get freed.
+	 * These fields get set up when writing to the origin.
+	 */
+	struct pending_exception *primary_pe;
+
+	/*
+	 * Number of pending_exceptions processing this chunk.
+	 * When this drops to zero we must complete the origin bios.
+	 * If incrementing or decrementing this, hold pe->snap->lock for
+	 * the sibling concerned and not pe->primary_pe->snap->lock unless
+	 * they are the same.
+	 */
+	atomic_t sibling_count;
 
 	/* Pointer back to snapshot context */
 	struct dm_snapshot *snap;
@@ -377,6 +392,8 @@
 		down_write(&s->lock);
 		s->valid = 0;
 		up_write(&s->lock);
+
+		dm_table_event(s->table);
 	}
 }
 
@@ -542,8 +559,12 @@
 {
 	struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
 
+	/* Prevent further origin writes from using this snapshot. */
+	/* After this returns there can be no new kcopyd jobs. */
 	unregister_snapshot(s);
 
+	kcopyd_client_destroy(s->kcopyd_client);
+
 	exit_exception_table(&s->pending, pending_cache);
 	exit_exception_table(&s->complete, exception_cache);
 
@@ -552,7 +573,7 @@
 
 	dm_put_device(ti, s->origin);
 	dm_put_device(ti, s->cow);
-	kcopyd_client_destroy(s->kcopyd_client);
+
 	kfree(s);
 }
 
@@ -586,78 +607,117 @@
 	}
 }
 
+static inline void error_snapshot_bios(struct pending_exception *pe)
+{
+	error_bios(bio_list_get(&pe->snapshot_bios));
+}
+
 static struct bio *__flush_bios(struct pending_exception *pe)
 {
-	struct pending_exception *sibling;
-
-	if (list_empty(&pe->siblings))
-		return bio_list_get(&pe->origin_bios);
-
-	sibling = list_entry(pe->siblings.next,
-			     struct pending_exception, siblings);
-
-	list_del(&pe->siblings);
-
-	/* This is fine as long as kcopyd is single-threaded. If kcopyd
-	 * becomes multi-threaded, we'll need some locking here.
+	/*
+	 * If this pe is involved in a write to the origin and
+	 * it is the last sibling to complete then release
+	 * the bios for the original write to the origin.
 	 */
-	bio_list_merge(&sibling->origin_bios, &pe->origin_bios);
+
+	if (pe->primary_pe &&
+	    atomic_dec_and_test(&pe->primary_pe->sibling_count))
+		return bio_list_get(&pe->primary_pe->origin_bios);
 
 	return NULL;
 }
 
+static void __invalidate_snapshot(struct dm_snapshot *s,
+				struct pending_exception *pe, int err)
+{
+	if (!s->valid)
+		return;
+
+	if (err == -EIO)
+		DMERR("Invalidating snapshot: Error reading/writing.");
+	else if (err == -ENOMEM)
+		DMERR("Invalidating snapshot: Unable to allocate exception.");
+
+	if (pe)
+		remove_exception(&pe->e);
+
+	if (s->store.drop_snapshot)
+		s->store.drop_snapshot(&s->store);
+
+	s->valid = 0;
+
+	dm_table_event(s->table);
+}
+
 static void pending_complete(struct pending_exception *pe, int success)
 {
 	struct exception *e;
+	struct pending_exception *primary_pe;
 	struct dm_snapshot *s = pe->snap;
 	struct bio *flush = NULL;
 
-	if (success) {
-		e = alloc_exception();
-		if (!e) {
-			DMWARN("Unable to allocate exception.");
-			down_write(&s->lock);
-			s->store.drop_snapshot(&s->store);
-			s->valid = 0;
-			flush = __flush_bios(pe);
-			up_write(&s->lock);
-
-			error_bios(bio_list_get(&pe->snapshot_bios));
-			goto out;
-		}
-		*e = pe->e;
-
-		/*
-		 * Add a proper exception, and remove the
-		 * in-flight exception from the list.
-		 */
-		down_write(&s->lock);
-		insert_exception(&s->complete, e);
-		remove_exception(&pe->e);
-		flush = __flush_bios(pe);
-
-		/* Submit any pending write bios */
-		up_write(&s->lock);
-
-		flush_bios(bio_list_get(&pe->snapshot_bios));
-	} else {
+	if (!success) {
 		/* Read/write error - snapshot is unusable */
 		down_write(&s->lock);
-		if (s->valid)
-			DMERR("Error reading/writing snapshot");
-		s->store.drop_snapshot(&s->store);
-		s->valid = 0;
-		remove_exception(&pe->e);
+		__invalidate_snapshot(s, pe, -EIO);
 		flush = __flush_bios(pe);
 		up_write(&s->lock);
 
-		error_bios(bio_list_get(&pe->snapshot_bios));
-
-		dm_table_event(s->table);
+		error_snapshot_bios(pe);
+		goto out;
 	}
 
+	e = alloc_exception();
+	if (!e) {
+		down_write(&s->lock);
+		__invalidate_snapshot(s, pe, -ENOMEM);
+		flush = __flush_bios(pe);
+		up_write(&s->lock);
+
+		error_snapshot_bios(pe);
+		goto out;
+	}
+	*e = pe->e;
+
+	/*
+	 * Add a proper exception, and remove the
+	 * in-flight exception from the list.
+	 */
+	down_write(&s->lock);
+	if (!s->valid) {
+		flush = __flush_bios(pe);
+		up_write(&s->lock);
+
+		free_exception(e);
+
+		error_snapshot_bios(pe);
+		goto out;
+	}
+
+	insert_exception(&s->complete, e);
+	remove_exception(&pe->e);
+	flush = __flush_bios(pe);
+
+	up_write(&s->lock);
+
+	/* Submit any pending write bios */
+	flush_bios(bio_list_get(&pe->snapshot_bios));
+
  out:
-	free_pending_exception(pe);
+	primary_pe = pe->primary_pe;
+
+	/*
+	 * Free the pe if it's not linked to an origin write or if
+	 * it's not itself a primary pe.
+	 */
+	if (!primary_pe || primary_pe != pe)
+		free_pending_exception(pe);
+
+	/*
+	 * Free the primary pe if nothing references it.
+	 */
+	if (primary_pe && !atomic_read(&primary_pe->sibling_count))
+		free_pending_exception(primary_pe);
 
 	if (flush)
 		flush_bios(flush);
@@ -734,38 +794,45 @@
 	if (e) {
 		/* cast the exception to a pending exception */
 		pe = container_of(e, struct pending_exception, e);
-
-	} else {
-		/*
-		 * Create a new pending exception, we don't want
-		 * to hold the lock while we do this.
-		 */
-		up_write(&s->lock);
-		pe = alloc_pending_exception();
-		down_write(&s->lock);
-
-		e = lookup_exception(&s->pending, chunk);
-		if (e) {
-			free_pending_exception(pe);
-			pe = container_of(e, struct pending_exception, e);
-		} else {
-			pe->e.old_chunk = chunk;
-			bio_list_init(&pe->origin_bios);
-			bio_list_init(&pe->snapshot_bios);
-			INIT_LIST_HEAD(&pe->siblings);
-			pe->snap = s;
-			pe->started = 0;
-
-			if (s->store.prepare_exception(&s->store, &pe->e)) {
-				free_pending_exception(pe);
-				s->valid = 0;
-				return NULL;
-			}
-
-			insert_exception(&s->pending, &pe->e);
-		}
+		goto out;
 	}
 
+	/*
+	 * Create a new pending exception, we don't want
+	 * to hold the lock while we do this.
+	 */
+	up_write(&s->lock);
+	pe = alloc_pending_exception();
+	down_write(&s->lock);
+
+	if (!s->valid) {
+		free_pending_exception(pe);
+		return NULL;
+	}
+
+	e = lookup_exception(&s->pending, chunk);
+	if (e) {
+		free_pending_exception(pe);
+		pe = container_of(e, struct pending_exception, e);
+		goto out;
+	}
+
+	pe->e.old_chunk = chunk;
+	bio_list_init(&pe->origin_bios);
+	bio_list_init(&pe->snapshot_bios);
+	pe->primary_pe = NULL;
+	atomic_set(&pe->sibling_count, 1);
+	pe->snap = s;
+	pe->started = 0;
+
+	if (s->store.prepare_exception(&s->store, &pe->e)) {
+		free_pending_exception(pe);
+		return NULL;
+	}
+
+	insert_exception(&s->pending, &pe->e);
+
+ out:
 	return pe;
 }
 
@@ -782,13 +849,15 @@
 {
 	struct exception *e;
 	struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
+	int copy_needed = 0;
 	int r = 1;
 	chunk_t chunk;
-	struct pending_exception *pe;
+	struct pending_exception *pe = NULL;
 
 	chunk = sector_to_chunk(s, bio->bi_sector);
 
 	/* Full snapshots are not usable */
+	/* To get here the table must be live so s->active is always set. */
 	if (!s->valid)
 		return -EIO;
 
@@ -806,36 +875,41 @@
 		 * to copy an exception */
 		down_write(&s->lock);
 
+		if (!s->valid) {
+			r = -EIO;
+			goto out_unlock;
+		}
+
 		/* If the block is already remapped - use that, else remap it */
 		e = lookup_exception(&s->complete, chunk);
 		if (e) {
 			remap_exception(s, e, bio);
-			up_write(&s->lock);
-
-		} else {
-			pe = __find_pending_exception(s, bio);
-
-			if (!pe) {
-				if (s->store.drop_snapshot)
-					s->store.drop_snapshot(&s->store);
-				s->valid = 0;
-				r = -EIO;
-				up_write(&s->lock);
-			} else {
-				remap_exception(s, &pe->e, bio);
-				bio_list_add(&pe->snapshot_bios, bio);
-
-				if (!pe->started) {
-					/* this is protected by snap->lock */
-					pe->started = 1;
-					up_write(&s->lock);
-					start_copy(pe);
-				} else
-					up_write(&s->lock);
-				r = 0;
-			}
+			goto out_unlock;
 		}
 
+		pe = __find_pending_exception(s, bio);
+		if (!pe) {
+			__invalidate_snapshot(s, pe, -ENOMEM);
+			r = -EIO;
+			goto out_unlock;
+		}
+
+		remap_exception(s, &pe->e, bio);
+		bio_list_add(&pe->snapshot_bios, bio);
+
+		if (!pe->started) {
+			/* this is protected by snap->lock */
+			pe->started = 1;
+			copy_needed = 1;
+		}
+
+		r = 0;
+
+ out_unlock:
+		up_write(&s->lock);
+
+		if (copy_needed)
+			start_copy(pe);
 	} else {
 		/*
 		 * FIXME: this read path scares me because we
@@ -847,6 +921,11 @@
 		/* Do reads */
 		down_read(&s->lock);
 
+		if (!s->valid) {
+			up_read(&s->lock);
+			return -EIO;
+		}
+
 		/* See if it it has been remapped */
 		e = lookup_exception(&s->complete, chunk);
 		if (e)
@@ -884,9 +963,9 @@
 				snap->store.fraction_full(&snap->store,
 							  &numerator,
 							  &denominator);
-				snprintf(result, maxlen,
-					 SECTOR_FORMAT "/" SECTOR_FORMAT,
-					 numerator, denominator);
+				snprintf(result, maxlen, "%llu/%llu",
+					(unsigned long long)numerator,
+					(unsigned long long)denominator);
 			}
 			else
 				snprintf(result, maxlen, "Unknown");
@@ -899,9 +978,10 @@
 		 * to make private copies if the output is to
 		 * make sense.
 		 */
-		snprintf(result, maxlen, "%s %s %c " SECTOR_FORMAT,
+		snprintf(result, maxlen, "%s %s %c %llu",
 			 snap->origin->name, snap->cow->name,
-			 snap->type, snap->chunk_size);
+			 snap->type,
+			 (unsigned long long)snap->chunk_size);
 		break;
 	}
 
@@ -911,40 +991,27 @@
 /*-----------------------------------------------------------------
  * Origin methods
  *---------------------------------------------------------------*/
-static void list_merge(struct list_head *l1, struct list_head *l2)
-{
-	struct list_head *l1_n, *l2_p;
-
-	l1_n = l1->next;
-	l2_p = l2->prev;
-
-	l1->next = l2;
-	l2->prev = l1;
-
-	l2_p->next = l1_n;
-	l1_n->prev = l2_p;
-}
-
 static int __origin_write(struct list_head *snapshots, struct bio *bio)
 {
-	int r = 1, first = 1;
+	int r = 1, first = 0;
 	struct dm_snapshot *snap;
 	struct exception *e;
-	struct pending_exception *pe, *last = NULL;
+	struct pending_exception *pe, *next_pe, *primary_pe = NULL;
 	chunk_t chunk;
+	LIST_HEAD(pe_queue);
 
 	/* Do all the snapshots on this origin */
 	list_for_each_entry (snap, snapshots, list) {
 
+		down_write(&snap->lock);
+
 		/* Only deal with valid and active snapshots */
 		if (!snap->valid || !snap->active)
-			continue;
+			goto next_snapshot;
 
 		/* Nothing to do if writing beyond end of snapshot */
 		if (bio->bi_sector >= dm_table_get_size(snap->table))
-			continue;
-
-		down_write(&snap->lock);
+			goto next_snapshot;
 
 		/*
 		 * Remember, different snapshots can have
@@ -956,49 +1023,75 @@
 		 * Check exception table to see if block
 		 * is already remapped in this snapshot
 		 * and trigger an exception if not.
+		 *
+		 * sibling_count is initialised to 1 so pending_complete()
+		 * won't destroy the primary_pe while we're inside this loop.
 		 */
 		e = lookup_exception(&snap->complete, chunk);
-		if (!e) {
-			pe = __find_pending_exception(snap, bio);
-			if (!pe) {
-				snap->store.drop_snapshot(&snap->store);
-				snap->valid = 0;
+		if (e)
+			goto next_snapshot;
 
-			} else {
-				if (last)
-					list_merge(&pe->siblings,
-						   &last->siblings);
-
-				last = pe;
-				r = 0;
-			}
+		pe = __find_pending_exception(snap, bio);
+		if (!pe) {
+			__invalidate_snapshot(snap, pe, ENOMEM);
+			goto next_snapshot;
 		}
 
+		if (!primary_pe) {
+			/*
+			 * Either every pe here has same
+			 * primary_pe or none has one yet.
+			 */
+			if (pe->primary_pe)
+				primary_pe = pe->primary_pe;
+			else {
+				primary_pe = pe;
+				first = 1;
+			}
+
+			bio_list_add(&primary_pe->origin_bios, bio);
+
+			r = 0;
+		}
+
+		if (!pe->primary_pe) {
+			atomic_inc(&primary_pe->sibling_count);
+			pe->primary_pe = primary_pe;
+		}
+
+		if (!pe->started) {
+			pe->started = 1;
+			list_add_tail(&pe->list, &pe_queue);
+		}
+
+ next_snapshot:
 		up_write(&snap->lock);
 	}
 
+	if (!primary_pe)
+		goto out;
+
+	/*
+	 * If this is the first time we're processing this chunk and
+	 * sibling_count is now 1 it means all the pending exceptions
+	 * got completed while we were in the loop above, so it falls to
+	 * us here to remove the primary_pe and submit any origin_bios.
+	 */
+
+	if (first && atomic_dec_and_test(&primary_pe->sibling_count)) {
+		flush_bios(bio_list_get(&primary_pe->origin_bios));
+		free_pending_exception(primary_pe);
+		/* If we got here, pe_queue is necessarily empty. */
+		goto out;
+	}
+
 	/*
 	 * Now that we have a complete pe list we can start the copying.
 	 */
-	if (last) {
-		pe = last;
-		do {
-			down_write(&pe->snap->lock);
-			if (first)
-				bio_list_add(&pe->origin_bios, bio);
-			if (!pe->started) {
-				pe->started = 1;
-				up_write(&pe->snap->lock);
-				start_copy(pe);
-			} else
-				up_write(&pe->snap->lock);
-			first = 0;
-			pe = list_entry(pe->siblings.next,
-					struct pending_exception, siblings);
+	list_for_each_entry_safe(pe, next_pe, &pe_queue, list)
+		start_copy(pe);
 
-		} while (pe != last);
-	}
-
+ out:
 	return r;
 }
 
@@ -1174,8 +1267,7 @@
 		goto bad4;
 	}
 
-	pending_pool = mempool_create(128, mempool_alloc_slab,
-				      mempool_free_slab, pending_cache);
+	pending_pool = mempool_create_slab_pool(128, pending_cache);
 	if (!pending_pool) {
 		DMERR("Couldn't create pending pool.");
 		r = -ENOMEM;
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 697aaca..08328a8 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -49,9 +49,9 @@
 static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
 		      unsigned int stripe, char **argv)
 {
-	sector_t start;
+	unsigned long long start;
 
-	if (sscanf(argv[1], SECTOR_FORMAT, &start) != 1)
+	if (sscanf(argv[1], "%llu", &start) != 1)
 		return -EINVAL;
 
 	if (dm_get_device(ti, argv[0], start, sc->stripe_width,
@@ -103,7 +103,7 @@
 		return -EINVAL;
 	}
 
-	if (((uint32_t)ti->len) & (chunk_size - 1)) {
+	if (ti->len & (chunk_size - 1)) {
 		ti->error = "dm-stripe: Target length not divisible by "
 		    "chunk size";
 		return -EINVAL;
@@ -201,10 +201,11 @@
 		break;
 
 	case STATUSTYPE_TABLE:
-		DMEMIT("%d " SECTOR_FORMAT, sc->stripes, sc->chunk_mask + 1);
+		DMEMIT("%d %llu", sc->stripes,
+			(unsigned long long)sc->chunk_mask + 1);
 		for (i = 0; i < sc->stripes; i++)
-			DMEMIT(" %s " SECTOR_FORMAT, sc->stripe[i].dev->name,
-			       sc->stripe[i].physical_start);
+			DMEMIT(" %s %llu", sc->stripe[i].dev->name,
+			    (unsigned long long)sc->stripe[i].physical_start);
 		break;
 	}
 	return 0;
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 9b1e2f5..8f56a54 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -14,6 +14,7 @@
 #include <linux/ctype.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
 #include <asm/atomic.h>
 
 #define MAX_DEPTH 16
@@ -22,6 +23,7 @@
 #define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
 
 struct dm_table {
+	struct mapped_device *md;
 	atomic_t holders;
 
 	/* btree table */
@@ -97,6 +99,8 @@
 
 	lhs->seg_boundary_mask =
 		min_not_zero(lhs->seg_boundary_mask, rhs->seg_boundary_mask);
+
+	lhs->no_cluster |= rhs->no_cluster;
 }
 
 /*
@@ -204,7 +208,8 @@
 	return 0;
 }
 
-int dm_table_create(struct dm_table **result, int mode, unsigned num_targets)
+int dm_table_create(struct dm_table **result, int mode,
+		    unsigned num_targets, struct mapped_device *md)
 {
 	struct dm_table *t = kmalloc(sizeof(*t), GFP_KERNEL);
 
@@ -227,6 +232,7 @@
 	}
 
 	t->mode = mode;
+	t->md = md;
 	*result = t;
 	return 0;
 }
@@ -345,20 +351,19 @@
 /*
  * Open a device so we can use it as a map destination.
  */
-static int open_dev(struct dm_dev *d, dev_t dev)
+static int open_dev(struct dm_dev *d, dev_t dev, struct mapped_device *md)
 {
 	static char *_claim_ptr = "I belong to device-mapper";
 	struct block_device *bdev;
 
 	int r;
 
-	if (d->bdev)
-		BUG();
+	BUG_ON(d->bdev);
 
 	bdev = open_by_devnum(dev, d->mode);
 	if (IS_ERR(bdev))
 		return PTR_ERR(bdev);
-	r = bd_claim(bdev, _claim_ptr);
+	r = bd_claim_by_disk(bdev, _claim_ptr, dm_disk(md));
 	if (r)
 		blkdev_put(bdev);
 	else
@@ -369,12 +374,12 @@
 /*
  * Close a device that we've been using.
  */
-static void close_dev(struct dm_dev *d)
+static void close_dev(struct dm_dev *d, struct mapped_device *md)
 {
 	if (!d->bdev)
 		return;
 
-	bd_release(d->bdev);
+	bd_release_from_disk(d->bdev, dm_disk(md));
 	blkdev_put(d->bdev);
 	d->bdev = NULL;
 }
@@ -395,7 +400,7 @@
  * careful to leave things as they were if we fail to reopen the
  * device.
  */
-static int upgrade_mode(struct dm_dev *dd, int new_mode)
+static int upgrade_mode(struct dm_dev *dd, int new_mode, struct mapped_device *md)
 {
 	int r;
 	struct dm_dev dd_copy;
@@ -405,9 +410,9 @@
 
 	dd->mode |= new_mode;
 	dd->bdev = NULL;
-	r = open_dev(dd, dev);
+	r = open_dev(dd, dev, md);
 	if (!r)
-		close_dev(&dd_copy);
+		close_dev(&dd_copy, md);
 	else
 		*dd = dd_copy;
 
@@ -427,8 +432,7 @@
 	struct dm_dev *dd;
 	unsigned int major, minor;
 
-	if (!t)
-		BUG();
+	BUG_ON(!t);
 
 	if (sscanf(path, "%u:%u", &major, &minor) == 2) {
 		/* Extract the major/minor numbers */
@@ -450,7 +454,7 @@
 		dd->mode = mode;
 		dd->bdev = NULL;
 
-		if ((r = open_dev(dd, dev))) {
+		if ((r = open_dev(dd, dev, t->md))) {
 			kfree(dd);
 			return r;
 		}
@@ -461,7 +465,7 @@
 		list_add(&dd->list, &t->devices);
 
 	} else if (dd->mode != (mode | dd->mode)) {
-		r = upgrade_mode(dd, mode);
+		r = upgrade_mode(dd, mode, t->md);
 		if (r)
 			return r;
 	}
@@ -525,6 +529,8 @@
 		rs->seg_boundary_mask =
 			min_not_zero(rs->seg_boundary_mask,
 				     q->seg_boundary_mask);
+
+		rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
 	}
 
 	return r;
@@ -536,7 +542,7 @@
 void dm_put_device(struct dm_target *ti, struct dm_dev *dd)
 {
 	if (atomic_dec_and_test(&dd->count)) {
-		close_dev(dd);
+		close_dev(dd, ti->table->md);
 		list_del(&dd->list);
 		kfree(dd);
 	}
@@ -765,14 +771,14 @@
 	return r;
 }
 
-static DECLARE_MUTEX(_event_lock);
+static DEFINE_MUTEX(_event_lock);
 void dm_table_event_callback(struct dm_table *t,
 			     void (*fn)(void *), void *context)
 {
-	down(&_event_lock);
+	mutex_lock(&_event_lock);
 	t->event_fn = fn;
 	t->event_context = context;
-	up(&_event_lock);
+	mutex_unlock(&_event_lock);
 }
 
 void dm_table_event(struct dm_table *t)
@@ -783,10 +789,10 @@
 	 */
 	BUG_ON(in_interrupt());
 
-	down(&_event_lock);
+	mutex_lock(&_event_lock);
 	if (t->event_fn)
 		t->event_fn(t->event_context);
-	up(&_event_lock);
+	mutex_unlock(&_event_lock);
 }
 
 sector_t dm_table_get_size(struct dm_table *t)
@@ -834,6 +840,11 @@
 	q->hardsect_size = t->limits.hardsect_size;
 	q->max_segment_size = t->limits.max_segment_size;
 	q->seg_boundary_mask = t->limits.seg_boundary_mask;
+	if (t->limits.no_cluster)
+		q->queue_flags &= ~(1 << QUEUE_FLAG_CLUSTER);
+	else
+		q->queue_flags |= (1 << QUEUE_FLAG_CLUSTER);
+
 }
 
 unsigned int dm_table_get_num_targets(struct dm_table *t)
@@ -945,12 +956,20 @@
 	return ret;
 }
 
+struct mapped_device *dm_table_get_md(struct dm_table *t)
+{
+	dm_get(t->md);
+
+	return t->md;
+}
+
 EXPORT_SYMBOL(dm_vcalloc);
 EXPORT_SYMBOL(dm_get_device);
 EXPORT_SYMBOL(dm_put_device);
 EXPORT_SYMBOL(dm_table_event);
 EXPORT_SYMBOL(dm_table_get_size);
 EXPORT_SYMBOL(dm_table_get_mode);
+EXPORT_SYMBOL(dm_table_get_md);
 EXPORT_SYMBOL(dm_table_put);
 EXPORT_SYMBOL(dm_table_get);
 EXPORT_SYMBOL(dm_table_unplug_all);
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 8c82373..4d710b7 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -10,6 +10,7 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/moduleparam.h>
 #include <linux/blkpg.h>
 #include <linux/bio.h>
@@ -17,6 +18,7 @@
 #include <linux/mempool.h>
 #include <linux/slab.h>
 #include <linux/idr.h>
+#include <linux/hdreg.h>
 #include <linux/blktrace_api.h>
 
 static const char *_name = DM_NAME;
@@ -69,6 +71,7 @@
 
 	request_queue_t *queue;
 	struct gendisk *disk;
+	char name[16];
 
 	void *interface_ptr;
 
@@ -101,6 +104,9 @@
 	 */
 	struct super_block *frozen_sb;
 	struct block_device *suspended_bdev;
+
+	/* forced geometry settings */
+	struct hd_geometry geometry;
 };
 
 #define MIN_IOS 256
@@ -226,6 +232,13 @@
 	return 0;
 }
 
+static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+	struct mapped_device *md = bdev->bd_disk->private_data;
+
+	return dm_get_geometry(md, geo);
+}
+
 static inline struct dm_io *alloc_io(struct mapped_device *md)
 {
 	return mempool_alloc(md->io_pool, GFP_NOIO);
@@ -312,6 +325,33 @@
 	return t;
 }
 
+/*
+ * Get the geometry associated with a dm device
+ */
+int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo)
+{
+	*geo = md->geometry;
+
+	return 0;
+}
+
+/*
+ * Set the geometry of a device.
+ */
+int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo)
+{
+	sector_t sz = (sector_t)geo->cylinders * geo->heads * geo->sectors;
+
+	if (geo->start > sz) {
+		DMWARN("Start sector is beyond the geometry limits.");
+		return -EINVAL;
+	}
+
+	md->geometry = *geo;
+
+	return 0;
+}
+
 /*-----------------------------------------------------------------
  * CRUD START:
  *   A more elegant soln is in the works that uses the queue
@@ -704,14 +744,14 @@
 /*-----------------------------------------------------------------
  * An IDR is used to keep track of allocated minor numbers.
  *---------------------------------------------------------------*/
-static DECLARE_MUTEX(_minor_lock);
+static DEFINE_MUTEX(_minor_lock);
 static DEFINE_IDR(_minor_idr);
 
 static void free_minor(unsigned int minor)
 {
-	down(&_minor_lock);
+	mutex_lock(&_minor_lock);
 	idr_remove(&_minor_idr, minor);
-	up(&_minor_lock);
+	mutex_unlock(&_minor_lock);
 }
 
 /*
@@ -724,7 +764,7 @@
 	if (minor >= (1 << MINORBITS))
 		return -EINVAL;
 
-	down(&_minor_lock);
+	mutex_lock(&_minor_lock);
 
 	if (idr_find(&_minor_idr, minor)) {
 		r = -EBUSY;
@@ -749,7 +789,7 @@
 	}
 
 out:
-	up(&_minor_lock);
+	mutex_unlock(&_minor_lock);
 	return r;
 }
 
@@ -758,7 +798,7 @@
 	int r;
 	unsigned int m;
 
-	down(&_minor_lock);
+	mutex_lock(&_minor_lock);
 
 	r = idr_pre_get(&_minor_idr, GFP_KERNEL);
 	if (!r) {
@@ -780,7 +820,7 @@
 	*minor = m;
 
 out:
-	up(&_minor_lock);
+	mutex_unlock(&_minor_lock);
 	return r;
 }
 
@@ -823,13 +863,11 @@
 	md->queue->unplug_fn = dm_unplug_all;
 	md->queue->issue_flush_fn = dm_flush_all;
 
-	md->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
-				     mempool_free_slab, _io_cache);
+	md->io_pool = mempool_create_slab_pool(MIN_IOS, _io_cache);
  	if (!md->io_pool)
  		goto bad2;
 
-	md->tio_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
-				      mempool_free_slab, _tio_cache);
+	md->tio_pool = mempool_create_slab_pool(MIN_IOS, _tio_cache);
 	if (!md->tio_pool)
 		goto bad3;
 
@@ -844,6 +882,7 @@
 	md->disk->private_data = md;
 	sprintf(md->disk->disk_name, "dm-%d", minor);
 	add_disk(md->disk);
+	format_dev_t(md->name, MKDEV(_major, minor));
 
 	atomic_set(&md->pending, 0);
 	init_waitqueue_head(&md->wait);
@@ -906,6 +945,13 @@
 	sector_t size;
 
 	size = dm_table_get_size(t);
+
+	/*
+	 * Wipe any geometry if the size of the table changed.
+	 */
+	if (size != get_capacity(md->disk))
+		memset(&md->geometry, 0, sizeof(md->geometry));
+
 	__set_size(md, size);
 	if (size == 0)
 		return 0;
@@ -969,13 +1015,13 @@
 	if (MAJOR(dev) != _major || minor >= (1 << MINORBITS))
 		return NULL;
 
-	down(&_minor_lock);
+	mutex_lock(&_minor_lock);
 
 	md = idr_find(&_minor_idr, minor);
 	if (!md || (dm_disk(md)->first_minor != minor))
 		md = NULL;
 
-	up(&_minor_lock);
+	mutex_unlock(&_minor_lock);
 
 	return md;
 }
@@ -990,15 +1036,9 @@
 	return md;
 }
 
-void *dm_get_mdptr(dev_t dev)
+void *dm_get_mdptr(struct mapped_device *md)
 {
-	struct mapped_device *md;
-	void *mdptr = NULL;
-
-	md = dm_find_md(dev);
-	if (md)
-		mdptr = md->interface_ptr;
-	return mdptr;
+	return md->interface_ptr;
 }
 
 void dm_set_mdptr(struct mapped_device *md, void *ptr)
@@ -1013,18 +1053,18 @@
 
 void dm_put(struct mapped_device *md)
 {
-	struct dm_table *map = dm_get_table(md);
+	struct dm_table *map;
 
 	if (atomic_dec_and_test(&md->holders)) {
+		map = dm_get_table(md);
 		if (!dm_suspended(md)) {
 			dm_table_presuspend_targets(map);
 			dm_table_postsuspend_targets(map);
 		}
 		__unbind(md);
+		dm_table_put(map);
 		free_dev(md);
 	}
-
-	dm_table_put(map);
 }
 
 /*
@@ -1109,6 +1149,7 @@
 {
 	struct dm_table *map = NULL;
 	DECLARE_WAITQUEUE(wait, current);
+	struct bio *def;
 	int r = -EINVAL;
 
 	down(&md->suspend_lock);
@@ -1168,9 +1209,11 @@
 	/* were we interrupted ? */
 	r = -EINTR;
 	if (atomic_read(&md->pending)) {
+		clear_bit(DMF_BLOCK_IO, &md->flags);
+		def = bio_list_get(&md->deferred);
+		__flush_deferred_io(md, def);
 		up_write(&md->io_lock);
 		unlock_fs(md);
-		clear_bit(DMF_BLOCK_IO, &md->flags);
 		goto out;
 	}
 	up_write(&md->io_lock);
@@ -1264,6 +1307,7 @@
 static struct block_device_operations dm_blk_dops = {
 	.open = dm_blk_open,
 	.release = dm_blk_close,
+	.getgeo = dm_blk_getgeo,
 	.owner = THIS_MODULE
 };
 
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 4eaf075..fd90bc8 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -14,6 +14,7 @@
 #include <linux/device-mapper.h>
 #include <linux/list.h>
 #include <linux/blkdev.h>
+#include <linux/hdreg.h>
 
 #define DM_NAME "device-mapper"
 #define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x)
@@ -23,16 +24,6 @@
 #define DMEMIT(x...) sz += ((sz >= maxlen) ? \
 			  0 : scnprintf(result + sz, maxlen - sz, x))
 
-/*
- * FIXME: I think this should be with the definition of sector_t
- * in types.h.
- */
-#ifdef CONFIG_LBD
-#define SECTOR_FORMAT "%llu"
-#else
-#define SECTOR_FORMAT "%lu"
-#endif
-
 #define SECTOR_SHIFT 9
 
 /*
@@ -57,7 +48,7 @@
 int dm_create(struct mapped_device **md);
 int dm_create_with_minor(unsigned int minor, struct mapped_device **md);
 void dm_set_mdptr(struct mapped_device *md, void *ptr);
-void *dm_get_mdptr(dev_t dev);
+void *dm_get_mdptr(struct mapped_device *md);
 struct mapped_device *dm_get_md(dev_t dev);
 
 /*
@@ -95,11 +86,18 @@
 struct gendisk *dm_disk(struct mapped_device *md);
 int dm_suspended(struct mapped_device *md);
 
+/*
+ * Geometry functions.
+ */
+int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo);
+int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo);
+
 /*-----------------------------------------------------------------
  * Functions for manipulating a table.  Tables are also reference
  * counted.
  *---------------------------------------------------------------*/
-int dm_table_create(struct dm_table **result, int mode, unsigned num_targets);
+int dm_table_create(struct dm_table **result, int mode,
+		    unsigned num_targets, struct mapped_device *md);
 
 void dm_table_get(struct dm_table *t);
 void dm_table_put(struct dm_table *t);
@@ -117,6 +115,7 @@
 unsigned int dm_table_get_num_targets(struct dm_table *t);
 struct list_head *dm_table_get_devices(struct dm_table *t);
 int dm_table_get_mode(struct dm_table *t);
+struct mapped_device *dm_table_get_md(struct dm_table *t);
 void dm_table_presuspend_targets(struct dm_table *t);
 void dm_table_postsuspend_targets(struct dm_table *t);
 void dm_table_resume_targets(struct dm_table *t);
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c
index 8b3515f..72480a4 100644
--- a/drivers/md/kcopyd.c
+++ b/drivers/md/kcopyd.c
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/workqueue.h>
+#include <linux/mutex.h>
 
 #include "kcopyd.h"
 
@@ -44,6 +45,9 @@
 	struct page_list *pages;
 	unsigned int nr_pages;
 	unsigned int nr_free_pages;
+
+	wait_queue_head_t destroyq;
+	atomic_t nr_jobs;
 };
 
 static struct page_list *alloc_pl(void)
@@ -227,8 +231,7 @@
 	if (!_job_cache)
 		return -ENOMEM;
 
-	_job_pool = mempool_create(MIN_JOBS, mempool_alloc_slab,
-				   mempool_free_slab, _job_cache);
+	_job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache);
 	if (!_job_pool) {
 		kmem_cache_destroy(_job_cache);
 		return -ENOMEM;
@@ -293,10 +296,15 @@
 	int read_err = job->read_err;
 	unsigned int write_err = job->write_err;
 	kcopyd_notify_fn fn = job->fn;
+	struct kcopyd_client *kc = job->kc;
 
-	kcopyd_put_pages(job->kc, job->pages);
+	kcopyd_put_pages(kc, job->pages);
 	mempool_free(job, _job_pool);
 	fn(read_err, write_err, context);
+
+	if (atomic_dec_and_test(&kc->nr_jobs))
+		wake_up(&kc->destroyq);
+
 	return 0;
 }
 
@@ -431,6 +439,7 @@
  */
 static void dispatch_job(struct kcopyd_job *job)
 {
+	atomic_inc(&job->kc->nr_jobs);
 	push(&_pages_jobs, job);
 	wake();
 }
@@ -573,68 +582,68 @@
 /*-----------------------------------------------------------------
  * Unit setup
  *---------------------------------------------------------------*/
-static DECLARE_MUTEX(_client_lock);
+static DEFINE_MUTEX(_client_lock);
 static LIST_HEAD(_clients);
 
 static void client_add(struct kcopyd_client *kc)
 {
-	down(&_client_lock);
+	mutex_lock(&_client_lock);
 	list_add(&kc->list, &_clients);
-	up(&_client_lock);
+	mutex_unlock(&_client_lock);
 }
 
 static void client_del(struct kcopyd_client *kc)
 {
-	down(&_client_lock);
+	mutex_lock(&_client_lock);
 	list_del(&kc->list);
-	up(&_client_lock);
+	mutex_unlock(&_client_lock);
 }
 
-static DECLARE_MUTEX(kcopyd_init_lock);
+static DEFINE_MUTEX(kcopyd_init_lock);
 static int kcopyd_clients = 0;
 
 static int kcopyd_init(void)
 {
 	int r;
 
-	down(&kcopyd_init_lock);
+	mutex_lock(&kcopyd_init_lock);
 
 	if (kcopyd_clients) {
 		/* Already initialized. */
 		kcopyd_clients++;
-		up(&kcopyd_init_lock);
+		mutex_unlock(&kcopyd_init_lock);
 		return 0;
 	}
 
 	r = jobs_init();
 	if (r) {
-		up(&kcopyd_init_lock);
+		mutex_unlock(&kcopyd_init_lock);
 		return r;
 	}
 
 	_kcopyd_wq = create_singlethread_workqueue("kcopyd");
 	if (!_kcopyd_wq) {
 		jobs_exit();
-		up(&kcopyd_init_lock);
+		mutex_unlock(&kcopyd_init_lock);
 		return -ENOMEM;
 	}
 
 	kcopyd_clients++;
 	INIT_WORK(&_kcopyd_work, do_work, NULL);
-	up(&kcopyd_init_lock);
+	mutex_unlock(&kcopyd_init_lock);
 	return 0;
 }
 
 static void kcopyd_exit(void)
 {
-	down(&kcopyd_init_lock);
+	mutex_lock(&kcopyd_init_lock);
 	kcopyd_clients--;
 	if (!kcopyd_clients) {
 		jobs_exit();
 		destroy_workqueue(_kcopyd_wq);
 		_kcopyd_wq = NULL;
 	}
-	up(&kcopyd_init_lock);
+	mutex_unlock(&kcopyd_init_lock);
 }
 
 int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
@@ -670,6 +679,9 @@
 		return r;
 	}
 
+	init_waitqueue_head(&kc->destroyq);
+	atomic_set(&kc->nr_jobs, 0);
+
 	client_add(kc);
 	*result = kc;
 	return 0;
@@ -677,6 +689,9 @@
 
 void kcopyd_client_destroy(struct kcopyd_client *kc)
 {
+	/* Wait for completion of all jobs submitted by this client. */
+	wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs));
+
 	dm_io_put(kc->nr_pages);
 	client_free_pages(kc);
 	client_del(kc);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 5ed2228..1ed5152 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -43,6 +43,7 @@
 #include <linux/buffer_head.h> /* for invalidate_bdev */
 #include <linux/suspend.h>
 #include <linux/poll.h>
+#include <linux/mutex.h>
 
 #include <linux/init.h>
 
@@ -158,11 +159,12 @@
  */
 static DECLARE_WAIT_QUEUE_HEAD(md_event_waiters);
 static atomic_t md_event_count;
-static void md_new_event(mddev_t *mddev)
+void md_new_event(mddev_t *mddev)
 {
 	atomic_inc(&md_event_count);
 	wake_up(&md_event_waiters);
 }
+EXPORT_SYMBOL_GPL(md_new_event);
 
 /*
  * Enables to iterate over all existing md arrays
@@ -213,13 +215,11 @@
 		return;
 	if (!mddev->raid_disks && list_empty(&mddev->disks)) {
 		list_del(&mddev->all_mddevs);
-		/* that blocks */
+		spin_unlock(&all_mddevs_lock);
 		blk_cleanup_queue(mddev->queue);
-		/* that also blocks */
 		kobject_unregister(&mddev->kobj);
-		/* result blows... */
-	}
-	spin_unlock(&all_mddevs_lock);
+	} else
+		spin_unlock(&all_mddevs_lock);
 }
 
 static mddev_t * mddev_find(dev_t unit)
@@ -253,7 +253,7 @@
 	else
 		new->md_minor = MINOR(unit) >> MdpMinorShift;
 
-	init_MUTEX(&new->reconfig_sem);
+	mutex_init(&new->reconfig_mutex);
 	INIT_LIST_HEAD(&new->disks);
 	INIT_LIST_HEAD(&new->all_mddevs);
 	init_timer(&new->safemode_timer);
@@ -266,6 +266,7 @@
 		kfree(new);
 		return NULL;
 	}
+	set_bit(QUEUE_FLAG_CLUSTER, &new->queue->queue_flags);
 
 	blk_queue_make_request(new->queue, md_fail_request);
 
@@ -274,22 +275,22 @@
 
 static inline int mddev_lock(mddev_t * mddev)
 {
-	return down_interruptible(&mddev->reconfig_sem);
+	return mutex_lock_interruptible(&mddev->reconfig_mutex);
 }
 
 static inline void mddev_lock_uninterruptible(mddev_t * mddev)
 {
-	down(&mddev->reconfig_sem);
+	mutex_lock(&mddev->reconfig_mutex);
 }
 
 static inline int mddev_trylock(mddev_t * mddev)
 {
-	return down_trylock(&mddev->reconfig_sem);
+	return mutex_trylock(&mddev->reconfig_mutex);
 }
 
 static inline void mddev_unlock(mddev_t * mddev)
 {
-	up(&mddev->reconfig_sem);
+	mutex_unlock(&mddev->reconfig_mutex);
 
 	md_wakeup_thread(mddev->thread);
 }
@@ -660,7 +661,8 @@
 	}
 
 	if (sb->major_version != 0 ||
-	    sb->minor_version != 90) {
+	    sb->minor_version < 90 ||
+	    sb->minor_version > 91) {
 		printk(KERN_WARNING "Bad version number %d.%d on %s\n",
 			sb->major_version, sb->minor_version,
 			b);
@@ -745,6 +747,20 @@
 		mddev->bitmap_offset = 0;
 		mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
 
+		if (mddev->minor_version >= 91) {
+			mddev->reshape_position = sb->reshape_position;
+			mddev->delta_disks = sb->delta_disks;
+			mddev->new_level = sb->new_level;
+			mddev->new_layout = sb->new_layout;
+			mddev->new_chunk = sb->new_chunk;
+		} else {
+			mddev->reshape_position = MaxSector;
+			mddev->delta_disks = 0;
+			mddev->new_level = mddev->level;
+			mddev->new_layout = mddev->layout;
+			mddev->new_chunk = mddev->chunk_size;
+		}
+
 		if (sb->state & (1<<MD_SB_CLEAN))
 			mddev->recovery_cp = MaxSector;
 		else {
@@ -764,7 +780,8 @@
 
 		if (sb->state & (1<<MD_SB_BITMAP_PRESENT) &&
 		    mddev->bitmap_file == NULL) {
-			if (mddev->level != 1 && mddev->level != 5 && mddev->level != 6
+			if (mddev->level != 1 && mddev->level != 4
+			    && mddev->level != 5 && mddev->level != 6
 			    && mddev->level != 10) {
 				/* FIXME use a better test */
 				printk(KERN_WARNING "md: bitmaps not supported for this level.\n");
@@ -838,7 +855,6 @@
 
 	sb->md_magic = MD_SB_MAGIC;
 	sb->major_version = mddev->major_version;
-	sb->minor_version = mddev->minor_version;
 	sb->patch_version = mddev->patch_version;
 	sb->gvalid_words  = 0; /* ignored */
 	memcpy(&sb->set_uuid0, mddev->uuid+0, 4);
@@ -857,6 +873,17 @@
 	sb->events_hi = (mddev->events>>32);
 	sb->events_lo = (u32)mddev->events;
 
+	if (mddev->reshape_position == MaxSector)
+		sb->minor_version = 90;
+	else {
+		sb->minor_version = 91;
+		sb->reshape_position = mddev->reshape_position;
+		sb->new_level = mddev->new_level;
+		sb->delta_disks = mddev->delta_disks;
+		sb->new_layout = mddev->new_layout;
+		sb->new_chunk = mddev->new_chunk;
+	}
+	mddev->minor_version = sb->minor_version;
 	if (mddev->in_sync)
 	{
 		sb->recovery_cp = mddev->recovery_cp;
@@ -893,10 +920,9 @@
 			d->raid_disk = rdev2->raid_disk;
 		else
 			d->raid_disk = rdev2->desc_nr; /* compatibility */
-		if (test_bit(Faulty, &rdev2->flags)) {
+		if (test_bit(Faulty, &rdev2->flags))
 			d->state = (1<<MD_DISK_FAULTY);
-			failed++;
-		} else if (test_bit(In_sync, &rdev2->flags)) {
+		else if (test_bit(In_sync, &rdev2->flags)) {
 			d->state = (1<<MD_DISK_ACTIVE);
 			d->state |= (1<<MD_DISK_SYNC);
 			active++;
@@ -1102,6 +1128,20 @@
 			}
 			mddev->bitmap_offset = (__s32)le32_to_cpu(sb->bitmap_offset);
 		}
+		if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
+			mddev->reshape_position = le64_to_cpu(sb->reshape_position);
+			mddev->delta_disks = le32_to_cpu(sb->delta_disks);
+			mddev->new_level = le32_to_cpu(sb->new_level);
+			mddev->new_layout = le32_to_cpu(sb->new_layout);
+			mddev->new_chunk = le32_to_cpu(sb->new_chunk)<<9;
+		} else {
+			mddev->reshape_position = MaxSector;
+			mddev->delta_disks = 0;
+			mddev->new_level = mddev->level;
+			mddev->new_layout = mddev->layout;
+			mddev->new_chunk = mddev->chunk_size;
+		}
+
 	} else if (mddev->pers == NULL) {
 		/* Insist of good event counter while assembling */
 		__u64 ev1 = le64_to_cpu(sb->events);
@@ -1173,6 +1213,14 @@
 		sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset);
 		sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
 	}
+	if (mddev->reshape_position != MaxSector) {
+		sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE);
+		sb->reshape_position = cpu_to_le64(mddev->reshape_position);
+		sb->new_layout = cpu_to_le32(mddev->new_layout);
+		sb->delta_disks = cpu_to_le32(mddev->delta_disks);
+		sb->new_level = cpu_to_le32(mddev->new_level);
+		sb->new_chunk = cpu_to_le32(mddev->new_chunk>>9);
+	}
 
 	max_dev = 0;
 	ITERATE_RDEV(mddev,rdev2,tmp)
@@ -1301,6 +1349,7 @@
 	else
 		ko = &rdev->bdev->bd_disk->kobj;
 	sysfs_create_link(&rdev->kobj, ko, "block");
+	bd_claim_by_disk(rdev->bdev, rdev, mddev->gendisk);
 	return 0;
 }
 
@@ -1311,6 +1360,7 @@
 		MD_BUG();
 		return;
 	}
+	bd_release_from_disk(rdev->bdev, rdev->mddev->gendisk);
 	list_del_init(&rdev->same_set);
 	printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
 	rdev->mddev = NULL;
@@ -1493,7 +1543,7 @@
 	}
 }
 
-static void md_update_sb(mddev_t * mddev)
+void md_update_sb(mddev_t * mddev)
 {
 	int err;
 	struct list_head *tmp;
@@ -1570,6 +1620,7 @@
 	wake_up(&mddev->sb_wait);
 
 }
+EXPORT_SYMBOL_GPL(md_update_sb);
 
 /* words written to sysfs files may, or my not, be \n terminated.
  * We want to accept with case. For this we use cmd_match.
@@ -2162,7 +2213,9 @@
 	char *type = "idle";
 	if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
 	    test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) {
-		if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+		if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+			type = "reshape";
+		else if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
 			if (!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
 				type = "resync";
 			else if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
@@ -2193,7 +2246,14 @@
 		return -EBUSY;
 	else if (cmd_match(page, "resync") || cmd_match(page, "recover"))
 		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
-	else {
+	else if (cmd_match(page, "reshape")) {
+		int err;
+		if (mddev->pers->start_reshape == NULL)
+			return -EINVAL;
+		err = mddev->pers->start_reshape(mddev);
+		if (err)
+			return err;
+	} else {
 		if (cmd_match(page, "check"))
 			set_bit(MD_RECOVERY_CHECK, &mddev->recovery);
 		else if (cmd_match(page, "repair"))
@@ -2304,6 +2364,63 @@
 static struct md_sysfs_entry
 md_sync_completed = __ATTR_RO(sync_completed);
 
+static ssize_t
+suspend_lo_show(mddev_t *mddev, char *page)
+{
+	return sprintf(page, "%llu\n", (unsigned long long)mddev->suspend_lo);
+}
+
+static ssize_t
+suspend_lo_store(mddev_t *mddev, const char *buf, size_t len)
+{
+	char *e;
+	unsigned long long new = simple_strtoull(buf, &e, 10);
+
+	if (mddev->pers->quiesce == NULL)
+		return -EINVAL;
+	if (buf == e || (*e && *e != '\n'))
+		return -EINVAL;
+	if (new >= mddev->suspend_hi ||
+	    (new > mddev->suspend_lo && new < mddev->suspend_hi)) {
+		mddev->suspend_lo = new;
+		mddev->pers->quiesce(mddev, 2);
+		return len;
+	} else
+		return -EINVAL;
+}
+static struct md_sysfs_entry md_suspend_lo =
+__ATTR(suspend_lo, S_IRUGO|S_IWUSR, suspend_lo_show, suspend_lo_store);
+
+
+static ssize_t
+suspend_hi_show(mddev_t *mddev, char *page)
+{
+	return sprintf(page, "%llu\n", (unsigned long long)mddev->suspend_hi);
+}
+
+static ssize_t
+suspend_hi_store(mddev_t *mddev, const char *buf, size_t len)
+{
+	char *e;
+	unsigned long long new = simple_strtoull(buf, &e, 10);
+
+	if (mddev->pers->quiesce == NULL)
+		return -EINVAL;
+	if (buf == e || (*e && *e != '\n'))
+		return -EINVAL;
+	if ((new <= mddev->suspend_lo && mddev->suspend_lo >= mddev->suspend_hi) ||
+	    (new > mddev->suspend_lo && new > mddev->suspend_hi)) {
+		mddev->suspend_hi = new;
+		mddev->pers->quiesce(mddev, 1);
+		mddev->pers->quiesce(mddev, 0);
+		return len;
+	} else
+		return -EINVAL;
+}
+static struct md_sysfs_entry md_suspend_hi =
+__ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store);
+
+
 static struct attribute *md_default_attrs[] = {
 	&md_level.attr,
 	&md_raid_disks.attr,
@@ -2321,6 +2438,8 @@
 	&md_sync_max.attr,
 	&md_sync_speed.attr,
 	&md_sync_completed.attr,
+	&md_suspend_lo.attr,
+	&md_suspend_hi.attr,
 	NULL,
 };
 static struct attribute_group md_redundancy_group = {
@@ -2380,7 +2499,7 @@
 
 static struct kobject *md_probe(dev_t dev, int *part, void *data)
 {
-	static DECLARE_MUTEX(disks_sem);
+	static DEFINE_MUTEX(disks_mutex);
 	mddev_t *mddev = mddev_find(dev);
 	struct gendisk *disk;
 	int partitioned = (MAJOR(dev) != MD_MAJOR);
@@ -2390,15 +2509,15 @@
 	if (!mddev)
 		return NULL;
 
-	down(&disks_sem);
+	mutex_lock(&disks_mutex);
 	if (mddev->gendisk) {
-		up(&disks_sem);
+		mutex_unlock(&disks_mutex);
 		mddev_put(mddev);
 		return NULL;
 	}
 	disk = alloc_disk(1 << shift);
 	if (!disk) {
-		up(&disks_sem);
+		mutex_unlock(&disks_mutex);
 		mddev_put(mddev);
 		return NULL;
 	}
@@ -2416,7 +2535,7 @@
 	disk->queue = mddev->queue;
 	add_disk(disk);
 	mddev->gendisk = disk;
-	up(&disks_sem);
+	mutex_unlock(&disks_mutex);
 	mddev->kobj.parent = &disk->kobj;
 	mddev->kobj.k_name = NULL;
 	snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md");
@@ -2539,6 +2658,14 @@
 	mddev->level = pers->level;
 	strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
 
+	if (mddev->reshape_position != MaxSector &&
+	    pers->start_reshape == NULL) {
+		/* This personality cannot handle reshaping... */
+		mddev->pers = NULL;
+		module_put(pers->owner);
+		return -EINVAL;
+	}
+
 	mddev->recovery = 0;
 	mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */
 	mddev->barriers_work = 1;
@@ -2772,7 +2899,6 @@
  */
 static void autorun_devices(int part)
 {
-	struct list_head candidates;
 	struct list_head *tmp;
 	mdk_rdev_t *rdev0, *rdev;
 	mddev_t *mddev;
@@ -2781,6 +2907,7 @@
 	printk(KERN_INFO "md: autorun ...\n");
 	while (!list_empty(&pending_raid_disks)) {
 		dev_t dev;
+		LIST_HEAD(candidates);
 		rdev0 = list_entry(pending_raid_disks.next,
 					 mdk_rdev_t, same_set);
 
@@ -3427,11 +3554,18 @@
 	mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
 	mddev->bitmap_offset = 0;
 
+	mddev->reshape_position = MaxSector;
+
 	/*
 	 * Generate a 128 bit UUID
 	 */
 	get_random_bytes(mddev->uuid, 16);
 
+	mddev->new_level = mddev->level;
+	mddev->new_chunk = mddev->chunk_size;
+	mddev->new_layout = mddev->layout;
+	mddev->delta_disks = 0;
+
 	return 0;
 }
 
@@ -3440,6 +3574,7 @@
 	mdk_rdev_t * rdev;
 	int rv;
 	struct list_head *tmp;
+	int fit = (size == 0);
 
 	if (mddev->pers->resize == NULL)
 		return -EINVAL;
@@ -3457,7 +3592,6 @@
 		return -EBUSY;
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		sector_t avail;
-		int fit = (size == 0);
 		if (rdev->sb_offset > rdev->data_offset)
 			avail = (rdev->sb_offset*2) - rdev->data_offset;
 		else
@@ -3487,14 +3621,16 @@
 {
 	int rv;
 	/* change the number of raid disks */
-	if (mddev->pers->reshape == NULL)
+	if (mddev->pers->check_reshape == NULL)
 		return -EINVAL;
 	if (raid_disks <= 0 ||
 	    raid_disks >= mddev->max_disks)
 		return -EINVAL;
-	if (mddev->sync_thread)
+	if (mddev->sync_thread || mddev->reshape_position != MaxSector)
 		return -EBUSY;
-	rv = mddev->pers->reshape(mddev, raid_disks);
+	mddev->delta_disks = raid_disks - mddev->raid_disks;
+
+	rv = mddev->pers->check_reshape(mddev);
 	return rv;
 }
 
@@ -4041,7 +4177,10 @@
 
 static void status_resync(struct seq_file *seq, mddev_t * mddev)
 {
-	unsigned long max_blocks, resync, res, dt, db, rt;
+	sector_t max_blocks, resync, res;
+	unsigned long dt, db, rt;
+	int scale;
+	unsigned int per_milli;
 
 	resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2;
 
@@ -4057,9 +4196,22 @@
 		MD_BUG();
 		return;
 	}
-	res = (resync/1024)*1000/(max_blocks/1024 + 1);
+	/* Pick 'scale' such that (resync>>scale)*1000 will fit
+	 * in a sector_t, and (max_blocks>>scale) will fit in a
+	 * u32, as those are the requirements for sector_div.
+	 * Thus 'scale' must be at least 10
+	 */
+	scale = 10;
+	if (sizeof(sector_t) > sizeof(unsigned long)) {
+		while ( max_blocks/2 > (1ULL<<(scale+32)))
+			scale++;
+	}
+	res = (resync>>scale)*1000;
+	sector_div(res, (u32)((max_blocks>>scale)+1));
+
+	per_milli = res;
 	{
-		int i, x = res/50, y = 20-x;
+		int i, x = per_milli/50, y = 20-x;
 		seq_printf(seq, "[");
 		for (i = 0; i < x; i++)
 			seq_printf(seq, "=");
@@ -4068,10 +4220,14 @@
 			seq_printf(seq, ".");
 		seq_printf(seq, "] ");
 	}
-	seq_printf(seq, " %s =%3lu.%lu%% (%lu/%lu)",
+	seq_printf(seq, " %s =%3u.%u%% (%llu/%llu)",
+		   (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)?
+		    "reshape" :
 		      (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ?
-		       "resync" : "recovery"),
-		      res/10, res % 10, resync, max_blocks);
+		       "resync" : "recovery")),
+		      per_milli/10, per_milli % 10,
+		   (unsigned long long) resync,
+		   (unsigned long long) max_blocks);
 
 	/*
 	 * We do not want to overflow, so the order of operands and
@@ -4085,7 +4241,7 @@
 	dt = ((jiffies - mddev->resync_mark) / HZ);
 	if (!dt) dt++;
 	db = resync - (mddev->resync_mark_cnt/2);
-	rt = (dt * ((max_blocks-resync) / (db/100+1)))/100;
+	rt = (dt * ((unsigned long)(max_blocks-resync) / (db/100+1)))/100;
 
 	seq_printf(seq, " finish=%lu.%lumin", rt / 60, (rt % 60)/6);
 
@@ -4442,7 +4598,7 @@
 
 #define SYNC_MARKS	10
 #define	SYNC_MARK_STEP	(3*HZ)
-static void md_do_sync(mddev_t *mddev)
+void md_do_sync(mddev_t *mddev)
 {
 	mddev_t *mddev2;
 	unsigned int currspeed = 0,
@@ -4522,7 +4678,9 @@
 		 */
 		max_sectors = mddev->resync_max_sectors;
 		mddev->resync_mismatches = 0;
-	} else
+	} else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+		max_sectors = mddev->size << 1;
+	else
 		/* recovery follows the physical size of devices */
 		max_sectors = mddev->size << 1;
 
@@ -4658,6 +4816,8 @@
 	mddev->pers->sync_request(mddev, max_sectors, &skipped, 1);
 
 	if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) &&
+	    test_bit(MD_RECOVERY_SYNC, &mddev->recovery) &&
+	    !test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
 	    mddev->curr_resync > 2 &&
 	    mddev->curr_resync >= mddev->recovery_cp) {
 		if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
@@ -4675,6 +4835,7 @@
 	set_bit(MD_RECOVERY_DONE, &mddev->recovery);
 	md_wakeup_thread(mddev->thread);
 }
+EXPORT_SYMBOL_GPL(md_do_sync);
 
 
 /*
@@ -4730,7 +4891,7 @@
 		))
 		return;
 
-	if (mddev_trylock(mddev)==0) {
+	if (mddev_trylock(mddev)) {
 		int spares =0;
 
 		spin_lock_irq(&mddev->write_lock);
@@ -4866,7 +5027,7 @@
 		printk(KERN_INFO "md: stopping all md devices.\n");
 
 		ITERATE_MDDEV(mddev,tmp)
-			if (mddev_trylock(mddev)==0)
+			if (mddev_trylock(mddev))
 				do_md_stop (mddev, 1);
 		/*
 		 * certain more exotic SCSI devices are known to be
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 96f7af4..1cc9de4 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -35,18 +35,6 @@
 #define	NR_RESERVED_BUFS	32
 
 
-static void *mp_pool_alloc(gfp_t gfp_flags, void *data)
-{
-	struct multipath_bh *mpb;
-	mpb = kzalloc(sizeof(*mpb), gfp_flags);
-	return mpb;
-}
-
-static void mp_pool_free(void *mpb, void *data)
-{
-	kfree(mpb);
-}
-
 static int multipath_map (multipath_conf_t *conf)
 {
 	int i, disks = conf->raid_disks;
@@ -494,9 +482,8 @@
 	}
 	mddev->degraded = conf->raid_disks = conf->working_disks;
 
-	conf->pool = mempool_create(NR_RESERVED_BUFS,
-				    mp_pool_alloc, mp_pool_free,
-				    NULL);
+	conf->pool = mempool_create_kzalloc_pool(NR_RESERVED_BUFS,
+						 sizeof(struct multipath_bh));
 	if (conf->pool == NULL) {
 		printk(KERN_ERR 
 			"multipath: couldn't allocate memory for %s\n",
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 5d88329..9b374c9 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1135,8 +1135,19 @@
 			mirror = i;
 			break;
 		}
-	if (!uptodate)
+	if (!uptodate) {
+		int sync_blocks = 0;
+		sector_t s = r1_bio->sector;
+		long sectors_to_go = r1_bio->sectors;
+		/* make sure these bits doesn't get cleared. */
+		do {
+			bitmap_end_sync(mddev->bitmap, r1_bio->sector,
+					&sync_blocks, 1);
+			s += sync_blocks;
+			sectors_to_go -= sync_blocks;
+		} while (sectors_to_go > 0);
 		md_error(mddev, conf->mirrors[mirror].rdev);
+	}
 
 	update_head_pos(mirror, r1_bio);
 
@@ -1402,6 +1413,9 @@
 			clear_bit(R1BIO_BarrierRetry, &r1_bio->state);
 			clear_bit(R1BIO_Barrier, &r1_bio->state);
 			for (i=0; i < conf->raid_disks; i++)
+				if (r1_bio->bios[i])
+					atomic_inc(&r1_bio->remaining);
+			for (i=0; i < conf->raid_disks; i++)
 				if (r1_bio->bios[i]) {
 					struct bio_vec *bvec;
 					int j;
@@ -1789,6 +1803,11 @@
 		       mdname(mddev), mddev->level);
 		goto out;
 	}
+	if (mddev->reshape_position != MaxSector) {
+		printk("raid1: %s: reshape_position set but not supported\n",
+		       mdname(mddev));
+		goto out;
+	}
 	/*
 	 * copy the already verified devices into our private RAID1
 	 * bookkeeping area. [whatever we allocate in run(),
@@ -1971,7 +1990,7 @@
 	return 0;
 }
 
-static int raid1_reshape(mddev_t *mddev, int raid_disks)
+static int raid1_reshape(mddev_t *mddev)
 {
 	/* We need to:
 	 * 1/ resize the r1bio_pool
@@ -1988,10 +2007,22 @@
 	struct pool_info *newpoolinfo;
 	mirror_info_t *newmirrors;
 	conf_t *conf = mddev_to_conf(mddev);
-	int cnt;
+	int cnt, raid_disks;
 
 	int d, d2;
 
+	/* Cannot change chunk_size, layout, or level */
+	if (mddev->chunk_size != mddev->new_chunk ||
+	    mddev->layout != mddev->new_layout ||
+	    mddev->level != mddev->new_level) {
+		mddev->new_chunk = mddev->chunk_size;
+		mddev->new_layout = mddev->layout;
+		mddev->new_level = mddev->level;
+		return -EINVAL;
+	}
+
+	raid_disks = mddev->raid_disks + mddev->delta_disks;
+
 	if (raid_disks < conf->raid_disks) {
 		cnt=0;
 		for (d= 0; d < conf->raid_disks; d++)
@@ -2038,6 +2069,7 @@
 
 	mddev->degraded += (raid_disks - conf->raid_disks);
 	conf->raid_disks = mddev->raid_disks = raid_disks;
+	mddev->delta_disks = 0;
 
 	conf->last_used = 0; /* just make sure it is in-range */
 	lower_barrier(conf);
@@ -2079,7 +2111,7 @@
 	.spare_active	= raid1_spare_active,
 	.sync_request	= sync_request,
 	.resize		= raid1_resize,
-	.reshape	= raid1_reshape,
+	.check_reshape	= raid1_reshape,
 	.quiesce	= raid1_quiesce,
 };
 
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 2dba305..dae740a 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -22,6 +22,7 @@
 #include <linux/raid/raid5.h>
 #include <linux/highmem.h>
 #include <linux/bitops.h>
+#include <linux/kthread.h>
 #include <asm/atomic.h>
 
 #include <linux/raid/bitmap.h>
@@ -93,11 +94,11 @@
 				if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD)
 					md_wakeup_thread(conf->mddev->thread);
 			}
-			list_add_tail(&sh->lru, &conf->inactive_list);
 			atomic_dec(&conf->active_stripes);
-			if (!conf->inactive_blocked ||
-			    atomic_read(&conf->active_stripes) < (conf->max_nr_stripes*3/4))
+			if (!test_bit(STRIPE_EXPANDING, &sh->state)) {
+				list_add_tail(&sh->lru, &conf->inactive_list);
 				wake_up(&conf->wait_for_stripe);
+			}
 		}
 	}
 }
@@ -178,10 +179,10 @@
 
 static void raid5_build_block (struct stripe_head *sh, int i);
 
-static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
+static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int disks)
 {
 	raid5_conf_t *conf = sh->raid_conf;
-	int disks = conf->raid_disks, i;
+	int i;
 
 	if (atomic_read(&sh->count) != 0)
 		BUG();
@@ -198,7 +199,9 @@
 	sh->pd_idx = pd_idx;
 	sh->state = 0;
 
-	for (i=disks; i--; ) {
+	sh->disks = disks;
+
+	for (i = sh->disks; i--; ) {
 		struct r5dev *dev = &sh->dev[i];
 
 		if (dev->toread || dev->towrite || dev->written ||
@@ -215,7 +218,7 @@
 	insert_hash(conf, sh);
 }
 
-static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector)
+static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector, int disks)
 {
 	struct stripe_head *sh;
 	struct hlist_node *hn;
@@ -223,7 +226,7 @@
 	CHECK_DEVLOCK();
 	PRINTK("__find_stripe, sector %llu\n", (unsigned long long)sector);
 	hlist_for_each_entry(sh, hn, stripe_hash(conf, sector), hash)
-		if (sh->sector == sector)
+		if (sh->sector == sector && sh->disks == disks)
 			return sh;
 	PRINTK("__stripe %llu not in cache\n", (unsigned long long)sector);
 	return NULL;
@@ -232,8 +235,8 @@
 static void unplug_slaves(mddev_t *mddev);
 static void raid5_unplug_device(request_queue_t *q);
 
-static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector,
-					     int pd_idx, int noblock) 
+static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector, int disks,
+					     int pd_idx, int noblock)
 {
 	struct stripe_head *sh;
 
@@ -245,7 +248,7 @@
 		wait_event_lock_irq(conf->wait_for_stripe,
 				    conf->quiesce == 0,
 				    conf->device_lock, /* nothing */);
-		sh = __find_stripe(conf, sector);
+		sh = __find_stripe(conf, sector, disks);
 		if (!sh) {
 			if (!conf->inactive_blocked)
 				sh = get_free_stripe(conf);
@@ -259,11 +262,11 @@
 						     < (conf->max_nr_stripes *3/4)
 						     || !conf->inactive_blocked),
 						    conf->device_lock,
-						    unplug_slaves(conf->mddev);
+						    unplug_slaves(conf->mddev)
 					);
 				conf->inactive_blocked = 0;
 			} else
-				init_stripe(sh, sector, pd_idx);
+				init_stripe(sh, sector, pd_idx, disks);
 		} else {
 			if (atomic_read(&sh->count)) {
 				if (!list_empty(&sh->lru))
@@ -271,9 +274,8 @@
 			} else {
 				if (!test_bit(STRIPE_HANDLE, &sh->state))
 					atomic_inc(&conf->active_stripes);
-				if (list_empty(&sh->lru))
-					BUG();
-				list_del_init(&sh->lru);
+				if (!list_empty(&sh->lru))
+					list_del_init(&sh->lru);
 			}
 		}
 	} while (sh == NULL);
@@ -300,6 +302,7 @@
 		kmem_cache_free(conf->slab_cache, sh);
 		return 0;
 	}
+	sh->disks = conf->raid_disks;
 	/* we just created an active stripe so... */
 	atomic_set(&sh->count, 1);
 	atomic_inc(&conf->active_stripes);
@@ -313,14 +316,16 @@
 	kmem_cache_t *sc;
 	int devs = conf->raid_disks;
 
-	sprintf(conf->cache_name, "raid5/%s", mdname(conf->mddev));
-
-	sc = kmem_cache_create(conf->cache_name, 
+	sprintf(conf->cache_name[0], "raid5/%s", mdname(conf->mddev));
+	sprintf(conf->cache_name[1], "raid5/%s-alt", mdname(conf->mddev));
+	conf->active_name = 0;
+	sc = kmem_cache_create(conf->cache_name[conf->active_name],
 			       sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
 			       0, 0, NULL, NULL);
 	if (!sc)
 		return 1;
 	conf->slab_cache = sc;
+	conf->pool_size = devs;
 	while (num--) {
 		if (!grow_one_stripe(conf))
 			return 1;
@@ -328,6 +333,129 @@
 	return 0;
 }
 
+#ifdef CONFIG_MD_RAID5_RESHAPE
+static int resize_stripes(raid5_conf_t *conf, int newsize)
+{
+	/* Make all the stripes able to hold 'newsize' devices.
+	 * New slots in each stripe get 'page' set to a new page.
+	 *
+	 * This happens in stages:
+	 * 1/ create a new kmem_cache and allocate the required number of
+	 *    stripe_heads.
+	 * 2/ gather all the old stripe_heads and tranfer the pages across
+	 *    to the new stripe_heads.  This will have the side effect of
+	 *    freezing the array as once all stripe_heads have been collected,
+	 *    no IO will be possible.  Old stripe heads are freed once their
+	 *    pages have been transferred over, and the old kmem_cache is
+	 *    freed when all stripes are done.
+	 * 3/ reallocate conf->disks to be suitable bigger.  If this fails,
+	 *    we simple return a failre status - no need to clean anything up.
+	 * 4/ allocate new pages for the new slots in the new stripe_heads.
+	 *    If this fails, we don't bother trying the shrink the
+	 *    stripe_heads down again, we just leave them as they are.
+	 *    As each stripe_head is processed the new one is released into
+	 *    active service.
+	 *
+	 * Once step2 is started, we cannot afford to wait for a write,
+	 * so we use GFP_NOIO allocations.
+	 */
+	struct stripe_head *osh, *nsh;
+	LIST_HEAD(newstripes);
+	struct disk_info *ndisks;
+	int err = 0;
+	kmem_cache_t *sc;
+	int i;
+
+	if (newsize <= conf->pool_size)
+		return 0; /* never bother to shrink */
+
+	/* Step 1 */
+	sc = kmem_cache_create(conf->cache_name[1-conf->active_name],
+			       sizeof(struct stripe_head)+(newsize-1)*sizeof(struct r5dev),
+			       0, 0, NULL, NULL);
+	if (!sc)
+		return -ENOMEM;
+
+	for (i = conf->max_nr_stripes; i; i--) {
+		nsh = kmem_cache_alloc(sc, GFP_KERNEL);
+		if (!nsh)
+			break;
+
+		memset(nsh, 0, sizeof(*nsh) + (newsize-1)*sizeof(struct r5dev));
+
+		nsh->raid_conf = conf;
+		spin_lock_init(&nsh->lock);
+
+		list_add(&nsh->lru, &newstripes);
+	}
+	if (i) {
+		/* didn't get enough, give up */
+		while (!list_empty(&newstripes)) {
+			nsh = list_entry(newstripes.next, struct stripe_head, lru);
+			list_del(&nsh->lru);
+			kmem_cache_free(sc, nsh);
+		}
+		kmem_cache_destroy(sc);
+		return -ENOMEM;
+	}
+	/* Step 2 - Must use GFP_NOIO now.
+	 * OK, we have enough stripes, start collecting inactive
+	 * stripes and copying them over
+	 */
+	list_for_each_entry(nsh, &newstripes, lru) {
+		spin_lock_irq(&conf->device_lock);
+		wait_event_lock_irq(conf->wait_for_stripe,
+				    !list_empty(&conf->inactive_list),
+				    conf->device_lock,
+				    unplug_slaves(conf->mddev)
+			);
+		osh = get_free_stripe(conf);
+		spin_unlock_irq(&conf->device_lock);
+		atomic_set(&nsh->count, 1);
+		for(i=0; i<conf->pool_size; i++)
+			nsh->dev[i].page = osh->dev[i].page;
+		for( ; i<newsize; i++)
+			nsh->dev[i].page = NULL;
+		kmem_cache_free(conf->slab_cache, osh);
+	}
+	kmem_cache_destroy(conf->slab_cache);
+
+	/* Step 3.
+	 * At this point, we are holding all the stripes so the array
+	 * is completely stalled, so now is a good time to resize
+	 * conf->disks.
+	 */
+	ndisks = kzalloc(newsize * sizeof(struct disk_info), GFP_NOIO);
+	if (ndisks) {
+		for (i=0; i<conf->raid_disks; i++)
+			ndisks[i] = conf->disks[i];
+		kfree(conf->disks);
+		conf->disks = ndisks;
+	} else
+		err = -ENOMEM;
+
+	/* Step 4, return new stripes to service */
+	while(!list_empty(&newstripes)) {
+		nsh = list_entry(newstripes.next, struct stripe_head, lru);
+		list_del_init(&nsh->lru);
+		for (i=conf->raid_disks; i < newsize; i++)
+			if (nsh->dev[i].page == NULL) {
+				struct page *p = alloc_page(GFP_NOIO);
+				nsh->dev[i].page = p;
+				if (!p)
+					err = -ENOMEM;
+			}
+		release_stripe(nsh);
+	}
+	/* critical section pass, GFP_NOIO no longer needed */
+
+	conf->slab_cache = sc;
+	conf->active_name = 1-conf->active_name;
+	conf->pool_size = newsize;
+	return err;
+}
+#endif
+
 static int drop_one_stripe(raid5_conf_t *conf)
 {
 	struct stripe_head *sh;
@@ -339,7 +467,7 @@
 		return 0;
 	if (atomic_read(&sh->count))
 		BUG();
-	shrink_buffers(sh, conf->raid_disks);
+	shrink_buffers(sh, conf->pool_size);
 	kmem_cache_free(conf->slab_cache, sh);
 	atomic_dec(&conf->active_stripes);
 	return 1;
@@ -360,7 +488,7 @@
 {
  	struct stripe_head *sh = bi->bi_private;
 	raid5_conf_t *conf = sh->raid_conf;
-	int disks = conf->raid_disks, i;
+	int disks = sh->disks, i;
 	int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
 
 	if (bi->bi_size)
@@ -458,7 +586,7 @@
 {
  	struct stripe_head *sh = bi->bi_private;
 	raid5_conf_t *conf = sh->raid_conf;
-	int disks = conf->raid_disks, i;
+	int disks = sh->disks, i;
 	unsigned long flags;
 	int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
 
@@ -612,7 +740,7 @@
 static sector_t compute_blocknr(struct stripe_head *sh, int i)
 {
 	raid5_conf_t *conf = sh->raid_conf;
-	int raid_disks = conf->raid_disks, data_disks = raid_disks - 1;
+	int raid_disks = sh->disks, data_disks = raid_disks - 1;
 	sector_t new_sector = sh->sector, check;
 	int sectors_per_chunk = conf->chunk_size >> 9;
 	sector_t stripe;
@@ -713,8 +841,7 @@
 
 static void compute_block(struct stripe_head *sh, int dd_idx)
 {
-	raid5_conf_t *conf = sh->raid_conf;
-	int i, count, disks = conf->raid_disks;
+	int i, count, disks = sh->disks;
 	void *ptr[MAX_XOR_BLOCKS], *p;
 
 	PRINTK("compute_block, stripe %llu, idx %d\n", 
@@ -744,7 +871,7 @@
 static void compute_parity(struct stripe_head *sh, int method)
 {
 	raid5_conf_t *conf = sh->raid_conf;
-	int i, pd_idx = sh->pd_idx, disks = conf->raid_disks, count;
+	int i, pd_idx = sh->pd_idx, disks = sh->disks, count;
 	void *ptr[MAX_XOR_BLOCKS];
 	struct bio *chosen;
 
@@ -910,6 +1037,20 @@
 	return 0;
 }
 
+static void end_reshape(raid5_conf_t *conf);
+
+static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks)
+{
+	int sectors_per_chunk = conf->chunk_size >> 9;
+	sector_t x = stripe;
+	int pd_idx, dd_idx;
+	int chunk_offset = sector_div(x, sectors_per_chunk);
+	stripe = x;
+	raid5_compute_sector(stripe*(disks-1)*sectors_per_chunk
+			     + chunk_offset, disks, disks-1, &dd_idx, &pd_idx, conf);
+	return pd_idx;
+}
+
 
 /*
  * handle_stripe - do things to a stripe.
@@ -932,11 +1073,11 @@
 static void handle_stripe(struct stripe_head *sh)
 {
 	raid5_conf_t *conf = sh->raid_conf;
-	int disks = conf->raid_disks;
+	int disks = sh->disks;
 	struct bio *return_bi= NULL;
 	struct bio *bi;
 	int i;
-	int syncing;
+	int syncing, expanding, expanded;
 	int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0;
 	int non_overwrite = 0;
 	int failed_num=0;
@@ -951,6 +1092,8 @@
 	clear_bit(STRIPE_DELAYED, &sh->state);
 
 	syncing = test_bit(STRIPE_SYNCING, &sh->state);
+	expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state);
+	expanded = test_bit(STRIPE_EXPAND_READY, &sh->state);
 	/* Now to look around and see what can be done */
 
 	rcu_read_lock();
@@ -1143,13 +1286,14 @@
 	 * parity, or to satisfy requests
 	 * or to load a block that is being partially written.
 	 */
-	if (to_read || non_overwrite || (syncing && (uptodate < disks))) {
+	if (to_read || non_overwrite || (syncing && (uptodate < disks)) || expanding) {
 		for (i=disks; i--;) {
 			dev = &sh->dev[i];
 			if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
 			    (dev->toread ||
 			     (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
 			     syncing ||
+			     expanding ||
 			     (failed && (sh->dev[failed_num].toread ||
 					 (sh->dev[failed_num].towrite && !test_bit(R5_OVERWRITE, &sh->dev[failed_num].flags))))
 				    )
@@ -1339,13 +1483,77 @@
 			set_bit(R5_Wantwrite, &dev->flags);
 			set_bit(R5_ReWrite, &dev->flags);
 			set_bit(R5_LOCKED, &dev->flags);
+			locked++;
 		} else {
 			/* let's read it back */
 			set_bit(R5_Wantread, &dev->flags);
 			set_bit(R5_LOCKED, &dev->flags);
+			locked++;
 		}
 	}
 
+	if (expanded && test_bit(STRIPE_EXPANDING, &sh->state)) {
+		/* Need to write out all blocks after computing parity */
+		sh->disks = conf->raid_disks;
+		sh->pd_idx = stripe_to_pdidx(sh->sector, conf, conf->raid_disks);
+		compute_parity(sh, RECONSTRUCT_WRITE);
+		for (i= conf->raid_disks; i--;) {
+			set_bit(R5_LOCKED, &sh->dev[i].flags);
+			locked++;
+			set_bit(R5_Wantwrite, &sh->dev[i].flags);
+		}
+		clear_bit(STRIPE_EXPANDING, &sh->state);
+	} else if (expanded) {
+		clear_bit(STRIPE_EXPAND_READY, &sh->state);
+		atomic_dec(&conf->reshape_stripes);
+		wake_up(&conf->wait_for_overlap);
+		md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
+	}
+
+	if (expanding && locked == 0) {
+		/* We have read all the blocks in this stripe and now we need to
+		 * copy some of them into a target stripe for expand.
+		 */
+		clear_bit(STRIPE_EXPAND_SOURCE, &sh->state);
+		for (i=0; i< sh->disks; i++)
+			if (i != sh->pd_idx) {
+				int dd_idx, pd_idx, j;
+				struct stripe_head *sh2;
+
+				sector_t bn = compute_blocknr(sh, i);
+				sector_t s = raid5_compute_sector(bn, conf->raid_disks,
+								  conf->raid_disks-1,
+								  &dd_idx, &pd_idx, conf);
+				sh2 = get_active_stripe(conf, s, conf->raid_disks, pd_idx, 1);
+				if (sh2 == NULL)
+					/* so far only the early blocks of this stripe
+					 * have been requested.  When later blocks
+					 * get requested, we will try again
+					 */
+					continue;
+				if(!test_bit(STRIPE_EXPANDING, &sh2->state) ||
+				   test_bit(R5_Expanded, &sh2->dev[dd_idx].flags)) {
+					/* must have already done this block */
+					release_stripe(sh2);
+					continue;
+				}
+				memcpy(page_address(sh2->dev[dd_idx].page),
+				       page_address(sh->dev[i].page),
+				       STRIPE_SIZE);
+				set_bit(R5_Expanded, &sh2->dev[dd_idx].flags);
+				set_bit(R5_UPTODATE, &sh2->dev[dd_idx].flags);
+				for (j=0; j<conf->raid_disks; j++)
+					if (j != sh2->pd_idx &&
+					    !test_bit(R5_Expanded, &sh2->dev[j].flags))
+						break;
+				if (j == conf->raid_disks) {
+					set_bit(STRIPE_EXPAND_READY, &sh2->state);
+					set_bit(STRIPE_HANDLE, &sh2->state);
+				}
+				release_stripe(sh2);
+			}
+	}
+
 	spin_unlock(&sh->lock);
 
 	while ((bi=return_bi)) {
@@ -1384,7 +1592,7 @@
 		rcu_read_unlock();
  
 		if (rdev) {
-			if (syncing)
+			if (syncing || expanding || expanded)
 				md_sync_acct(rdev->bdev, STRIPE_SECTORS);
 
 			bi->bi_bdev = rdev->bdev;
@@ -1526,17 +1734,16 @@
 	spin_unlock_irq(&conf->device_lock);
 }
 
-static int make_request (request_queue_t *q, struct bio * bi)
+static int make_request(request_queue_t *q, struct bio * bi)
 {
 	mddev_t *mddev = q->queuedata;
 	raid5_conf_t *conf = mddev_to_conf(mddev);
-	const unsigned int raid_disks = conf->raid_disks;
-	const unsigned int data_disks = raid_disks - 1;
 	unsigned int dd_idx, pd_idx;
 	sector_t new_sector;
 	sector_t logical_sector, last_sector;
 	struct stripe_head *sh;
 	const int rw = bio_data_dir(bi);
+	int remaining;
 
 	if (unlikely(bio_barrier(bi))) {
 		bio_endio(bi, bi->bi_size, -EOPNOTSUPP);
@@ -1555,20 +1762,77 @@
 
 	for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
 		DEFINE_WAIT(w);
-		
-		new_sector = raid5_compute_sector(logical_sector,
-						  raid_disks, data_disks, &dd_idx, &pd_idx, conf);
+		int disks;
 
+	retry:
+		prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
+		if (likely(conf->expand_progress == MaxSector))
+			disks = conf->raid_disks;
+		else {
+			/* spinlock is needed as expand_progress may be
+			 * 64bit on a 32bit platform, and so it might be
+			 * possible to see a half-updated value
+			 * Ofcourse expand_progress could change after
+			 * the lock is dropped, so once we get a reference
+			 * to the stripe that we think it is, we will have
+			 * to check again.
+			 */
+			spin_lock_irq(&conf->device_lock);
+			disks = conf->raid_disks;
+			if (logical_sector >= conf->expand_progress)
+				disks = conf->previous_raid_disks;
+			else {
+				if (logical_sector >= conf->expand_lo) {
+					spin_unlock_irq(&conf->device_lock);
+					schedule();
+					goto retry;
+				}
+			}
+			spin_unlock_irq(&conf->device_lock);
+		}
+ 		new_sector = raid5_compute_sector(logical_sector, disks, disks - 1,
+						  &dd_idx, &pd_idx, conf);
 		PRINTK("raid5: make_request, sector %llu logical %llu\n",
 			(unsigned long long)new_sector, 
 			(unsigned long long)logical_sector);
 
-	retry:
-		prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
-		sh = get_active_stripe(conf, new_sector, pd_idx, (bi->bi_rw&RWA_MASK));
+		sh = get_active_stripe(conf, new_sector, disks, pd_idx, (bi->bi_rw&RWA_MASK));
 		if (sh) {
-			if (!add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK))) {
-				/* Add failed due to overlap.  Flush everything
+			if (unlikely(conf->expand_progress != MaxSector)) {
+				/* expansion might have moved on while waiting for a
+				 * stripe, so we must do the range check again.
+				 * Expansion could still move past after this
+				 * test, but as we are holding a reference to
+				 * 'sh', we know that if that happens,
+				 *  STRIPE_EXPANDING will get set and the expansion
+				 * won't proceed until we finish with the stripe.
+				 */
+				int must_retry = 0;
+				spin_lock_irq(&conf->device_lock);
+				if (logical_sector <  conf->expand_progress &&
+				    disks == conf->previous_raid_disks)
+					/* mismatch, need to try again */
+					must_retry = 1;
+				spin_unlock_irq(&conf->device_lock);
+				if (must_retry) {
+					release_stripe(sh);
+					goto retry;
+				}
+			}
+			/* FIXME what if we get a false positive because these
+			 * are being updated.
+			 */
+			if (logical_sector >= mddev->suspend_lo &&
+			    logical_sector < mddev->suspend_hi) {
+				release_stripe(sh);
+				schedule();
+				goto retry;
+			}
+
+			if (test_bit(STRIPE_EXPANDING, &sh->state) ||
+			    !add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK))) {
+				/* Stripe is busy expanding or
+				 * add failed due to overlap.  Flush everything
 				 * and wait a while
 				 */
 				raid5_unplug_device(mddev->queue);
@@ -1580,7 +1844,6 @@
 			raid5_plug_device(conf);
 			handle_stripe(sh);
 			release_stripe(sh);
-
 		} else {
 			/* cannot get stripe for read-ahead, just give-up */
 			clear_bit(BIO_UPTODATE, &bi->bi_flags);
@@ -1590,7 +1853,9 @@
 			
 	}
 	spin_lock_irq(&conf->device_lock);
-	if (--bi->bi_phys_segments == 0) {
+	remaining = --bi->bi_phys_segments;
+	spin_unlock_irq(&conf->device_lock);
+	if (remaining == 0) {
 		int bytes = bi->bi_size;
 
 		if ( bio_data_dir(bi) == WRITE )
@@ -1598,7 +1863,6 @@
 		bi->bi_size = 0;
 		bi->bi_end_io(bi, bytes, 0);
 	}
-	spin_unlock_irq(&conf->device_lock);
 	return 0;
 }
 
@@ -1607,12 +1871,8 @@
 {
 	raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
 	struct stripe_head *sh;
-	int sectors_per_chunk = conf->chunk_size >> 9;
-	sector_t x;
-	unsigned long stripe;
-	int chunk_offset;
-	int dd_idx, pd_idx;
-	sector_t first_sector;
+	int pd_idx;
+	sector_t first_sector, last_sector;
 	int raid_disks = conf->raid_disks;
 	int data_disks = raid_disks-1;
 	sector_t max_sector = mddev->size << 1;
@@ -1621,6 +1881,10 @@
 	if (sector_nr >= max_sector) {
 		/* just being told to finish up .. nothing much to do */
 		unplug_slaves(mddev);
+		if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) {
+			end_reshape(conf);
+			return 0;
+		}
 
 		if (mddev->curr_resync < max_sector) /* aborted */
 			bitmap_end_sync(mddev->bitmap, mddev->curr_resync,
@@ -1631,6 +1895,123 @@
 
 		return 0;
 	}
+
+	if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) {
+		/* reshaping is quite different to recovery/resync so it is
+		 * handled quite separately ... here.
+		 *
+		 * On each call to sync_request, we gather one chunk worth of
+		 * destination stripes and flag them as expanding.
+		 * Then we find all the source stripes and request reads.
+		 * As the reads complete, handle_stripe will copy the data
+		 * into the destination stripe and release that stripe.
+		 */
+		int i;
+		int dd_idx;
+		sector_t writepos, safepos, gap;
+
+		if (sector_nr == 0 &&
+		    conf->expand_progress != 0) {
+			/* restarting in the middle, skip the initial sectors */
+			sector_nr = conf->expand_progress;
+			sector_div(sector_nr, conf->raid_disks-1);
+			*skipped = 1;
+			return sector_nr;
+		}
+
+		/* we update the metadata when there is more than 3Meg
+		 * in the block range (that is rather arbitrary, should
+		 * probably be time based) or when the data about to be
+		 * copied would over-write the source of the data at
+		 * the front of the range.
+		 * i.e. one new_stripe forward from expand_progress new_maps
+		 * to after where expand_lo old_maps to
+		 */
+		writepos = conf->expand_progress +
+			conf->chunk_size/512*(conf->raid_disks-1);
+		sector_div(writepos, conf->raid_disks-1);
+		safepos = conf->expand_lo;
+		sector_div(safepos, conf->previous_raid_disks-1);
+		gap = conf->expand_progress - conf->expand_lo;
+
+		if (writepos >= safepos ||
+		    gap > (conf->raid_disks-1)*3000*2 /*3Meg*/) {
+			/* Cannot proceed until we've updated the superblock... */
+			wait_event(conf->wait_for_overlap,
+				   atomic_read(&conf->reshape_stripes)==0);
+			mddev->reshape_position = conf->expand_progress;
+			mddev->sb_dirty = 1;
+			md_wakeup_thread(mddev->thread);
+			wait_event(mddev->sb_wait, mddev->sb_dirty == 0 ||
+				   kthread_should_stop());
+			spin_lock_irq(&conf->device_lock);
+			conf->expand_lo = mddev->reshape_position;
+			spin_unlock_irq(&conf->device_lock);
+			wake_up(&conf->wait_for_overlap);
+		}
+
+		for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) {
+			int j;
+			int skipped = 0;
+			pd_idx = stripe_to_pdidx(sector_nr+i, conf, conf->raid_disks);
+			sh = get_active_stripe(conf, sector_nr+i,
+					       conf->raid_disks, pd_idx, 0);
+			set_bit(STRIPE_EXPANDING, &sh->state);
+			atomic_inc(&conf->reshape_stripes);
+			/* If any of this stripe is beyond the end of the old
+			 * array, then we need to zero those blocks
+			 */
+			for (j=sh->disks; j--;) {
+				sector_t s;
+				if (j == sh->pd_idx)
+					continue;
+				s = compute_blocknr(sh, j);
+				if (s < (mddev->array_size<<1)) {
+					skipped = 1;
+					continue;
+				}
+				memset(page_address(sh->dev[j].page), 0, STRIPE_SIZE);
+				set_bit(R5_Expanded, &sh->dev[j].flags);
+				set_bit(R5_UPTODATE, &sh->dev[j].flags);
+			}
+			if (!skipped) {
+				set_bit(STRIPE_EXPAND_READY, &sh->state);
+				set_bit(STRIPE_HANDLE, &sh->state);
+			}
+			release_stripe(sh);
+		}
+		spin_lock_irq(&conf->device_lock);
+		conf->expand_progress = (sector_nr + i)*(conf->raid_disks-1);
+		spin_unlock_irq(&conf->device_lock);
+		/* Ok, those stripe are ready. We can start scheduling
+		 * reads on the source stripes.
+		 * The source stripes are determined by mapping the first and last
+		 * block on the destination stripes.
+		 */
+		raid_disks = conf->previous_raid_disks;
+		data_disks = raid_disks - 1;
+		first_sector =
+			raid5_compute_sector(sector_nr*(conf->raid_disks-1),
+					     raid_disks, data_disks,
+					     &dd_idx, &pd_idx, conf);
+		last_sector =
+			raid5_compute_sector((sector_nr+conf->chunk_size/512)
+					       *(conf->raid_disks-1) -1,
+					     raid_disks, data_disks,
+					     &dd_idx, &pd_idx, conf);
+		if (last_sector >= (mddev->size<<1))
+			last_sector = (mddev->size<<1)-1;
+		while (first_sector <= last_sector) {
+			pd_idx = stripe_to_pdidx(first_sector, conf, conf->previous_raid_disks);
+			sh = get_active_stripe(conf, first_sector,
+					       conf->previous_raid_disks, pd_idx, 0);
+			set_bit(STRIPE_EXPAND_SOURCE, &sh->state);
+			set_bit(STRIPE_HANDLE, &sh->state);
+			release_stripe(sh);
+			first_sector += STRIPE_SECTORS;
+		}
+		return conf->chunk_size>>9;
+	}
 	/* if there is 1 or more failed drives and we are trying
 	 * to resync, then assert that we are finished, because there is
 	 * nothing we can do.
@@ -1649,16 +2030,10 @@
 		return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */
 	}
 
-	x = sector_nr;
-	chunk_offset = sector_div(x, sectors_per_chunk);
-	stripe = x;
-	BUG_ON(x != stripe);
-
-	first_sector = raid5_compute_sector((sector_t)stripe*data_disks*sectors_per_chunk
-		+ chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf);
-	sh = get_active_stripe(conf, sector_nr, pd_idx, 1);
+	pd_idx = stripe_to_pdidx(sector_nr, conf, raid_disks);
+	sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 1);
 	if (sh == NULL) {
-		sh = get_active_stripe(conf, sector_nr, pd_idx, 0);
+		sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 0);
 		/* make sure we don't swamp the stripe cache if someone else
 		 * is trying to get access 
 		 */
@@ -1822,11 +2197,64 @@
 		return -EIO;
 	}
 
-	mddev->private = kzalloc(sizeof (raid5_conf_t)
-				 + mddev->raid_disks * sizeof(struct disk_info),
-				 GFP_KERNEL);
+	if (mddev->reshape_position != MaxSector) {
+		/* Check that we can continue the reshape.
+		 * Currently only disks can change, it must
+		 * increase, and we must be past the point where
+		 * a stripe over-writes itself
+		 */
+		sector_t here_new, here_old;
+		int old_disks;
+
+		if (mddev->new_level != mddev->level ||
+		    mddev->new_layout != mddev->layout ||
+		    mddev->new_chunk != mddev->chunk_size) {
+			printk(KERN_ERR "raid5: %s: unsupported reshape required - aborting.\n",
+			       mdname(mddev));
+			return -EINVAL;
+		}
+		if (mddev->delta_disks <= 0) {
+			printk(KERN_ERR "raid5: %s: unsupported reshape (reduce disks) required - aborting.\n",
+			       mdname(mddev));
+			return -EINVAL;
+		}
+		old_disks = mddev->raid_disks - mddev->delta_disks;
+		/* reshape_position must be on a new-stripe boundary, and one
+		 * further up in new geometry must map after here in old geometry.
+		 */
+		here_new = mddev->reshape_position;
+		if (sector_div(here_new, (mddev->chunk_size>>9)*(mddev->raid_disks-1))) {
+			printk(KERN_ERR "raid5: reshape_position not on a stripe boundary\n");
+			return -EINVAL;
+		}
+		/* here_new is the stripe we will write to */
+		here_old = mddev->reshape_position;
+		sector_div(here_old, (mddev->chunk_size>>9)*(old_disks-1));
+		/* here_old is the first stripe that we might need to read from */
+		if (here_new >= here_old) {
+			/* Reading from the same stripe as writing to - bad */
+			printk(KERN_ERR "raid5: reshape_position too early for auto-recovery - aborting.\n");
+			return -EINVAL;
+		}
+		printk(KERN_INFO "raid5: reshape will continue\n");
+		/* OK, we should be able to continue; */
+	}
+
+
+	mddev->private = kzalloc(sizeof (raid5_conf_t), GFP_KERNEL);
 	if ((conf = mddev->private) == NULL)
 		goto abort;
+	if (mddev->reshape_position == MaxSector) {
+		conf->previous_raid_disks = conf->raid_disks = mddev->raid_disks;
+	} else {
+		conf->raid_disks = mddev->raid_disks;
+		conf->previous_raid_disks = mddev->raid_disks - mddev->delta_disks;
+	}
+
+	conf->disks = kzalloc(conf->raid_disks * sizeof(struct disk_info),
+			      GFP_KERNEL);
+	if (!conf->disks)
+		goto abort;
 
 	conf->mddev = mddev;
 
@@ -1847,7 +2275,7 @@
 
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		raid_disk = rdev->raid_disk;
-		if (raid_disk >= mddev->raid_disks
+		if (raid_disk >= conf->raid_disks
 		    || raid_disk < 0)
 			continue;
 		disk = conf->disks + raid_disk;
@@ -1863,7 +2291,6 @@
 		}
 	}
 
-	conf->raid_disks = mddev->raid_disks;
 	/*
 	 * 0 for a fully functional array, 1 for a degraded array.
 	 */
@@ -1873,6 +2300,7 @@
 	conf->level = mddev->level;
 	conf->algorithm = mddev->layout;
 	conf->max_nr_stripes = NR_STRIPES;
+	conf->expand_progress = mddev->reshape_position;
 
 	/* device size must be a multiple of chunk size */
 	mddev->size &= ~(mddev->chunk_size/1024 -1);
@@ -1945,6 +2373,21 @@
 
 	print_raid5_conf(conf);
 
+	if (conf->expand_progress != MaxSector) {
+		printk("...ok start reshape thread\n");
+		conf->expand_lo = conf->expand_progress;
+		atomic_set(&conf->reshape_stripes, 0);
+		clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+		clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+		set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
+		set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+		mddev->sync_thread = md_register_thread(md_do_sync, mddev,
+							"%s_reshape");
+		/* FIXME if md_register_thread fails?? */
+		md_wakeup_thread(mddev->sync_thread);
+
+	}
+
 	/* read-ahead size must cover two whole stripes, which is
 	 * 2 * (n-1) * chunksize where 'n' is the number of raid devices
 	 */
@@ -1960,12 +2403,13 @@
 
 	mddev->queue->unplug_fn = raid5_unplug_device;
 	mddev->queue->issue_flush_fn = raid5_issue_flush;
+	mddev->array_size =  mddev->size * (conf->previous_raid_disks - 1);
 
-	mddev->array_size =  mddev->size * (mddev->raid_disks - 1);
 	return 0;
 abort:
 	if (conf) {
 		print_raid5_conf(conf);
+		kfree(conf->disks);
 		kfree(conf->stripe_hashtbl);
 		kfree(conf);
 	}
@@ -1986,6 +2430,7 @@
 	kfree(conf->stripe_hashtbl);
 	blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
 	sysfs_remove_group(&mddev->kobj, &raid5_attrs_group);
+	kfree(conf->disks);
 	kfree(conf);
 	mddev->private = NULL;
 	return 0;
@@ -2001,7 +2446,7 @@
 	printk("sh %llu,  count %d.\n",
 		(unsigned long long)sh->sector, atomic_read(&sh->count));
 	printk("sh %llu, ", (unsigned long long)sh->sector);
-	for (i = 0; i < sh->raid_conf->raid_disks; i++) {
+	for (i = 0; i < sh->disks; i++) {
 		printk("(cache%d: %p %ld) ", 
 			i, sh->dev[i].page, sh->dev[i].flags);
 	}
@@ -2132,7 +2577,7 @@
 	/*
 	 * find the disk ...
 	 */
-	for (disk=0; disk < mddev->raid_disks; disk++)
+	for (disk=0; disk < conf->raid_disks; disk++)
 		if ((p=conf->disks + disk)->rdev == NULL) {
 			clear_bit(In_sync, &rdev->flags);
 			rdev->raid_disk = disk;
@@ -2168,11 +2613,146 @@
 	return 0;
 }
 
+#ifdef CONFIG_MD_RAID5_RESHAPE
+static int raid5_check_reshape(mddev_t *mddev)
+{
+	raid5_conf_t *conf = mddev_to_conf(mddev);
+	int err;
+
+	if (mddev->delta_disks < 0 ||
+	    mddev->new_level != mddev->level)
+		return -EINVAL; /* Cannot shrink array or change level yet */
+	if (mddev->delta_disks == 0)
+		return 0; /* nothing to do */
+
+	/* Can only proceed if there are plenty of stripe_heads.
+	 * We need a minimum of one full stripe,, and for sensible progress
+	 * it is best to have about 4 times that.
+	 * If we require 4 times, then the default 256 4K stripe_heads will
+	 * allow for chunk sizes up to 256K, which is probably OK.
+	 * If the chunk size is greater, user-space should request more
+	 * stripe_heads first.
+	 */
+	if ((mddev->chunk_size / STRIPE_SIZE) * 4 > conf->max_nr_stripes ||
+	    (mddev->new_chunk / STRIPE_SIZE) * 4 > conf->max_nr_stripes) {
+		printk(KERN_WARNING "raid5: reshape: not enough stripes.  Needed %lu\n",
+		       (mddev->chunk_size / STRIPE_SIZE)*4);
+		return -ENOSPC;
+	}
+
+	err = resize_stripes(conf, conf->raid_disks + mddev->delta_disks);
+	if (err)
+		return err;
+
+	/* looks like we might be able to manage this */
+	return 0;
+}
+
+static int raid5_start_reshape(mddev_t *mddev)
+{
+	raid5_conf_t *conf = mddev_to_conf(mddev);
+	mdk_rdev_t *rdev;
+	struct list_head *rtmp;
+	int spares = 0;
+	int added_devices = 0;
+
+	if (mddev->degraded ||
+	    test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+		return -EBUSY;
+
+	ITERATE_RDEV(mddev, rdev, rtmp)
+		if (rdev->raid_disk < 0 &&
+		    !test_bit(Faulty, &rdev->flags))
+			spares++;
+
+	if (spares < mddev->delta_disks-1)
+		/* Not enough devices even to make a degraded array
+		 * of that size
+		 */
+		return -EINVAL;
+
+	atomic_set(&conf->reshape_stripes, 0);
+	spin_lock_irq(&conf->device_lock);
+	conf->previous_raid_disks = conf->raid_disks;
+	conf->raid_disks += mddev->delta_disks;
+	conf->expand_progress = 0;
+	conf->expand_lo = 0;
+	spin_unlock_irq(&conf->device_lock);
+
+	/* Add some new drives, as many as will fit.
+	 * We know there are enough to make the newly sized array work.
+	 */
+	ITERATE_RDEV(mddev, rdev, rtmp)
+		if (rdev->raid_disk < 0 &&
+		    !test_bit(Faulty, &rdev->flags)) {
+			if (raid5_add_disk(mddev, rdev)) {
+				char nm[20];
+				set_bit(In_sync, &rdev->flags);
+				conf->working_disks++;
+				added_devices++;
+				sprintf(nm, "rd%d", rdev->raid_disk);
+				sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
+			} else
+				break;
+		}
+
+	mddev->degraded = (conf->raid_disks - conf->previous_raid_disks) - added_devices;
+	mddev->raid_disks = conf->raid_disks;
+	mddev->reshape_position = 0;
+	mddev->sb_dirty = 1;
+
+	clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+	clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+	set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
+	set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+	mddev->sync_thread = md_register_thread(md_do_sync, mddev,
+						"%s_reshape");
+	if (!mddev->sync_thread) {
+		mddev->recovery = 0;
+		spin_lock_irq(&conf->device_lock);
+		mddev->raid_disks = conf->raid_disks = conf->previous_raid_disks;
+		conf->expand_progress = MaxSector;
+		spin_unlock_irq(&conf->device_lock);
+		return -EAGAIN;
+	}
+	md_wakeup_thread(mddev->sync_thread);
+	md_new_event(mddev);
+	return 0;
+}
+#endif
+
+static void end_reshape(raid5_conf_t *conf)
+{
+	struct block_device *bdev;
+
+	if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) {
+		conf->mddev->array_size = conf->mddev->size * (conf->raid_disks-1);
+		set_capacity(conf->mddev->gendisk, conf->mddev->array_size << 1);
+		conf->mddev->changed = 1;
+
+		bdev = bdget_disk(conf->mddev->gendisk, 0);
+		if (bdev) {
+			mutex_lock(&bdev->bd_inode->i_mutex);
+			i_size_write(bdev->bd_inode, conf->mddev->array_size << 10);
+			mutex_unlock(&bdev->bd_inode->i_mutex);
+			bdput(bdev);
+		}
+		spin_lock_irq(&conf->device_lock);
+		conf->expand_progress = MaxSector;
+		spin_unlock_irq(&conf->device_lock);
+		conf->mddev->reshape_position = MaxSector;
+	}
+}
+
 static void raid5_quiesce(mddev_t *mddev, int state)
 {
 	raid5_conf_t *conf = mddev_to_conf(mddev);
 
 	switch(state) {
+	case 2: /* resume for a suspend */
+		wake_up(&conf->wait_for_overlap);
+		break;
+
 	case 1: /* stop all writes */
 		spin_lock_irq(&conf->device_lock);
 		conf->quiesce = 1;
@@ -2186,6 +2766,7 @@
 		spin_lock_irq(&conf->device_lock);
 		conf->quiesce = 0;
 		wake_up(&conf->wait_for_stripe);
+		wake_up(&conf->wait_for_overlap);
 		spin_unlock_irq(&conf->device_lock);
 		break;
 	}
@@ -2206,6 +2787,10 @@
 	.spare_active	= raid5_spare_active,
 	.sync_request	= sync_request,
 	.resize		= raid5_resize,
+#ifdef CONFIG_MD_RAID5_RESHAPE
+	.check_reshape	= raid5_check_reshape,
+	.start_reshape  = raid5_start_reshape,
+#endif
 	.quiesce	= raid5_quiesce,
 };
 
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c
index cd477eb..ab64b37 100644
--- a/drivers/md/raid6main.c
+++ b/drivers/md/raid6main.c
@@ -331,9 +331,9 @@
 	kmem_cache_t *sc;
 	int devs = conf->raid_disks;
 
-	sprintf(conf->cache_name, "raid6/%s", mdname(conf->mddev));
+	sprintf(conf->cache_name[0], "raid6/%s", mdname(conf->mddev));
 
-	sc = kmem_cache_create(conf->cache_name,
+	sc = kmem_cache_create(conf->cache_name[0],
 			       sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
 			       0, 0, NULL, NULL);
 	if (!sc)
@@ -2006,11 +2006,14 @@
 		return -EIO;
 	}
 
-	mddev->private = kzalloc(sizeof (raid6_conf_t)
-				 + mddev->raid_disks * sizeof(struct disk_info),
-				 GFP_KERNEL);
+	mddev->private = kzalloc(sizeof (raid6_conf_t), GFP_KERNEL);
 	if ((conf = mddev->private) == NULL)
 		goto abort;
+	conf->disks = kzalloc(mddev->raid_disks * sizeof(struct disk_info),
+				 GFP_KERNEL);
+	if (!conf->disks)
+		goto abort;
+
 	conf->mddev = mddev;
 
 	if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
@@ -2148,6 +2151,8 @@
 	}
 
 	/* Ok, everything is just fine now */
+	sysfs_create_group(&mddev->kobj, &raid6_attrs_group);
+
 	mddev->array_size =  mddev->size * (mddev->raid_disks - 2);
 
 	mddev->queue->unplug_fn = raid6_unplug_device;
@@ -2158,6 +2163,7 @@
 		print_raid6_conf(conf);
 		safe_put_page(conf->spare_page);
 		kfree(conf->stripe_hashtbl);
+		kfree(conf->disks);
 		kfree(conf);
 	}
 	mddev->private = NULL;
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 54f8b95..96fe0ec 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -86,7 +86,7 @@
 
 	if (dvbdev && dvbdev->fops) {
 		int err = 0;
-		struct file_operations *old_fops;
+		const struct file_operations *old_fops;
 
 		file->private_data = dvbdev;
 		old_fops = file->f_op;
diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c
index 3021f21..0b00e60 100644
--- a/drivers/media/video/cpia_pp.c
+++ b/drivers/media/video/cpia_pp.c
@@ -873,7 +873,7 @@
 		parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE;
 	}
 
-	return 0;
+	return 1;
 }
 
 __setup("cpia_pp=", cpia_pp_setup);
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index 522e9dd..d9e3cad 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -2156,7 +2156,7 @@
 	struct pci_dev 		*pdev;
 	int rc;
 
-	if (_machine != _MACH_Pmac)
+	if (!machine_is(powermac))
 		return 0;
 
 	planb_devices = find_devices("planb");
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 75e3d41..5f87dd5 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -97,7 +97,7 @@
 	unsigned int minor = iminor(inode);
 	int err = 0;
 	struct video_device *vfl;
-	struct file_operations *old_fops;
+	const struct file_operations *old_fops;
 
 	if(minor>=VIDEO_NUM_DEVICES)
 		return -ENODEV;
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index b09fb63..7d4c549 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -1179,10 +1179,9 @@
 		goto exit;
 	}
 
-	i2o_blk_req_pool.pool = mempool_create(I2O_BLOCK_REQ_MEMPOOL_SIZE,
-					       mempool_alloc_slab,
-					       mempool_free_slab,
-					       i2o_blk_req_pool.slab);
+	i2o_blk_req_pool.pool =
+		mempool_create_slab_pool(I2O_BLOCK_REQ_MEMPOOL_SIZE,
+					 i2o_blk_req_pool.slab);
 	if (!i2o_blk_req_pool.pool) {
 		osm_err("can't init request mempool\n");
 		rc = -ENOMEM;
diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c
index 2a0c42b..3d2e76e 100644
--- a/drivers/message/i2o/i2o_proc.c
+++ b/drivers/message/i2o/i2o_proc.c
@@ -56,7 +56,7 @@
 typedef struct _i2o_proc_entry_t {
 	char *name;		/* entry name */
 	mode_t mode;		/* mode */
-	struct file_operations *fops;	/* open function */
+	const struct file_operations *fops;	/* open function */
 } i2o_proc_entry;
 
 /* global I2O /proc/i2o entry */
diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c
index f295401..7fd7a43 100644
--- a/drivers/misc/ibmasm/heartbeat.c
+++ b/drivers/misc/ibmasm/heartbeat.c
@@ -52,12 +52,13 @@
 
 void ibmasm_register_panic_notifier(void)
 {
-	notifier_chain_register(&panic_notifier_list, &panic_notifier);
+	atomic_notifier_chain_register(&panic_notifier_list, &panic_notifier);
 }
 
 void ibmasm_unregister_panic_notifier(void)
 {
-	notifier_chain_unregister(&panic_notifier_list, &panic_notifier);
+	atomic_notifier_chain_unregister(&panic_notifier_list,
+			&panic_notifier);
 }
 
 
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index 5c550fc..26a230b 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -101,7 +101,7 @@
 	.drop_inode	= generic_delete_inode,
 };
 
-static struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations;
+static const struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations;
 
 static struct file_system_type ibmasmfs_type = {
 	.owner          = THIS_MODULE,
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index 205bb70..0f6bb2e 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -25,9 +25,8 @@
 	  compatible with the Common Flash Interface, but will use the common
 	  CFI-targetted flash drivers for any chips which are identified which
 	  are in fact compatible in all but the probe method. This actually
-	  covers most AMD/Fujitsu-compatible chips, and will shortly cover also
-	  non-CFI Intel chips (that code is in MTD CVS and should shortly be sent
-	  for inclusion in Linus' tree)
+	  covers most AMD/Fujitsu-compatible chips and also non-CFI
+	  Intel chips.
 
 config MTD_GEN_PROBE
 	tristate
diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
index fdb91b6..5711561 100644
--- a/drivers/mtd/chips/amd_flash.c
+++ b/drivers/mtd/chips/amd_flash.c
@@ -664,7 +664,7 @@
 	printk("%s: Probing for AMD compatible flash...\n", map->name);
 
 	if ((table_pos[0] = probe_new_chip(mtd, 0, NULL, &temp, table,
-					   sizeof(table)/sizeof(table[0])))
+					   ARRAY_SIZE(table)))
 	    == -1) {
 		printk(KERN_WARNING
 		       "%s: Found no AMD compatible device at location zero\n",
@@ -696,7 +696,7 @@
 	     base += (1 << temp.chipshift)) {
 	     	int numchips = temp.numchips;
 		table_pos[numchips] = probe_new_chip(mtd, base, chips,
-			&temp, table, sizeof(table)/sizeof(table[0]));
+			&temp, table, ARRAY_SIZE(table));
 	}
 
 	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) *
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index edb306c..517ea33 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -34,6 +34,7 @@
 #define MANUFACTURER_MACRONIX	0x00C2
 #define MANUFACTURER_NEC	0x0010
 #define MANUFACTURER_PMC	0x009D
+#define MANUFACTURER_SHARP	0x00b0
 #define MANUFACTURER_SST	0x00BF
 #define MANUFACTURER_ST		0x0020
 #define MANUFACTURER_TOSHIBA	0x0098
@@ -124,6 +125,9 @@
 #define PM49FL004	0x006E
 #define PM49FL008	0x006A
 
+/* Sharp */
+#define LH28F640BF	0x00b0
+
 /* ST - www.st.com */
 #define M29W800DT	0x00D7
 #define M29W800DB	0x005B
@@ -1267,6 +1271,19 @@
 		.regions	= {
 			ERASEINFO( 0x01000, 256 )
 		}
+	}, {
+		.mfr_id		= MANUFACTURER_SHARP,
+		.dev_id		= LH28F640BF,
+		.name		= "LH28F640BF",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+		},
+		.DevSize	= SIZE_4MiB,
+		.CmdSet         = P_ID_INTEL_STD,
+		.NumEraseRegions= 1,
+		.regions        = {
+			ERASEINFO(0x40000,16),
+		}
         }, {
 		.mfr_id		= MANUFACTURER_SST,
 		.dev_id		= SST39LF512,
@@ -2035,7 +2052,7 @@
 		DEBUG(MTD_DEBUG_LEVEL3,
 		      "Search for id:(%02x %02x) interleave(%d) type(%d)\n",
 			cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type);
-		for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
+		for (i = 0; i < ARRAY_SIZE(jedec_table); i++) {
 			if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) {
 				DEBUG( MTD_DEBUG_LEVEL3,
 				       "MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n",
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
index 36f61a6..3cc0b23 100644
--- a/drivers/mtd/chips/sharp.c
+++ b/drivers/mtd/chips/sharp.c
@@ -64,7 +64,7 @@
 
 #undef AUTOUNLOCK  /* automatically unlocks blocks before erasing */
 
-struct mtd_info *sharp_probe(struct map_info *);
+static struct mtd_info *sharp_probe(struct map_info *);
 
 static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd);
 
@@ -96,7 +96,6 @@
 	struct flchip chips[1];
 };
 
-struct mtd_info *sharp_probe(struct map_info *map);
 static void sharp_destroy(struct mtd_info *mtd);
 
 static struct mtd_chip_driver sharp_chipdrv = {
@@ -107,7 +106,7 @@
 };
 
 
-struct mtd_info *sharp_probe(struct map_info *map)
+static struct mtd_info *sharp_probe(struct map_info *map)
 {
 	struct mtd_info *mtd = NULL;
 	struct sharp_info *sharp = NULL;
@@ -581,7 +580,7 @@
 
 }
 
-int __init sharp_probe_init(void)
+static int __init sharp_probe_init(void)
 {
 	printk("MTD Sharp chip driver <ds@lineo.com>\n");
 
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c
index 6b8bb2e..a7a7bfe 100644
--- a/drivers/mtd/cmdlinepart.c
+++ b/drivers/mtd/cmdlinepart.c
@@ -42,7 +42,8 @@
 
 
 /* special size referring to all the remaining space in a partition */
-#define SIZE_REMAINING 0xffffffff
+#define SIZE_REMAINING UINT_MAX
+#define OFFSET_CONTINUOUS UINT_MAX
 
 struct cmdline_mtd_partition {
 	struct cmdline_mtd_partition *next;
@@ -75,7 +76,7 @@
 {
 	struct mtd_partition *parts;
 	unsigned long size;
-	unsigned long offset = 0;
+	unsigned long offset = OFFSET_CONTINUOUS;
 	char *name;
 	int name_len;
 	unsigned char *extra_mem;
@@ -314,7 +315,7 @@
 		{
 			for(i = 0, offset = 0; i < part->num_parts; i++)
 			{
-				if (!part->parts[i].offset)
+				if (part->parts[i].offset == OFFSET_CONTINUOUS)
 				  part->parts[i].offset = offset;
 				else
 				  offset = part->parts[i].offset;
diff --git a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c
index 04f864d..79f2e1f 100644
--- a/drivers/mtd/devices/blkmtd.c
+++ b/drivers/mtd/devices/blkmtd.c
@@ -28,8 +28,9 @@
 #include <linux/pagemap.h>
 #include <linux/list.h>
 #include <linux/init.h>
+#include <linux/mount.h>
 #include <linux/mtd/mtd.h>
-
+#include <linux/mutex.h>
 
 #define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
 #define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
@@ -46,7 +47,7 @@
 	struct list_head list;
 	struct block_device *blkdev;
 	struct mtd_info mtd_info;
-	struct semaphore wrbuf_mutex;
+	struct mutex wrbuf_mutex;
 };
 
 
@@ -268,7 +269,7 @@
 	if(end_len)
 		pagecnt++;
 
-	down(&dev->wrbuf_mutex);
+	mutex_lock(&dev->wrbuf_mutex);
 
 	DEBUG(3, "blkmtd: write: start_len = %zd len = %zd end_len = %zd pagecnt = %d\n",
 	      start_len, len, end_len, pagecnt);
@@ -376,7 +377,7 @@
 		blkmtd_write_out(bio);
 
 	DEBUG(2, "blkmtd: write: end, retlen = %zd, err = %d\n", *retlen, err);
-	up(&dev->wrbuf_mutex);
+	mutex_unlock(&dev->wrbuf_mutex);
 
 	if(retlen)
 		*retlen = thislen;
@@ -614,8 +615,6 @@
 }
 
 
-extern dev_t __init name_to_dev_t(const char *line);
-
 static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size)
 {
 	struct block_device *bdev;
@@ -659,7 +658,7 @@
 	memset(dev, 0, sizeof(struct blkmtd_dev));
 	dev->blkdev = bdev;
 	if(!readonly) {
-		init_MUTEX(&dev->wrbuf_mutex);
+		mutex_init(&dev->wrbuf_mutex);
 	}
 
 	dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 7ff403b..4160b83 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/mtd/mtd.h>
 #include <linux/buffer_head.h>
+#include <linux/mutex.h>
 
 #define VERSION "$Revision: 1.30 $"
 
@@ -31,7 +32,7 @@
 	struct list_head list;
 	struct block_device *blkdev;
 	struct mtd_info mtd;
-	struct semaphore write_mutex;
+	struct mutex write_mutex;
 };
 
 
@@ -134,9 +135,9 @@
 	int err;
 
 	instr->state = MTD_ERASING;
-	down(&dev->write_mutex);
+	mutex_lock(&dev->write_mutex);
 	err = _block2mtd_erase(dev, from, len);
-	up(&dev->write_mutex);
+	mutex_unlock(&dev->write_mutex);
 	if (err) {
 		ERROR("erase failed err = %d", err);
 		instr->state = MTD_ERASE_FAILED;
@@ -249,9 +250,9 @@
 	if (to + len > mtd->size)
 		len = mtd->size - to;
 
-	down(&dev->write_mutex);
+	mutex_lock(&dev->write_mutex);
 	err = _block2mtd_write(dev, buf, to, len, retlen);
-	up(&dev->write_mutex);
+	mutex_unlock(&dev->write_mutex);
 	if (err > 0)
 		err = 0;
 	return err;
@@ -310,7 +311,7 @@
 		goto devinit_err;
 	}
 
-	init_MUTEX(&dev->write_mutex);
+	mutex_init(&dev->write_mutex);
 
 	/* Setup the MTD structure */
 	/* make the name contain the block device in */
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c
index e4345cf..23e7a5c 100644
--- a/drivers/mtd/devices/doc2000.c
+++ b/drivers/mtd/devices/doc2000.c
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/bitops.h>
+#include <linux/mutex.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -605,7 +606,7 @@
 
 	this->curfloor = -1;
 	this->curchip = -1;
-	init_MUTEX(&this->lock);
+	mutex_init(&this->lock);
 
 	/* Ident all the chips present. */
 	DoC_ScanChips(this, maxchips);
@@ -645,7 +646,7 @@
 	if (from >= this->totlen)
 		return -EINVAL;
 
-	down(&this->lock);
+	mutex_lock(&this->lock);
 
 	*retlen = 0;
 	while (left) {
@@ -774,7 +775,7 @@
 		buf += len;
 	}
 
-	up(&this->lock);
+	mutex_unlock(&this->lock);
 
 	return ret;
 }
@@ -803,7 +804,7 @@
 	if (to >= this->totlen)
 		return -EINVAL;
 
-	down(&this->lock);
+	mutex_lock(&this->lock);
 
 	*retlen = 0;
 	while (left) {
@@ -873,7 +874,7 @@
 				printk(KERN_ERR "Error programming flash\n");
 				/* Error in programming */
 				*retlen = 0;
-				up(&this->lock);
+				mutex_unlock(&this->lock);
 				return -EIO;
 			}
 
@@ -935,7 +936,7 @@
 			printk(KERN_ERR "Error programming flash\n");
 			/* Error in programming */
 			*retlen = 0;
-			up(&this->lock);
+			mutex_unlock(&this->lock);
 			return -EIO;
 		}
 
@@ -956,7 +957,7 @@
 
 			ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
 			if (ret) {
-				up(&this->lock);
+				mutex_unlock(&this->lock);
 				return ret;
 			}
 		}
@@ -966,7 +967,7 @@
 		buf += len;
 	}
 
-	up(&this->lock);
+	mutex_unlock(&this->lock);
 	return 0;
 }
 
@@ -975,13 +976,13 @@
 			  u_char *eccbuf, struct nand_oobinfo *oobsel)
 {
 	static char static_buf[512];
-	static DECLARE_MUTEX(writev_buf_sem);
+	static DEFINE_MUTEX(writev_buf_mutex);
 
 	size_t totretlen = 0;
 	size_t thisvecofs = 0;
 	int ret= 0;
 
-	down(&writev_buf_sem);
+	mutex_lock(&writev_buf_mutex);
 
 	while(count) {
 		size_t thislen, thisretlen;
@@ -1024,7 +1025,7 @@
 		to += thislen;
 	}
 
-	up(&writev_buf_sem);
+	mutex_unlock(&writev_buf_mutex);
 	*retlen = totretlen;
 	return ret;
 }
@@ -1037,7 +1038,7 @@
 	int len256 = 0, ret;
 	struct Nand *mychip;
 
-	down(&this->lock);
+	mutex_lock(&this->lock);
 
 	mychip = &this->chips[ofs >> this->chipshift];
 
@@ -1083,7 +1084,7 @@
 
 	ret = DoC_WaitReady(this);
 
-	up(&this->lock);
+	mutex_unlock(&this->lock);
 	return ret;
 
 }
@@ -1197,10 +1198,10 @@
  	struct DiskOnChip *this = mtd->priv;
  	int ret;
 
- 	down(&this->lock);
+ 	mutex_lock(&this->lock);
  	ret = doc_write_oob_nolock(mtd, ofs, len, retlen, buf);
 
- 	up(&this->lock);
+ 	mutex_unlock(&this->lock);
  	return ret;
 }
 
@@ -1214,10 +1215,10 @@
 	struct Nand *mychip;
 	int status;
 
- 	down(&this->lock);
+ 	mutex_lock(&this->lock);
 
 	if (ofs & (mtd->erasesize-1) || len & (mtd->erasesize-1)) {
-		up(&this->lock);
+		mutex_unlock(&this->lock);
 		return -EINVAL;
 	}
 
@@ -1265,7 +1266,7 @@
  callback:
 	mtd_erase_callback(instr);
 
-	up(&this->lock);
+	mutex_unlock(&this->lock);
 	return 0;
 }
 
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c
index 1e876fc..29b0dda 100644
--- a/drivers/mtd/devices/lart.c
+++ b/drivers/mtd/devices/lart.c
@@ -581,8 +581,6 @@
 
 /***************************************************************************************************/
 
-#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
-
 static struct mtd_info mtd;
 
 static struct mtd_erase_region_info erase_regions[] = {
@@ -640,7 +638,7 @@
    mtd.flags = MTD_CAP_NORFLASH;
    mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN;
    mtd.erasesize = FLASH_BLOCKSIZE_MAIN;
-   mtd.numeraseregions = NB_OF (erase_regions);
+   mtd.numeraseregions = ARRAY_SIZE(erase_regions);
    mtd.eraseregions = erase_regions;
    mtd.erase = flash_erase;
    mtd.read = flash_read;
@@ -670,9 +668,9 @@
 			   result,mtd.eraseregions[result].numblocks);
 
 #ifdef HAVE_PARTITIONS
-   printk ("\npartitions = %d\n",NB_OF (lart_partitions));
+   printk ("\npartitions = %d\n", ARRAY_SIZE(lart_partitions));
 
-   for (result = 0; result < NB_OF (lart_partitions); result++)
+   for (result = 0; result < ARRAY_SIZE(lart_partitions); result++)
 	 printk (KERN_DEBUG
 			 "\n\n"
 			 "lart_partitions[%d].name = %s\n"
@@ -687,7 +685,7 @@
 #ifndef HAVE_PARTITIONS
    result = add_mtd_device (&mtd);
 #else
-   result = add_mtd_partitions (&mtd,lart_partitions,NB_OF (lart_partitions));
+   result = add_mtd_partitions (&mtd,lart_partitions, ARRAY_SIZE(lart_partitions));
 #endif
 
    return (result);
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index d5f2408..04e65d5 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -186,7 +186,7 @@
 	struct m25p *flash = mtd_to_m25p(mtd);
 	u32 addr,len;
 
-	DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
+	DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n",
 			flash->spi->dev.bus_id, __FUNCTION__, "at",
 			(u32)instr->addr, instr->len);
 
diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c
index 0ff2e43..485f663 100644
--- a/drivers/mtd/devices/ms02-nv.c
+++ b/drivers/mtd/devices/ms02-nv.c
@@ -308,7 +308,7 @@
 		break;
 	}
 
-	for (i = 0; i < (sizeof(ms02nv_addrs) / sizeof(*ms02nv_addrs)); i++)
+	for (i = 0; i < ARRAY_SIZE(ms02nv_addrs); i++)
 		if (!ms02nv_init_one(ms02nv_addrs[i] << stride))
 			count++;
 
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index 8a54489..a3b9247 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -47,9 +47,6 @@
  */
 #define MAX_LOOPS 10000
 
-extern void INFTL_dumptables(struct INFTLrecord *inftl);
-extern void INFTL_dumpVUchains(struct INFTLrecord *inftl);
-
 static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 {
 	struct INFTLrecord *inftl;
@@ -132,7 +129,7 @@
 		return;
 	}
 #ifdef PSYCHO_DEBUG
-	printk(KERN_INFO "INFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
+	printk(KERN_INFO "INFTL: Found new inftl%c\n", inftl->mbd.devnum + 'a');
 #endif
 	return;
 }
@@ -885,8 +882,6 @@
 	.owner		= THIS_MODULE,
 };
 
-extern char inftlmountrev[];
-
 static int __init init_inftl(void)
 {
 	printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, "
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c
index a57791a..b933a2a 100644
--- a/drivers/mtd/maps/alchemy-flash.c
+++ b/drivers/mtd/maps/alchemy-flash.c
@@ -126,8 +126,6 @@
         }
 };
 
-#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-
 static struct mtd_info *mymtd;
 
 int __init alchemy_mtd_init(void)
@@ -154,7 +152,7 @@
 	 * Static partition definition selection
 	 */
 	parts = alchemy_partitions;
-	nb_parts = NB_OF(alchemy_partitions);
+	nb_parts = ARRAY_SIZE(alchemy_partitions);
 	alchemy_map.size = window_size;
 
 	/*
diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c
index 6a8c041..fd0f0d3 100644
--- a/drivers/mtd/maps/cfi_flagadm.c
+++ b/drivers/mtd/maps/cfi_flagadm.c
@@ -86,7 +86,7 @@
 	}
 };
 
-#define PARTITION_COUNT (sizeof(flagadm_parts)/sizeof(struct mtd_partition))
+#define PARTITION_COUNT ARRAY_SIZE(flagadm_parts)
 
 static struct mtd_info *mymtd;
 
diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c
index 49d9054..652813c 100644
--- a/drivers/mtd/maps/dbox2-flash.c
+++ b/drivers/mtd/maps/dbox2-flash.c
@@ -57,7 +57,7 @@
 	}
 };
 
-#define NUM_PARTITIONS (sizeof(partition_info) / sizeof(partition_info[0]))
+#define NUM_PARTITIONS ARRAY_SIZE(partition_info)
 
 #define WINDOW_ADDR 0x10000000
 #define WINDOW_SIZE 0x800000
diff --git a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c
index b51c757..c299d10 100644
--- a/drivers/mtd/maps/dilnetpc.c
+++ b/drivers/mtd/maps/dilnetpc.c
@@ -218,8 +218,8 @@
 	{
 		if(--vpp_counter == 0)
 			setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x4);
-		else if(vpp_counter < 0)
-			BUG();
+		else
+			BUG_ON(vpp_counter < 0);
 	}
 	spin_unlock_irq(&dnpc_spin);
 }
@@ -240,8 +240,8 @@
 	{
 		if(--vpp_counter == 0)
 			setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x8);
-		else if(vpp_counter < 0)
-			BUG();
+		else
+			BUG_ON(vpp_counter < 0);
 	}
 	spin_unlock_irq(&dnpc_spin);
 }
@@ -300,7 +300,7 @@
 	},
 };
 
-#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
+#define NUM_PARTITIONS ARRAY_SIZE(partition_info)
 
 static struct mtd_info *mymtd;
 static struct mtd_info *lowlvl_parts[NUM_PARTITIONS];
@@ -345,7 +345,7 @@
 	},
 };
 
-#define NUM_HIGHLVL_PARTITIONS (sizeof(higlvl_partition_info)/sizeof(partition_info[0]))
+#define NUM_HIGHLVL_PARTITIONS ARRAY_SIZE(higlvl_partition_info)
 
 
 static int dnp_adnp_probe(void)
diff --git a/drivers/mtd/maps/dmv182.c b/drivers/mtd/maps/dmv182.c
index b993ac0..2bb3c0f 100644
--- a/drivers/mtd/maps/dmv182.c
+++ b/drivers/mtd/maps/dmv182.c
@@ -99,7 +99,7 @@
 static int __init init_svme182(void)
 {
 	struct mtd_partition *partitions;
-	int num_parts = sizeof(svme182_partitions) / sizeof(struct mtd_partition);
+	int num_parts = ARRAY_SIZE(svme182_partitions);
 
 	partitions = svme182_partitions;
 
diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c
index 3190948..0667101 100644
--- a/drivers/mtd/maps/h720x-flash.c
+++ b/drivers/mtd/maps/h720x-flash.c
@@ -59,7 +59,7 @@
         }
 };
 
-#define NUM_PARTITIONS  (sizeof(h720x_partitions)/sizeof(h720x_partitions[0]))
+#define NUM_PARTITIONS ARRAY_SIZE(h720x_partitions)
 
 static int                   nr_mtd_parts;
 static struct mtd_partition *mtd_parts;
diff --git a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c
index 33060a3..ed21547 100644
--- a/drivers/mtd/maps/netsc520.c
+++ b/drivers/mtd/maps/netsc520.c
@@ -76,7 +76,7 @@
 	    .size = 0x80000
     },
 };
-#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
+#define NUM_PARTITIONS ARRAY_SIZE(partition_info)
 
 #define WINDOW_SIZE	0x00100000
 #define WINDOW_ADDR	0x00200000
@@ -88,7 +88,7 @@
 	.phys = WINDOW_ADDR,
 };
 
-#define NUM_FLASH_BANKS	(sizeof(netsc520_map)/sizeof(struct map_info))
+#define NUM_FLASH_BANKS	ARRAY_SIZE(netsc520_map)
 
 static struct mtd_info *mymtd;
 
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
index 632eb2a..54a3102 100644
--- a/drivers/mtd/maps/nettel.c
+++ b/drivers/mtd/maps/nettel.c
@@ -128,8 +128,7 @@
 	}
 };
 
-#define NUM_AMD_PARTITIONS \
-	(sizeof(nettel_amd_partitions)/sizeof(nettel_amd_partitions[0]))
+#define NUM_AMD_PARTITIONS ARRAY_SIZE(nettel_amd_partitions)
 
 /****************************************************************************/
 
diff --git a/drivers/mtd/maps/ocotea.c b/drivers/mtd/maps/ocotea.c
index c223514..a21fcd1 100644
--- a/drivers/mtd/maps/ocotea.c
+++ b/drivers/mtd/maps/ocotea.c
@@ -58,8 +58,6 @@
 	}
 };
 
-#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-
 int __init init_ocotea(void)
 {
 	u8 fpga0_reg;
@@ -97,7 +95,7 @@
 	if (flash) {
 		flash->owner = THIS_MODULE;
 		add_mtd_partitions(flash, ocotea_small_partitions,
-					NB_OF(ocotea_small_partitions));
+					ARRAY_SIZE(ocotea_small_partitions));
 	} else {
 		printk("map probe failed for flash\n");
 		return -ENXIO;
@@ -118,7 +116,7 @@
 	if (flash) {
 		flash->owner = THIS_MODULE;
 		add_mtd_partitions(flash, ocotea_large_partitions,
-					NB_OF(ocotea_large_partitions));
+					ARRAY_SIZE(ocotea_large_partitions));
 	} else {
 		printk("map probe failed for flash\n");
 		return -ENXIO;
diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c
index 21822c2..d2ab1ba 100644
--- a/drivers/mtd/maps/pci.c
+++ b/drivers/mtd/maps/pci.c
@@ -334,9 +334,6 @@
 	return 0;
 
 release:
-	if (mtd)
-		map_destroy(mtd);
-
 	if (map) {
 		map->exit(dev, map);
 		kfree(map);
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index f988c81..8bbc751 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -616,7 +616,7 @@
 	} else if(mem_type == 2) {
 		mtd = do_map_probe("map_rom", &dev->pcmcia_map);
 	} else {
-		for(i = 0; i < sizeof(probes) / sizeof(char *); i++) {
+		for(i = 0; i < ARRAY_SIZE(probes); i++) {
 			DEBUG(1, "Trying %s", probes[i]);
 			mtd = do_map_probe(probes[i], &dev->pcmcia_map);
 			if(mtd)
diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c
index 5b76ed8..50b1403 100644
--- a/drivers/mtd/maps/redwood.c
+++ b/drivers/mtd/maps/redwood.c
@@ -121,8 +121,7 @@
 };
 
 
-#define NUM_REDWOOD_FLASH_PARTITIONS \
-	(sizeof(redwood_flash_partitions)/sizeof(redwood_flash_partitions[0]))
+#define NUM_REDWOOD_FLASH_PARTITIONS ARRAY_SIZE(redwood_flash_partitions)
 
 static struct mtd_info *redwood_mtd;
 
diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c
index 225cdd9..350286d 100644
--- a/drivers/mtd/maps/sbc8240.c
+++ b/drivers/mtd/maps/sbc8240.c
@@ -66,7 +66,7 @@
 	}
 };
 
-#define NUM_FLASH_BANKS	(sizeof(sbc8240_map) / sizeof(struct map_info))
+#define NUM_FLASH_BANKS	ARRAY_SIZE(sbc8240_map)
 
 /*
  * The following defines the partition layout of SBC8240 boards.
@@ -125,8 +125,6 @@
 	}
 };
 
-#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
-
 /* trivial struct to describe partition information */
 struct mtd_part_def
 {
@@ -190,10 +188,10 @@
 #ifdef CONFIG_MTD_PARTITIONS
 	sbc8240_part_banks[0].mtd_part   = sbc8240_uboot_partitions;
 	sbc8240_part_banks[0].type       = "static image";
-	sbc8240_part_banks[0].nums       = NB_OF(sbc8240_uboot_partitions);
+	sbc8240_part_banks[0].nums       = ARRAY_SIZE(sbc8240_uboot_partitions);
 	sbc8240_part_banks[1].mtd_part   = sbc8240_fs_partitions;
 	sbc8240_part_banks[1].type       = "static file system";
-	sbc8240_part_banks[1].nums       = NB_OF(sbc8240_fs_partitions);
+	sbc8240_part_banks[1].nums       = ARRAY_SIZE(sbc8240_fs_partitions);
 
 	for (i = 0; i < NUM_FLASH_BANKS; i++) {
 
diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c
index ed92afa..e8c130e 100644
--- a/drivers/mtd/maps/sc520cdp.c
+++ b/drivers/mtd/maps/sc520cdp.c
@@ -107,7 +107,7 @@
 	},
 };
 
-#define NUM_FLASH_BANKS	(sizeof(sc520cdp_map)/sizeof(struct map_info))
+#define NUM_FLASH_BANKS	ARRAY_SIZE(sc520cdp_map)
 
 static struct mtd_info *mymtd[NUM_FLASH_BANKS];
 static struct mtd_info *merged_mtd;
diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c
index 2c91dff..28b8a57 100644
--- a/drivers/mtd/maps/scx200_docflash.c
+++ b/drivers/mtd/maps/scx200_docflash.c
@@ -70,7 +70,7 @@
 		.size   = 0x80000
 	},
 };
-#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
+#define NUM_PARTITIONS ARRAY_SIZE(partition_info)
 #endif
 
 
diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c
index 999f4bb..12fe53c 100644
--- a/drivers/mtd/maps/sharpsl-flash.c
+++ b/drivers/mtd/maps/sharpsl-flash.c
@@ -49,8 +49,6 @@
 	}
 };
 
-#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-
 int __init init_sharpsl(void)
 {
 	struct mtd_partition *parts;
@@ -92,7 +90,7 @@
 	}
 
 	parts = sharpsl_partitions;
-	nb_parts = NB_OF(sharpsl_partitions);
+	nb_parts = ARRAY_SIZE(sharpsl_partitions);
 
 	printk(KERN_NOTICE "Using %s partision definition\n", part_type);
 	add_mtd_partitions(mymtd, parts, nb_parts);
diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c
index 4b372bc..a7422c2 100644
--- a/drivers/mtd/maps/ts5500_flash.c
+++ b/drivers/mtd/maps/ts5500_flash.c
@@ -64,7 +64,7 @@
 	}
 };
 
-#define NUM_PARTITIONS (sizeof(ts5500_partitions)/sizeof(struct mtd_partition))
+#define NUM_PARTITIONS ARRAY_SIZE(ts5500_partitions)
 
 static struct mtd_info *mymtd;
 
diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c
index 79d9280..f7264dc 100644
--- a/drivers/mtd/maps/uclinux.c
+++ b/drivers/mtd/maps/uclinux.c
@@ -37,7 +37,7 @@
 	{ .name = "ROMfs" }
 };
 
-#define	NUM_PARTITIONS	(sizeof(uclinux_romfs) / sizeof(uclinux_romfs[0]))
+#define	NUM_PARTITIONS	ARRAY_SIZE(uclinux_romfs)
 
 /****************************************************************************/
 
diff --git a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c
index e006394..b3e4873 100644
--- a/drivers/mtd/maps/vmax301.c
+++ b/drivers/mtd/maps/vmax301.c
@@ -182,7 +182,7 @@
 		}
 	}
 
-	if (!vmax_mtd[1] && !vmax_mtd[2]) {
+	if (!vmax_mtd[0] && !vmax_mtd[1]) {
 		iounmap((void *)iomapadr);
 		return -ENXIO;
 	}
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 7f3ff50..458d3c8 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -19,12 +19,12 @@
 #include <linux/spinlock.h>
 #include <linux/hdreg.h>
 #include <linux/init.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 static LIST_HEAD(blktrans_majors);
 
-extern struct semaphore mtd_table_mutex;
+extern struct mutex mtd_table_mutex;
 extern struct mtd_info *mtd_table[];
 
 struct mtd_blkcore_priv {
@@ -122,9 +122,9 @@
 
 		spin_unlock_irq(rq->queue_lock);
 
-		down(&dev->sem);
+		mutex_lock(&dev->lock);
 		res = do_blktrans_request(tr, dev, req);
-		up(&dev->sem);
+		mutex_unlock(&dev->lock);
 
 		spin_lock_irq(rq->queue_lock);
 
@@ -235,8 +235,8 @@
 	int last_devnum = -1;
 	struct gendisk *gd;
 
-	if (!down_trylock(&mtd_table_mutex)) {
-		up(&mtd_table_mutex);
+	if (!!mutex_trylock(&mtd_table_mutex)) {
+		mutex_unlock(&mtd_table_mutex);
 		BUG();
 	}
 
@@ -267,7 +267,7 @@
 		return -EBUSY;
 	}
 
-	init_MUTEX(&new->sem);
+	mutex_init(&new->lock);
 	list_add_tail(&new->list, &tr->devs);
  added:
 	if (!tr->writesect)
@@ -313,8 +313,8 @@
 
 int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
 {
-	if (!down_trylock(&mtd_table_mutex)) {
-		up(&mtd_table_mutex);
+	if (!!mutex_trylock(&mtd_table_mutex)) {
+		mutex_unlock(&mtd_table_mutex);
 		BUG();
 	}
 
@@ -378,14 +378,14 @@
 
 	memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv));
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	ret = register_blkdev(tr->major, tr->name);
 	if (ret) {
 		printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n",
 		       tr->name, tr->major, ret);
 		kfree(tr->blkcore_priv);
-		up(&mtd_table_mutex);
+		mutex_unlock(&mtd_table_mutex);
 		return ret;
 	}
 	spin_lock_init(&tr->blkcore_priv->queue_lock);
@@ -396,7 +396,7 @@
 	if (!tr->blkcore_priv->rq) {
 		unregister_blkdev(tr->major, tr->name);
 		kfree(tr->blkcore_priv);
-		up(&mtd_table_mutex);
+		mutex_unlock(&mtd_table_mutex);
 		return -ENOMEM;
 	}
 
@@ -407,7 +407,7 @@
 		blk_cleanup_queue(tr->blkcore_priv->rq);
 		unregister_blkdev(tr->major, tr->name);
 		kfree(tr->blkcore_priv);
-		up(&mtd_table_mutex);
+		mutex_unlock(&mtd_table_mutex);
 		return ret;
 	}
 
@@ -419,7 +419,7 @@
 			tr->add_mtd(tr, mtd_table[i]);
 	}
 
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 
 	return 0;
 }
@@ -428,7 +428,7 @@
 {
 	struct list_head *this, *next;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	/* Clean up the kernel thread */
 	tr->blkcore_priv->exiting = 1;
@@ -446,12 +446,11 @@
 	blk_cleanup_queue(tr->blkcore_priv->rq);
 	unregister_blkdev(tr->major, tr->name);
 
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 
 	kfree(tr->blkcore_priv);
 
-	if (!list_empty(&tr->devs))
-		BUG();
+	BUG_ON(!list_empty(&tr->devs));
 	return 0;
 }
 
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index e847566..2cef280 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -19,11 +19,13 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/blktrans.h>
+#include <linux/mutex.h>
+
 
 static struct mtdblk_dev {
 	struct mtd_info *mtd;
 	int count;
-	struct semaphore cache_sem;
+	struct mutex cache_mutex;
 	unsigned char *cache_data;
 	unsigned long cache_offset;
 	unsigned int cache_size;
@@ -284,7 +286,7 @@
 	mtdblk->count = 1;
 	mtdblk->mtd = mtd;
 
-	init_MUTEX (&mtdblk->cache_sem);
+	mutex_init(&mtdblk->cache_mutex);
 	mtdblk->cache_state = STATE_EMPTY;
 	if ((mtdblk->mtd->flags & MTD_CAP_RAM) != MTD_CAP_RAM &&
 	    mtdblk->mtd->erasesize) {
@@ -306,9 +308,9 @@
 
    	DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
 
-	down(&mtdblk->cache_sem);
+	mutex_lock(&mtdblk->cache_mutex);
 	write_cached_data(mtdblk);
-	up(&mtdblk->cache_sem);
+	mutex_unlock(&mtdblk->cache_mutex);
 
 	if (!--mtdblk->count) {
 		/* It was the last usage. Free the device */
@@ -327,9 +329,9 @@
 {
 	struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
 
-	down(&mtdblk->cache_sem);
+	mutex_lock(&mtdblk->cache_mutex);
 	write_cached_data(mtdblk);
-	up(&mtdblk->cache_sem);
+	mutex_unlock(&mtdblk->cache_mutex);
 
 	if (mtdblk->mtd->sync)
 		mtdblk->mtd->sync(mtdblk->mtd);
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index b1bf8c4..9af8403 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -477,8 +477,7 @@
 	}
 
 	/* must never happen since size limit has been verified above */
-	if (i >= concat->num_subdev)
-		BUG();
+	BUG_ON(i >= concat->num_subdev);
 
 	/* now do the erase: */
 	err = 0;
@@ -500,8 +499,7 @@
 		if ((err = concat_dev_erase(subdev, erase))) {
 			/* sanity check: should never happen since
 			 * block alignment has been checked above */
-			if (err == -EINVAL)
-				BUG();
+			BUG_ON(err == -EINVAL);
 			if (erase->fail_addr != 0xffffffff)
 				instr->fail_addr = erase->fail_addr + offset;
 			break;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index dade02a..9905870 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -19,15 +19,13 @@
 #include <linux/ioctl.h>
 #include <linux/init.h>
 #include <linux/mtd/compatmac.h>
-#ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
-#endif
 
 #include <linux/mtd/mtd.h>
 
 /* These are exported solely for the purpose of mtd_blkdevs.c. You
    should not use them for _anything_ else */
-DECLARE_MUTEX(mtd_table_mutex);
+DEFINE_MUTEX(mtd_table_mutex);
 struct mtd_info *mtd_table[MAX_MTD_DEVICES];
 
 EXPORT_SYMBOL_GPL(mtd_table_mutex);
@@ -49,7 +47,7 @@
 {
 	int i;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	for (i=0; i < MAX_MTD_DEVICES; i++)
 		if (!mtd_table[i]) {
@@ -67,7 +65,7 @@
 				not->add(mtd);
 			}
 
-			up(&mtd_table_mutex);
+			mutex_unlock(&mtd_table_mutex);
 			/* We _know_ we aren't being removed, because
 			   our caller is still holding us here. So none
 			   of this try_ nonsense, and no bitching about it
@@ -76,7 +74,7 @@
 			return 0;
 		}
 
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 	return 1;
 }
 
@@ -94,7 +92,7 @@
 {
 	int ret;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	if (mtd_table[mtd->index] != mtd) {
 		ret = -ENODEV;
@@ -118,7 +116,7 @@
 		ret = 0;
 	}
 
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 	return ret;
 }
 
@@ -135,7 +133,7 @@
 {
 	int i;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	list_add(&new->list, &mtd_notifiers);
 
@@ -145,7 +143,7 @@
 		if (mtd_table[i])
 			new->add(mtd_table[i]);
 
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 }
 
 /**
@@ -162,7 +160,7 @@
 {
 	int i;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	module_put(THIS_MODULE);
 
@@ -171,7 +169,7 @@
 			old->remove(mtd_table[i]);
 
 	list_del(&old->list);
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 	return 0;
 }
 
@@ -193,7 +191,7 @@
 	struct mtd_info *ret = NULL;
 	int i;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	if (num == -1) {
 		for (i=0; i< MAX_MTD_DEVICES; i++)
@@ -211,7 +209,7 @@
 	if (ret)
 		ret->usecount++;
 
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 	return ret;
 }
 
@@ -219,9 +217,9 @@
 {
 	int c;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 	c = --mtd->usecount;
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 	BUG_ON(c < 0);
 
 	module_put(mtd->owner);
@@ -296,10 +294,11 @@
 EXPORT_SYMBOL(default_mtd_writev);
 EXPORT_SYMBOL(default_mtd_readv);
 
+#ifdef CONFIG_PROC_FS
+
 /*====================================================================*/
 /* Support for /proc/mtd */
 
-#ifdef CONFIG_PROC_FS
 static struct proc_dir_entry *proc_mtd;
 
 static inline int mtd_proc_info (char *buf, int i)
@@ -319,7 +318,7 @@
 	int len, l, i;
         off_t   begin = 0;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	len = sprintf(page, "dev:    size   erasesize  name\n");
         for (i=0; i< MAX_MTD_DEVICES; i++) {
@@ -337,38 +336,34 @@
         *eof = 1;
 
 done:
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
         if (off >= len+begin)
                 return 0;
         *start = page + (off-begin);
         return ((count < begin+len-off) ? count : begin+len-off);
 }
 
-#endif /* CONFIG_PROC_FS */
-
 /*====================================================================*/
 /* Init code */
 
 static int __init init_mtd(void)
 {
-#ifdef CONFIG_PROC_FS
 	if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))
 		proc_mtd->read_proc = mtd_read_proc;
-#endif
 	return 0;
 }
 
 static void __exit cleanup_mtd(void)
 {
-#ifdef CONFIG_PROC_FS
         if (proc_mtd)
 		remove_proc_entry( "mtd", NULL);
-#endif
 }
 
 module_init(init_mtd);
 module_exit(cleanup_mtd);
 
+#endif /* CONFIG_PROC_FS */
+
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 1fc4c13..cfe288a 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -178,17 +178,16 @@
 	  Even if you leave this disabled, you can enable BBT writes at module
 	  load time (assuming you build diskonchip as a module) with the module
 	  parameter "inftl_bbt_write=1".
-	  
- config MTD_NAND_SHARPSL
- 	bool "Support for NAND Flash on Sharp SL Series (C7xx + others)"
- 	depends on MTD_NAND && ARCH_PXA
- 
- config MTD_NAND_NANDSIM
- 	bool "Support for NAND Flash Simulator"
- 	depends on MTD_NAND && MTD_PARTITIONS
 
+config MTD_NAND_SHARPSL
+	tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
+	depends on MTD_NAND && ARCH_PXA
+
+config MTD_NAND_NANDSIM
+	tristate "Support for NAND Flash Simulator"
+	depends on MTD_NAND && MTD_PARTITIONS
 	help
 	  The simulator may simulate verious NAND flash chips for the
 	  MTD nand layer.
- 
+
 endmenu
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
index 201e136..bde3550 100644
--- a/drivers/mtd/nand/au1550nd.c
+++ b/drivers/mtd/nand/au1550nd.c
@@ -55,8 +55,6 @@
  		.size 	=    MTDPART_SIZ_FULL
 	}
 };
-#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-
 
 /**
  * au_read_byte -  read one byte from the chip
@@ -462,7 +460,7 @@
 	}
 
 	/* Register the partitions */
-	add_mtd_partitions(au1550_mtd, partition_info, NB_OF(partition_info));
+	add_mtd_partitions(au1550_mtd, partition_info, ARRAY_SIZE(partition_info));
 
 	return 0;
 
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 5d22246..95e96fa 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -80,6 +80,7 @@
 #include <linux/mtd/compatmac.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
+#include <linux/leds.h>
 #include <asm/io.h>
 
 #ifdef CONFIG_MTD_PARTITIONS
@@ -515,6 +516,8 @@
 	return nand_isbad_bbt (mtd, ofs, allowbbt);
 }
 
+DEFINE_LED_TRIGGER(nand_led_trigger);
+
 /*
  * Wait for the ready pin, after a command
  * The timeout is catched later.
@@ -524,12 +527,14 @@
 	struct nand_chip *this = mtd->priv;
 	unsigned long	timeo = jiffies + 2;
 
+	led_trigger_event(nand_led_trigger, LED_FULL);
 	/* wait until command is processed or timeout occures */
 	do {
 		if (this->dev_ready(mtd))
-			return;
+			break;
 		touch_softlockup_watchdog();
 	} while (time_before(jiffies, timeo));
+	led_trigger_event(nand_led_trigger, LED_OFF);
 }
 
 /**
@@ -817,6 +822,8 @@
 	else
 		 timeo += (HZ * 20) / 1000;
 
+	led_trigger_event(nand_led_trigger, LED_FULL);
+
 	/* Apply this short delay always to ensure that we do wait tWB in
 	 * any case on any machine. */
 	ndelay (100);
@@ -840,6 +847,8 @@
 		}
 		cond_resched();
 	}
+	led_trigger_event(nand_led_trigger, LED_OFF);
+
 	status = (int) this->read_byte(mtd);
 	return status;
 }
@@ -2724,6 +2733,21 @@
 EXPORT_SYMBOL_GPL (nand_scan);
 EXPORT_SYMBOL_GPL (nand_release);
 
+
+static int __init nand_base_init(void)
+{
+	led_trigger_register_simple("nand-disk", &nand_led_trigger);
+	return 0;
+}
+
+static void __exit nand_base_exit(void)
+{
+	led_trigger_unregister_simple(nand_led_trigger);
+}
+
+module_init(nand_base_init);
+module_exit(nand_base_exit);
+
 MODULE_LICENSE ("GPL");
 MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
 MODULE_DESCRIPTION ("Generic NAND flash driver code");
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c
index 8815c8d..c077d2e 100644
--- a/drivers/mtd/redboot.c
+++ b/drivers/mtd/redboot.c
@@ -85,10 +85,6 @@
 
 	numslots = (master->erasesize / sizeof(struct fis_image_desc));
 	for (i = 0; i < numslots; i++) {
-		if (buf[i].name[0] == 0xff) {
-			i = numslots;
-			break;
-		}
 		if (!memcmp(buf[i].name, "FIS directory", 14)) {
 			/* This is apparently the FIS directory entry for the
 			 * FIS directory itself.  The FIS directory size is
@@ -128,7 +124,7 @@
 		struct fis_list *new_fl, **prev;
 
 		if (buf[i].name[0] == 0xff)
-			break;
+			continue;
 		if (!redboot_checksum(&buf[i]))
 			break;
 
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index d339308..274b013 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -196,8 +196,6 @@
 
 
 #define DRV_NAME	"3c59x"
-#define DRV_VERSION	"LK1.1.19"
-#define DRV_RELDATE	"10 Nov 2002"
 
 
 
@@ -275,10 +273,8 @@
 DRV_NAME ": Donald Becker and others. www.scyld.com/network/vortex.html\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver "
-					DRV_VERSION " " DRV_RELDATE);
+MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver ");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
 
 
 /* Operational parameter that usually are not changed. */
@@ -792,7 +788,7 @@
 	int options;						/* User-settable misc. driver options. */
 	unsigned int media_override:4, 		/* Passed-in media type. */
 		default_media:4,				/* Read from the EEPROM/Wn3_Config. */
-		full_duplex:1, force_fd:1, autoselect:1,
+		full_duplex:1, autoselect:1,
 		bus_master:1,					/* Vortex can only do a fragment bus-m. */
 		full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
 		flow_ctrl:1,					/* Use 802.3x flow control (PAUSE only) */
@@ -904,7 +900,6 @@
 static struct ethtool_ops vortex_ethtool_ops;
 static void set_8021q_mode(struct net_device *dev, int enable);
 
-
 /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
 /* Option count limit only -- unlimited interfaces are supported. */
 #define MAX_UNITS 8
@@ -919,8 +914,6 @@
 static int global_enable_wol = -1;
 static int global_use_mmio = -1;
 
-/* #define dev_alloc_skb dev_alloc_skb_debug */
-
 /* Variables to work-around the Compaq PCI BIOS32 problem. */
 static int compaq_ioaddr, compaq_irq, compaq_device_id = 0x5900;
 static struct net_device *compaq_net_device;
@@ -976,7 +969,7 @@
 
 #ifdef CONFIG_PM
 
-static int vortex_suspend (struct pci_dev *pdev, pm_message_t state)
+static int vortex_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 
@@ -994,7 +987,7 @@
 	return 0;
 }
 
-static int vortex_resume (struct pci_dev *pdev)
+static int vortex_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct vortex_private *vp = netdev_priv(dev);
@@ -1027,8 +1020,8 @@
 	{ "" }
 };
 
-static int vortex_eisa_probe (struct device *device);
-static int vortex_eisa_remove (struct device *device);
+static int vortex_eisa_probe(struct device *device);
+static int vortex_eisa_remove(struct device *device);
 
 static struct eisa_driver vortex_eisa_driver = {
 	.id_table = vortex_eisa_ids,
@@ -1039,12 +1032,12 @@
 	}
 };
 
-static int vortex_eisa_probe (struct device *device)
+static int vortex_eisa_probe(struct device *device)
 {
 	void __iomem *ioaddr;
 	struct eisa_device *edev;
 
-	edev = to_eisa_device (device);
+	edev = to_eisa_device(device);
 
 	if (!request_region(edev->base_addr, VORTEX_TOTAL_SIZE, DRV_NAME))
 		return -EBUSY;
@@ -1053,7 +1046,7 @@
 
 	if (vortex_probe1(device, ioaddr, ioread16(ioaddr + 0xC88) >> 12,
 					  edev->id.driver_data, vortex_cards_found)) {
-		release_region (edev->base_addr, VORTEX_TOTAL_SIZE);
+		release_region(edev->base_addr, VORTEX_TOTAL_SIZE);
 		return -ENODEV;
 	}
 
@@ -1062,15 +1055,15 @@
 	return 0;
 }
 
-static int vortex_eisa_remove (struct device *device)
+static int vortex_eisa_remove(struct device *device)
 {
 	struct eisa_device *edev;
 	struct net_device *dev;
 	struct vortex_private *vp;
 	void __iomem *ioaddr;
 
-	edev = to_eisa_device (device);
-	dev = eisa_get_drvdata (edev);
+	edev = to_eisa_device(device);
+	dev = eisa_get_drvdata(edev);
 
 	if (!dev) {
 		printk("vortex_eisa_remove called for Compaq device!\n");
@@ -1080,17 +1073,17 @@
 	vp = netdev_priv(dev);
 	ioaddr = vp->ioaddr;
 	
-	unregister_netdev (dev);
-	iowrite16 (TotalReset|0x14, ioaddr + EL3_CMD);
-	release_region (dev->base_addr, VORTEX_TOTAL_SIZE);
+	unregister_netdev(dev);
+	iowrite16(TotalReset|0x14, ioaddr + EL3_CMD);
+	release_region(dev->base_addr, VORTEX_TOTAL_SIZE);
 
-	free_netdev (dev);
+	free_netdev(dev);
 	return 0;
 }
 #endif
 
 /* returns count found (>= 0), or negative on error */
-static int __init vortex_eisa_init (void)
+static int __init vortex_eisa_init(void)
 {
 	int eisa_found = 0;
 	int orig_cards_found = vortex_cards_found;
@@ -1121,7 +1114,7 @@
 }
 
 /* returns count (>= 0), or negative on error */
-static int __devinit vortex_init_one (struct pci_dev *pdev,
+static int __devinit vortex_init_one(struct pci_dev *pdev,
 				      const struct pci_device_id *ent)
 {
 	int rc, unit, pci_bar;
@@ -1129,7 +1122,7 @@
 	void __iomem *ioaddr;
 
 	/* wake up and enable device */		
-	rc = pci_enable_device (pdev);
+	rc = pci_enable_device(pdev);
 	if (rc < 0)
 		goto out;
 
@@ -1151,7 +1144,7 @@
 	rc = vortex_probe1(&pdev->dev, ioaddr, pdev->irq,
 			   ent->driver_data, unit);
 	if (rc < 0) {
-		pci_disable_device (pdev);
+		pci_disable_device(pdev);
 		goto out;
 	}
 
@@ -1236,7 +1229,7 @@
 	if (print_info)
 		printk (KERN_INFO "See Documentation/networking/vortex.txt\n");
 
-	printk(KERN_INFO "%s: 3Com %s %s at %p. Vers " DRV_VERSION "\n",
+	printk(KERN_INFO "%s: 3Com %s %s at %p.\n",
 	       print_name,
 	       pdev ? "PCI" : "EISA",
 	       vci->name,
@@ -1266,7 +1259,7 @@
 
 		/* enable bus-mastering if necessary */		
 		if (vci->flags & PCI_USES_MASTER)
-			pci_set_master (pdev);
+			pci_set_master(pdev);
 
 		if (vci->drv_flags & IS_VORTEX) {
 			u8 pci_latency;
@@ -1310,7 +1303,7 @@
 	if (pdev)
 		pci_set_drvdata(pdev, dev);
 	if (edev)
-		eisa_set_drvdata (edev, dev);
+		eisa_set_drvdata(edev, dev);
 
 	vp->media_override = 7;
 	if (option >= 0) {
@@ -1335,7 +1328,7 @@
 			vp->enable_wol = 1;
 	}
 
-	vp->force_fd = vp->full_duplex;
+	vp->mii.force_media = vp->full_duplex;
 	vp->options = option;
 	/* Read the station address from the EEPROM. */
 	EL3WINDOW(0);
@@ -1625,12 +1618,46 @@
 }
 
 static void
+vortex_set_duplex(struct net_device *dev)
+{
+	struct vortex_private *vp = netdev_priv(dev);
+	void __iomem *ioaddr = vp->ioaddr;
+
+	printk(KERN_INFO "%s:  setting %s-duplex.\n",
+		dev->name, (vp->full_duplex) ? "full" : "half");
+
+	EL3WINDOW(3);
+	/* Set the full-duplex bit. */
+	iowrite16(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
+		 	(vp->large_frames ? 0x40 : 0) |
+			((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ?
+					0x100 : 0),
+			ioaddr + Wn3_MAC_Ctrl);
+}
+
+static void vortex_check_media(struct net_device *dev, unsigned int init)
+{
+	struct vortex_private *vp = netdev_priv(dev);
+	unsigned int ok_to_print = 0;
+
+	if (vortex_debug > 3)
+		ok_to_print = 1;
+
+	if (mii_check_media(&vp->mii, ok_to_print, init)) {
+		vp->full_duplex = vp->mii.full_duplex;
+		vortex_set_duplex(dev);
+	} else if (init) {
+		vortex_set_duplex(dev);
+	}
+}
+
+static void
 vortex_up(struct net_device *dev)
 {
 	struct vortex_private *vp = netdev_priv(dev);
 	void __iomem *ioaddr = vp->ioaddr;
 	unsigned int config;
-	int i;
+	int i, mii_reg1, mii_reg5;
 
 	if (VORTEX_PCI(vp)) {
 		pci_set_power_state(VORTEX_PCI(vp), PCI_D0);	/* Go active */
@@ -1684,47 +1711,22 @@
 		printk(KERN_DEBUG "%s: Initial media type %s.\n",
 			   dev->name, media_tbl[dev->if_port].name);
 
-	vp->full_duplex = vp->force_fd;
+	vp->full_duplex = vp->mii.force_media;
 	config = BFINS(config, dev->if_port, 20, 4);
 	if (vortex_debug > 6)
 		printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config);
 	iowrite32(config, ioaddr + Wn3_Config);
 
 	if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
-		int mii_reg1, mii_reg5;
 		EL3WINDOW(4);
-		/* Read BMSR (reg1) only to clear old status. */
 		mii_reg1 = mdio_read(dev, vp->phys[0], MII_BMSR);
 		mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA);
-		if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000) {
-			netif_carrier_off(dev); /* No MII device or no link partner report */
-		} else {
-			mii_reg5 &= vp->advertising;
-			if ((mii_reg5 & 0x0100) != 0	/* 100baseTx-FD */
-				 || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
-			vp->full_duplex = 1;
-			netif_carrier_on(dev);
-		}
 		vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0);
-		if (vortex_debug > 1)
-			printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
-				   " info1 %04x, setting %s-duplex.\n",
-					dev->name, vp->phys[0],
-					mii_reg1, mii_reg5,
-					vp->info1, ((vp->info1 & 0x8000) || vp->full_duplex) ? "full" : "half");
-		EL3WINDOW(3);
-	}
 
-	/* Set the full-duplex bit. */
-	iowrite16(	((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
-		 	(vp->large_frames ? 0x40 : 0) |
-			((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0),
-			ioaddr + Wn3_MAC_Ctrl);
-
-	if (vortex_debug > 1) {
-		printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n",
-			dev->name, config);
+		vortex_check_media(dev, 1);
 	}
+	else
+		vortex_set_duplex(dev);
 
 	issue_and_wait(dev, TxReset);
 	/*
@@ -1732,6 +1734,7 @@
 	 */
 	issue_and_wait(dev, RxReset|0x04);
 
+
 	iowrite16(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
 
 	if (vortex_debug > 1) {
@@ -1805,7 +1808,6 @@
 	set_8021q_mode(dev, 1);
 	iowrite16(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
 
-//	issue_and_wait(dev, SetTxStart|0x07ff);
 	iowrite16(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
 	iowrite16(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
 	/* Allow status bits to be seen. */
@@ -1892,7 +1894,7 @@
 	void __iomem *ioaddr = vp->ioaddr;
 	int next_tick = 60*HZ;
 	int ok = 0;
-	int media_status, mii_status, old_window;
+	int media_status, old_window;
 
 	if (vortex_debug > 2) {
 		printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
@@ -1900,8 +1902,6 @@
 		printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo);
 	}
 
-	if (vp->medialock)
-		goto leave_media_alone;
 	disable_irq(dev->irq);
 	old_window = ioread16(ioaddr + EL3_CMD) >> 13;
 	EL3WINDOW(4);
@@ -1924,44 +1924,9 @@
 		break;
 	case XCVR_MII: case XCVR_NWAY:
 		{
-			spin_lock_bh(&vp->lock);
-			mii_status = mdio_read(dev, vp->phys[0], MII_BMSR);
-			if (!(mii_status & BMSR_LSTATUS)) {
-				/* Re-read to get actual link status */
-				mii_status = mdio_read(dev, vp->phys[0], MII_BMSR);
-			}
 			ok = 1;
-			if (vortex_debug > 2)
-				printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
-					dev->name, mii_status);
-			if (mii_status & BMSR_LSTATUS) {
-				int mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA);
-				if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
-					int duplex;
-
-					mii_reg5 &= vp->advertising;
-					duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
-					if (vp->full_duplex != duplex) {
-						vp->full_duplex = duplex;
-						printk(KERN_INFO "%s: Setting %s-duplex based on MII "
-							"#%d link partner capability of %4.4x.\n",
-							dev->name, vp->full_duplex ? "full" : "half",
-							vp->phys[0], mii_reg5);
-						/* Set the full-duplex bit. */
-						EL3WINDOW(3);
-						iowrite16(	(vp->full_duplex ? 0x20 : 0) |
-								(vp->large_frames ? 0x40 : 0) |
-								((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0),
-								ioaddr + Wn3_MAC_Ctrl);
-						if (vortex_debug > 1)
-							printk(KERN_DEBUG "Setting duplex in Wn3_MAC_Ctrl\n");
-						/* AKPM: bug: should reset Tx and Rx after setting Duplex.  Page 180 */
-					}
-				}
-				netif_carrier_on(dev);
-			} else {
-				netif_carrier_off(dev);
-			}
+			spin_lock_bh(&vp->lock);
+			vortex_check_media(dev, 0);
 			spin_unlock_bh(&vp->lock);
 		}
 		break;
@@ -1971,7 +1936,14 @@
 				 dev->name, media_tbl[dev->if_port].name, media_status);
 		ok = 1;
 	}
-	if ( ! ok) {
+
+	if (!netif_carrier_ok(dev))
+		next_tick = 5*HZ;
+
+	if (vp->medialock)
+		goto leave_media_alone;
+
+	if (!ok) {
 		unsigned int config;
 
 		do {
@@ -2004,14 +1976,14 @@
 			printk(KERN_DEBUG "wrote 0x%08x to Wn3_Config\n", config);
 		/* AKPM: FIXME: Should reset Rx & Tx here.  P60 of 3c90xc.pdf */
 	}
-	EL3WINDOW(old_window);
-	enable_irq(dev->irq);
 
 leave_media_alone:
 	if (vortex_debug > 2)
 	  printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
 			 dev->name, media_tbl[dev->if_port].name);
 
+	EL3WINDOW(old_window);
+	enable_irq(dev->irq);
 	mod_timer(&vp->timer, RUN_AT(next_tick));
 	if (vp->deferred)
 		iowrite16(FakeIntr, ioaddr + EL3_CMD);
@@ -2114,16 +2086,14 @@
 		}
 		if (tx_status & 0x14)  vp->stats.tx_fifo_errors++;
 		if (tx_status & 0x38)  vp->stats.tx_aborted_errors++;
+		if (tx_status & 0x08)  vp->xstats.tx_max_collisions++;
 		iowrite8(0, ioaddr + TxStatus);
 		if (tx_status & 0x30) {			/* txJabber or txUnderrun */
 			do_tx_reset = 1;
-		} else if (tx_status & 0x08) {	/* maxCollisions */
-			vp->xstats.tx_max_collisions++;
-			if (vp->drv_flags & MAX_COLLISION_RESET) {
-				do_tx_reset = 1;
-				reset_mask = 0x0108;		/* Reset interface logic, but not download logic */
-			}
-		} else {						/* Merely re-enable the transmitter. */
+		} else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET))  {	/* maxCollisions */
+			do_tx_reset = 1;
+			reset_mask = 0x0108;		/* Reset interface logic, but not download logic */
+		} else {				/* Merely re-enable the transmitter. */
 			iowrite16(TxEnable, ioaddr + EL3_CMD);
 		}
 	}
@@ -2206,7 +2176,7 @@
 	if (vp->bus_master) {
 		/* Set the bus-master controller to transfer the packet. */
 		int len = (skb->len + 3) & ~3;
-		iowrite32(	vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len, PCI_DMA_TODEVICE),
+		iowrite32(vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len, PCI_DMA_TODEVICE),
 				ioaddr + Wn7_MasterAddr);
 		iowrite16(len, ioaddr + Wn7_MasterLen);
 		vp->tx_skb = skb;
@@ -2983,20 +2953,6 @@
 	return rc;
 }
 
-static u32 vortex_get_link(struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	unsigned long flags;
-	int rc;
-
-	spin_lock_irqsave(&vp->lock, flags);
-	EL3WINDOW(4);
-	rc = mii_link_ok(&vp->mii);
-	spin_unlock_irqrestore(&vp->lock, flags);
-	return rc;
-}
-
 static int vortex_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct vortex_private *vp = netdev_priv(dev);
@@ -3077,7 +3033,6 @@
 	struct vortex_private *vp = netdev_priv(dev);
 
 	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
 	if (VORTEX_PCI(vp)) {
 		strcpy(info->bus_info, pci_name(VORTEX_PCI(vp)));
 	} else {
@@ -3098,9 +3053,9 @@
 	.get_stats_count        = vortex_get_stats_count,
 	.get_settings           = vortex_get_settings,
 	.set_settings           = vortex_set_settings,
-	.get_link               = vortex_get_link,
+	.get_link               = ethtool_op_get_link,
 	.nway_reset             = vortex_nway_reset,
-	.get_perm_addr			= ethtool_op_get_perm_addr,
+	.get_perm_addr		= ethtool_op_get_perm_addr,
 };
 
 #ifdef CONFIG_PCI
@@ -3301,7 +3256,7 @@
 	}
 	return;
 }
-
+
 /* ACPI: Advanced Configuration and Power Interface. */
 /* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */
 static void acpi_set_WOL(struct net_device *dev)
@@ -3325,7 +3280,7 @@
 }
 
 
-static void __devexit vortex_remove_one (struct pci_dev *pdev)
+static void __devexit vortex_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct vortex_private *vp;
@@ -3381,7 +3336,7 @@
 static int vortex_have_eisa;
 
 
-static int __init vortex_init (void)
+static int __init vortex_init(void)
 {
 	int pci_rc, eisa_rc;
 
@@ -3397,14 +3352,14 @@
 }
 
 
-static void __exit vortex_eisa_cleanup (void)
+static void __exit vortex_eisa_cleanup(void)
 {
 	struct vortex_private *vp;
 	void __iomem *ioaddr;
 
 #ifdef CONFIG_EISA
 	/* Take care of the EISA devices */
-	eisa_driver_unregister (&vortex_eisa_driver);
+	eisa_driver_unregister(&vortex_eisa_driver);
 #endif
 	
 	if (compaq_net_device) {
@@ -3412,33 +3367,24 @@
 		ioaddr = ioport_map(compaq_net_device->base_addr,
 		                    VORTEX_TOTAL_SIZE);
 
-		unregister_netdev (compaq_net_device);
-		iowrite16 (TotalReset, ioaddr + EL3_CMD);
+		unregister_netdev(compaq_net_device);
+		iowrite16(TotalReset, ioaddr + EL3_CMD);
 		release_region(compaq_net_device->base_addr,
 		               VORTEX_TOTAL_SIZE);
 
-		free_netdev (compaq_net_device);
+		free_netdev(compaq_net_device);
 	}
 }
 
 
-static void __exit vortex_cleanup (void)
+static void __exit vortex_cleanup(void)
 {
 	if (vortex_have_pci)
-		pci_unregister_driver (&vortex_driver);
+		pci_unregister_driver(&vortex_driver);
 	if (vortex_have_eisa)
-		vortex_eisa_cleanup ();
+		vortex_eisa_cleanup();
 }
 
 
 module_init(vortex_init);
 module_exit(vortex_cleanup);
-
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff --git a/drivers/net/8390.h b/drivers/net/8390.h
index 599b68d..51e39dc 100644
--- a/drivers/net/8390.h
+++ b/drivers/net/8390.h
@@ -134,7 +134,7 @@
 #define inb_p(_p)	inb(_p)
 #define outb_p(_v,_p)	outb(_v,_p)
 
-#elif defined(CONFIG_NET_CBUS) || defined(CONFIG_NE_H8300) || defined(CONFIG_NE_H8300_MODULE)
+#elif defined(CONFIG_NE_H8300) || defined(CONFIG_NE_H8300_MODULE)
 #define EI_SHIFT(x)	(ei_local->reg_offset[x])
 #else
 #define EI_SHIFT(x)	(x)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index e20b849..bdaaad8 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2313,13 +2313,11 @@
 
 endmenu
 
-if !UML
 source "drivers/net/tokenring/Kconfig"
 
 source "drivers/net/wireless/Kconfig"
 
 source "drivers/net/pcmcia/Kconfig"
-endif
 
 source "drivers/net/wan/Kconfig"
 
diff --git a/drivers/net/acenic_firmware.h b/drivers/net/acenic_firmware.h
index 6d625d5..d7882dd 100644
--- a/drivers/net/acenic_firmware.h
+++ b/drivers/net/acenic_firmware.h
@@ -4397,7 +4397,7 @@
 0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024, 
 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 
 0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 };
-static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
+static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = {
 0x24486561, 0x6465723a, 0x202f7072, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
 0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, 
@@ -4571,7 +4571,7 @@
 0x0, 0x14c38, 0x14c38, 0x14b80, 
 0x14bc4, 0x14c38, 0x14c38, 0x0, 
 0x0, 0x0 };
-static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = {
+static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __devinitdata = {
 0x416c7465, 
 0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465, 
 0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, 
@@ -4612,7 +4612,7 @@
 #define tigon2FwSbssLen 0xcc
 #define tigon2FwBssAddr 0x00016f50
 #define tigon2FwBssLen 0x20c0
-static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
+static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = {
 0x0, 
 0x10000003, 0x0, 0xd, 0xd, 
 0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000, 
@@ -9154,7 +9154,7 @@
 0x24020001, 0x8f430328, 0x1021, 0x24630001, 
 0x3e00008, 0xaf430328, 0x3e00008, 0x0, 
 0x0, 0x0, 0x0, 0x0 };
-static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
+static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = {
 0x24486561, 0x6465723a, 0x202f7072, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
 0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, 
@@ -9425,7 +9425,7 @@
 0x14ed8, 0x14b8c, 0x14bd8, 0x14c24, 
 0x14ed8, 0x7365746d, 0x61636163, 0x74000000, 
 0x0, 0x0 };
-static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = {
+static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __devinitdata = {
 0x1, 
 0x1, 0x1, 0xc001fc, 0x3ffc, 
 0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49, 
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index c3267e4..15032f2 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1339,6 +1339,9 @@
 	if (netif_running(dev))
 		return -EBUSY;
 
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EINVAL;
+
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
 	spin_lock_irq(&bp->lock);
@@ -1876,6 +1879,12 @@
 	bp->dev->dev_addr[3] = eeprom[80];
 	bp->dev->dev_addr[4] = eeprom[83];
 	bp->dev->dev_addr[5] = eeprom[82];
+
+	if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){
+		printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n");
+		return -EINVAL;
+	}
+
 	memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
 
 	bp->phy_addr = eeprom[90] & 0x1f;
@@ -2033,6 +2042,11 @@
 
 	pci_save_state(bp->pdev);
 
+	/* Chip reset provides power to the b44 MAC & PCI cores, which 
+	 * is necessary for MAC register access.
+	 */ 
+	b44_chip_reset(bp);
+
 	printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
 	for (i = 0; i < 6; i++)
 		printk("%2.2x%c", dev->dev_addr[i],
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index f3f5825..6a40707 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2294,6 +2294,34 @@
 	port->sm_vars |= AD_PORT_BEGIN;
 }
 
+/*
+ * set link state for bonding master: if we have an active partnered
+ * aggregator, we're up, if not, we're down.  Presumes that we cannot
+ * have an active aggregator if there are no slaves with link up.
+ *
+ * Called by bond_set_carrier(). Return zero if carrier state does not
+ * change, nonzero if it does.
+ */
+int bond_3ad_set_carrier(struct bonding *bond)
+{
+	struct aggregator *agg;
+
+	agg = __get_active_agg(&(SLAVE_AD_INFO(bond->first_slave).aggregator));
+	if (agg && MAC_ADDRESS_COMPARE(&agg->partner_system, &null_mac_addr)) {
+		if (!netif_carrier_ok(bond->dev)) {
+			netif_carrier_on(bond->dev);
+			return 1;
+		}
+		return 0;
+	}
+
+	if (netif_carrier_ok(bond->dev)) {
+		netif_carrier_off(bond->dev);
+		return 1;
+	}
+	return 0;
+}
+
 /**
  * bond_3ad_get_active_agg_info - get information of the active aggregator
  * @bond: bonding struct to work on
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index 5ee2cef..6ad5ad6 100644
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -283,5 +283,6 @@
 int  bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
 int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
 int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev);
+int bond_3ad_set_carrier(struct bonding *bond);
 #endif //__BOND_3AD_H__
 
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 2d0ac16..55d2367 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -559,6 +559,42 @@
 /*------------------------------- Link status -------------------------------*/
 
 /*
+ * Set the carrier state for the master according to the state of its
+ * slaves.  If any slaves are up, the master is up.  In 802.3ad mode,
+ * do special 802.3ad magic.
+ *
+ * Returns zero if carrier state does not change, nonzero if it does.
+ */
+static int bond_set_carrier(struct bonding *bond)
+{
+	struct slave *slave;
+	int i;
+
+	if (bond->slave_cnt == 0)
+		goto down;
+
+	if (bond->params.mode == BOND_MODE_8023AD)
+		return bond_3ad_set_carrier(bond);
+
+	bond_for_each_slave(bond, slave, i) {
+		if (slave->link == BOND_LINK_UP) {
+			if (!netif_carrier_ok(bond->dev)) {
+				netif_carrier_on(bond->dev);
+				return 1;
+			}
+			return 0;
+		}
+	}
+
+down:
+	if (netif_carrier_ok(bond->dev)) {
+		netif_carrier_off(bond->dev);
+		return 1;
+	}
+	return 0;
+}
+
+/*
  * Get link speed and duplex from the slave's base driver
  * using ethtool. If for some reason the call fails or the
  * values are invalid, fake speed and duplex to 100/Full
@@ -1074,10 +1110,24 @@
 void bond_select_active_slave(struct bonding *bond)
 {
 	struct slave *best_slave;
+	int rv;
 
 	best_slave = bond_find_best_slave(bond);
 	if (best_slave != bond->curr_active_slave) {
 		bond_change_active_slave(bond, best_slave);
+		rv = bond_set_carrier(bond);
+		if (!rv)
+			return;
+
+		if (netif_carrier_ok(bond->dev)) {
+			printk(KERN_INFO DRV_NAME
+			       ": %s: first active interface up!\n",
+			       bond->dev->name);
+		} else {
+			printk(KERN_INFO DRV_NAME ": %s: "
+			       "now running without any active interface !\n",
+			       bond->dev->name);
+		}
 	}
 }
 
@@ -1458,10 +1508,14 @@
 		if (((!bond->curr_active_slave) ||
 		     (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) &&
 		    (new_slave->link != BOND_LINK_DOWN)) {
-			dprintk("This is the first active slave\n");
 			/* first slave or no active slave yet, and this link
 			   is OK, so make this interface the active one */
 			bond_change_active_slave(bond, new_slave);
+			printk(KERN_INFO DRV_NAME
+			       ": %s: first active interface up!\n",
+			       bond->dev->name);
+			netif_carrier_on(bond->dev);
+
 		} else {
 			dprintk("This is just a backup slave\n");
 			bond_set_slave_inactive_flags(new_slave);
@@ -1517,6 +1571,8 @@
 		break;
 	} /* switch(bond_mode) */
 
+	bond_set_carrier(bond);
+
 	write_unlock_bh(&bond->lock);
 
 	res = bond_create_slave_symlinks(bond_dev, slave_dev);
@@ -1656,18 +1712,12 @@
 		bond_alb_deinit_slave(bond, slave);
 	}
 
-	if (oldcurrent == slave) {
+	if (oldcurrent == slave)
 		bond_select_active_slave(bond);
 
-		if (!bond->curr_active_slave) {
-			printk(KERN_INFO DRV_NAME
-			       ": %s: now running without any active "
-			       "interface !\n",
-			       bond_dev->name);
-		}
-	}
-
 	if (bond->slave_cnt == 0) {
+		bond_set_carrier(bond);
+
 		/* if the last slave was removed, zero the mac address
 		 * of the master so it will be set by the application
 		 * to the mac address of the first slave
@@ -1751,6 +1801,8 @@
 
 	write_lock_bh(&bond->lock);
 
+	netif_carrier_off(bond_dev);
+
 	if (bond->slave_cnt == 0) {
 		goto out;
 	}
@@ -2187,15 +2239,9 @@
 
 		bond_select_active_slave(bond);
 
-		if (oldcurrent && !bond->curr_active_slave) {
-			printk(KERN_INFO DRV_NAME
-			       ": %s: now running without any active "
-			       "interface !\n",
-			       bond_dev->name);
-		}
-
 		write_unlock(&bond->curr_slave_lock);
-	}
+	} else
+		bond_set_carrier(bond);
 
 re_arm:
 	if (bond->params.miimon) {
@@ -2499,13 +2545,6 @@
 
 		bond_select_active_slave(bond);
 
-		if (oldcurrent && !bond->curr_active_slave) {
-			printk(KERN_INFO DRV_NAME
-			       ": %s: now running without any active "
-			       "interface !\n",
-			       bond_dev->name);
-		}
-
 		write_unlock(&bond->curr_slave_lock);
 	}
 
@@ -2579,12 +2618,15 @@
 					bond->current_arp_slave = NULL;
 				}
 
+				bond_set_carrier(bond);
+
 				if (slave == bond->curr_active_slave) {
 					printk(KERN_INFO DRV_NAME
 					       ": %s: %s is up and now the "
 					       "active interface\n",
 					       bond_dev->name,
 					       slave->dev->name);
+					netif_carrier_on(bond->dev);
 				} else {
 					printk(KERN_INFO DRV_NAME
 					       ": %s: backup interface %s is "
@@ -2844,7 +2886,8 @@
 			   (curr) ? curr->dev->name : "None");
 	}
 
-	seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down");
+	seq_printf(seq, "MII Status: %s\n", netif_carrier_ok(bond->dev) ?
+		   "up" : "down");
 	seq_printf(seq, "MII Polling Interval (ms): %d\n", bond->params.miimon);
 	seq_printf(seq, "Up Delay (ms): %d\n",
 		   bond->params.updelay * bond->params.miimon);
@@ -3159,7 +3202,7 @@
  * bond_netdev_event: handle netdev notifier chain events.
  *
  * This function receives events for the netdev chain.  The caller (an
- * ioctl handler calling notifier_call_chain) holds the necessary
+ * ioctl handler calling blocking_notifier_call_chain) holds the necessary
  * locks for us to safely manipulate the slave devices (RTNL lock,
  * dev_probe_lock).
  */
@@ -4531,6 +4574,8 @@
 	if (newbond)
 		*newbond = bond_dev->priv;
 
+	netif_carrier_off(bond_dev);
+
 	rtnl_unlock(); /* allows sysfs registration of net device */
 	res = bond_create_sysfs_entry(bond_dev->priv);
 	goto done;
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index ce9dc9b..0bdfe2c 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -22,8 +22,8 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION	"3.0.2"
-#define DRV_RELDATE	"February 21, 2006"
+#define DRV_VERSION	"3.0.3"
+#define DRV_RELDATE	"March 23, 2006"
 #define DRV_NAME	"bonding"
 #define DRV_DESCRIPTION	"Ethernet Channel Bonding Driver"
 
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index e7fc28b..7627a75 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -134,6 +134,7 @@
 #include <linux/random.h>
 #include <linux/init.h>
 #include <linux/if_vlan.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -2932,7 +2933,7 @@
 	if (id->driver_data & DEV_HAS_HIGH_DMA) {
 		/* packet format 3: supports 40-bit addressing */
 		np->desc_ver = DESC_VER_3;
-		if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) {
+		if (pci_set_dma_mask(pci_dev, DMA_39BIT_MASK)) {
 			printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n",
 					pci_name(pci_dev));
 		} else {
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index 9b8295e..ae71ed5 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -44,6 +44,7 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
+#include <linux/dma-mapping.h>
 
 #ifdef CONFIG_SERIAL_8250
 #include <linux/serial_core.h>
@@ -1195,17 +1196,17 @@
 	int err, pci_using_dac;
 
 	/* Configure DMA attributes. */
-	err = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+	err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
 	if (!err) {
 		pci_using_dac = 1;
-		err = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+		err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
 		if (err < 0) {
 			printk(KERN_ERR "%s: Unable to obtain 64 bit DMA "
 			       "for consistent allocations\n", pci_name(pdev));
 			goto out;
 		}
 	} else {
-		err = pci_set_dma_mask(pdev, 0xffffffffULL);
+		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		if (err) {
 			printk(KERN_ERR "%s: No usable DMA configuration, "
 			       "aborting.\n", pci_name(pdev));
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 83141a3..cc7ff8f 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -207,7 +207,7 @@
  	/* Register with PnP subsystem to detect disable ports */
 	ret = pnp_register_driver(&nsc_ircc_pnp_driver);
 
- 	if (ret >= 0)
+ 	if (!ret)
  		pnp_registered = 1;
 
 	ret = -ENODEV;
@@ -812,7 +812,7 @@
 	int cfg_base = info->cfg_base;
 	int enabled;
 
-	/* User is shure about his config... accept it. */
+	/* User is sure about his config... accept it. */
 	IRDA_DEBUG(2, "%s(): nsc_ircc_init_39x (user settings): "
 		   "io=0x%04x, irq=%d, dma=%d\n", 
 		   __FUNCTION__, info->fir_base, info->irq, info->dma);
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index 77f104a..fbc2d21 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -299,10 +299,7 @@
 	int i;
 	int err;
 
-	if (RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192) {
-		static void __too_many_rx_or_tx_buffers(void);
-		__too_many_rx_or_tx_buffers();
-	}
+	BUILD_BUG_ON(RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192);
 
 	printk(KERN_INFO "IXP2000 MSF ethernet driver %s\n", DRV_MODULE_VERSION);
 
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 0c13795..b79d6e8 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -172,7 +172,7 @@
 
 	memset(stats, 0, sizeof(struct net_device_stats));
 
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		struct net_device_stats *lb_stats;
 
 		lb_stats = &per_cpu(loopback_stats, i);
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 8d49998..7826afb 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -226,7 +226,7 @@
 				 NATSEMI_PG1_NREGS)
 #define NATSEMI_REGS_VER	1 /* v1 added RFDR registers */
 #define NATSEMI_REGS_SIZE	(NATSEMI_NREGS * sizeof(u32))
-#define NATSEMI_EEPROM_SIZE	24 /* 12 16-bit values */
+#define NATSEMI_DEF_EEPROM_SIZE	24 /* 12 16-bit values */
 
 /* Buffer sizes:
  * The nic writes 32-bit values, even if the upper bytes of
@@ -714,6 +714,8 @@
 	unsigned int iosize;
 	spinlock_t lock;
 	u32 msg_enable;
+	/* EEPROM data */
+	int eeprom_size;
 };
 
 static void move_int_phy(struct net_device *dev, int addr);
@@ -890,6 +892,7 @@
 	np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG;
 	np->hands_off = 0;
 	np->intr_status = 0;
+	np->eeprom_size = NATSEMI_DEF_EEPROM_SIZE;
 
 	/* Initial port:
 	 * - If the nic was configured to use an external phy and if find_mii
@@ -2582,7 +2585,8 @@
 
 static int get_eeprom_len(struct net_device *dev)
 {
-	return NATSEMI_EEPROM_SIZE;
+	struct netdev_private *np = netdev_priv(dev);
+	return np->eeprom_size;
 }
 
 static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
@@ -2669,15 +2673,20 @@
 static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
 {
 	struct netdev_private *np = netdev_priv(dev);
-	u8 eebuf[NATSEMI_EEPROM_SIZE];
+	u8 *eebuf;
 	int res;
 
+	eebuf = kmalloc(np->eeprom_size, GFP_KERNEL);
+	if (!eebuf)
+		return -ENOMEM;
+
 	eeprom->magic = PCI_VENDOR_ID_NS | (PCI_DEVICE_ID_NS_83815<<16);
 	spin_lock_irq(&np->lock);
 	res = netdev_get_eeprom(dev, eebuf);
 	spin_unlock_irq(&np->lock);
 	if (!res)
 		memcpy(data, eebuf+eeprom->offset, eeprom->len);
+	kfree(eebuf);
 	return res;
 }
 
@@ -3033,9 +3042,10 @@
 	int i;
 	u16 *ebuf = (u16 *)buf;
 	void __iomem * ioaddr = ns_ioaddr(dev);
+	struct netdev_private *np = netdev_priv(dev);
 
 	/* eeprom_read reads 16 bits, and indexes by 16 bits */
-	for (i = 0; i < NATSEMI_EEPROM_SIZE/2; i++) {
+	for (i = 0; i < np->eeprom_size/2; i++) {
 		ebuf[i] = eeprom_read(ioaddr, i);
 		/* The EEPROM itself stores data bit-swapped, but eeprom_read
 		 * reads it back "sanely". So we swap it back here in order to
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index edd1b53..75b35ad 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -94,7 +94,7 @@
 static int option_setup(char *opt)
 {
 	configured = !netpoll_parse_options(&np, opt);
-	return 0;
+	return 1;
 }
 
 __setup("netconsole=", option_setup);
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 0fede50..8e9b1a5 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1828,10 +1828,10 @@
 	int using_dac = 0;
 
 	/* See if we can set the dma mask early on; failure is fatal. */
-	if (sizeof(dma_addr_t) == 8 && 
-	 	!pci_set_dma_mask(pci_dev, 0xffffffffffffffffULL)) {
+	if (sizeof(dma_addr_t) == 8 &&
+	 	!pci_set_dma_mask(pci_dev, DMA_64BIT_MASK)) {
 		using_dac = 1;
-	} else if (!pci_set_dma_mask(pci_dev, 0xffffffff)) {
+	} else if (!pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
 		using_dac = 0;
 	} else {
 		printk(KERN_WARNING "ns83820.c: pci_set_dma_mask failed!\n");
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index aa55813..1cc94b2 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -35,6 +35,7 @@
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
 #include <linux/netdevice.h>
+#include <linux/crc32.h>
 #include "../8390.h"
 
 #include <pcmcia/cs_types.h>
@@ -1682,17 +1683,67 @@
 	return &ei_local->stat;
 }
 
+/*
+ * Form the 64 bit 8390 multicast table from the linked list of addresses
+ * associated with this dev structure.
+ */
+ 
+static inline void make_mc_bits(u8 *bits, struct net_device *dev)
+{
+	struct dev_mc_list *dmi;
+	u32 crc;
+
+	for (dmi=dev->mc_list; dmi; dmi=dmi->next) {
+		
+		crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
+		/* 
+		 * The 8390 uses the 6 most significant bits of the
+		 * CRC to index the multicast table.
+		 */
+		bits[crc>>29] |= (1<<((crc>>26)&7));
+	}
+}
+
 /**
  * do_set_multicast_list - set/clear multicast filter
  * @dev: net device for which multicast filter is adjusted
  *
- *	Set or clear the multicast filter for this adaptor. May be called
- *	from a BH in 2.1.x. Must be called with lock held. 
+ *	Set or clear the multicast filter for this adaptor.
+ *	Must be called with lock held. 
  */
  
 static void do_set_multicast_list(struct net_device *dev)
 {
 	long e8390_base = dev->base_addr;
+	int i;
+	struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+
+	if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
+		memset(ei_local->mcfilter, 0, 8);
+		if (dev->mc_list)
+			make_mc_bits(ei_local->mcfilter, dev);
+	} else {
+		/* set to accept-all */
+		memset(ei_local->mcfilter, 0xFF, 8);
+	}
+
+	/* 
+	 * DP8390 manuals don't specify any magic sequence for altering
+	 * the multicast regs on an already running card. To be safe, we
+	 * ensure multicast mode is off prior to loading up the new hash
+	 * table. If this proves to be not enough, we can always resort
+	 * to stopping the NIC, loading the table and then restarting.
+	 */
+	 
+	if (netif_running(dev))
+		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+
+	outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
+	for(i = 0; i < 8; i++) 
+	{
+		outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
+	}
+	outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
 
   	if(dev->flags&IFF_PROMISC)
   		outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
@@ -1794,12 +1845,6 @@
 		if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
 			printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
 	}
-	/*
-	 * Initialize the multicast list to accept-all.  If we enable multicast
-	 * the higher levels can do the filtering.
-	 */
-	for (i = 0; i < 8; i++)
-		outb_p(0xff, e8390_base + EN1_MULT + i);
 
 	outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
 	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index eed4968..e8f849e 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1973,7 +1973,7 @@
 	MAYBE_SET(lockup_hack, 6);
 #undef  MAYBE_SET
 
-	return 0;
+	return 1;
 }
 
 __setup("xirc2ps_cs=", setup_xirc2ps_cs);
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 9595f74..07c31f1 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -1167,8 +1167,8 @@
 	 * station address PROM at the base address and programmed into the
 	 * "Physical Address Registers" CSR12-14.
 	 * As a precautionary measure, we read the PROM values and complain if
-	 * they disagree with the CSRs.  Either way, we use the CSR values, and
-	 * double check that they are valid.
+	 * they disagree with the CSRs.  If they miscompare, and the PROM addr
+	 * is valid, then the PROM addr is used.
 	 */
 	for (i = 0; i < 3; i++) {
 		unsigned int val;
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 253440a..b82191d 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -1693,7 +1693,7 @@
  *
  *	Process receive interrupt events, 
  *	put buffer to higher layer and refill buffer pool
- *	Note: This fucntion is called by interrupt handler, 
+ *	Note: This function is called by interrupt handler,
  *	don't do "too much" work here
  */
 
@@ -1840,7 +1840,7 @@
  *
  *	Check for error condition and free socket buffer etc 
  *	schedule for more transmission as needed
- *	Note: This fucntion is called by interrupt handler, 
+ *	Note: This function is called by interrupt handler,
  *	don't do "too much" work here
  */
 
@@ -2283,7 +2283,7 @@
 	int i, table_entries;
 	u32 rx_mode;
 
-	/* 635 Hash Table entires = 256(2^16) */
+	/* 635 Hash Table entries = 256(2^16) */
 	if((sis_priv->chipset_rev >= SIS635A_900_REV) ||
 			(sis_priv->chipset_rev == SIS900B_900_REV))
 		table_entries = 16;
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 1f5975a..43f5e86 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -1442,7 +1442,7 @@
 	case SPIDER_NET_GRFAFLLINT: /* fallthrough */
 	case SPIDER_NET_GRMFLLINT:
 		if (netif_msg_intr(card) && net_ratelimit())
-			pr_err("Spider RX RAM full, incoming packets "
+			pr_debug("Spider RX RAM full, incoming packets "
 			       "might be discarded!\n");
 		spider_net_rx_irq_off(card);
 		tasklet_schedule(&card->rxram_full_tl);
@@ -2086,7 +2086,7 @@
 
 	spider_net_setup_netdev_ops(netdev);
 
-	netdev->features = 0;
+	netdev->features = NETIF_F_HW_CSUM;
 	/* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
 	 *		NETIF_F_HW_VLAN_FILTER */
 
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index b547332..964c096 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -69,8 +69,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.54"
-#define DRV_MODULE_RELDATE	"Mar 23, 2006"
+#define DRV_MODULE_VERSION	"3.55"
+#define DRV_MODULE_RELDATE	"Mar 27, 2006"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -497,33 +497,40 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&tp->indirect_lock, flags);
-	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
-	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+	if (tp->write32 != tg3_write_indirect_reg32) {
+		tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off);
+		tw32_f(TG3PCI_MEM_WIN_DATA, val);
 
-	/* Always leave this as zero. */
-	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+		/* Always leave this as zero. */
+		tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0);
+	} else {
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+
+		/* Always leave this as zero. */
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+	}
 	spin_unlock_irqrestore(&tp->indirect_lock, flags);
 }
 
-static void tg3_write_mem_fast(struct tg3 *tp, u32 off, u32 val)
-{
-	/* If no workaround is needed, write to mem space directly */
-	if (tp->write32 != tg3_write_indirect_reg32)
-		tw32(NIC_SRAM_WIN_BASE + off, val);
-	else
-		tg3_write_mem(tp, off, val);
-}
-
 static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&tp->indirect_lock, flags);
-	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
-	pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+	if (tp->write32 != tg3_write_indirect_reg32) {
+		tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off);
+		*val = tr32(TG3PCI_MEM_WIN_DATA);
 
-	/* Always leave this as zero. */
-	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+		/* Always leave this as zero. */
+		tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0);
+	} else {
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+		pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+
+		/* Always leave this as zero. */
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+	}
 	spin_unlock_irqrestore(&tp->indirect_lock, flags);
 }
 
@@ -1367,12 +1374,12 @@
 		}
 	}
 
+	tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
+
 	/* Finally, set the new power state. */
 	pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
 	udelay(100);	/* Delay after power state change */
 
-	tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
-
 	return 0;
 }
 
@@ -3600,7 +3607,7 @@
 					  int len)
 {
 #if defined(CONFIG_HIGHMEM) && (BITS_PER_LONG == 64)
-	if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
+	if (tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG)
 		return (((u64) mapping + len) > DMA_40BIT_MASK);
 	return 0;
 #else
@@ -6461,6 +6468,9 @@
 {
 	struct tg3 *tp = (struct tg3 *) __opaque;
 
+	if (tp->irq_sync)
+		goto restart_timer;
+
 	spin_lock(&tp->lock);
 
 	if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
@@ -6537,11 +6547,11 @@
 		if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
 			u32 val;
 
-			tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_MBOX,
-					   FWCMD_NICDRV_ALIVE2);
-			tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
+			tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
+				      FWCMD_NICDRV_ALIVE2);
+			tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
 			/* 5 seconds timeout */
-			tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
+			tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
 			val = tr32(GRC_RX_CPU_EVENT);
 			val |= (1 << 14);
 			tw32(GRC_RX_CPU_EVENT, val);
@@ -6551,6 +6561,7 @@
 
 	spin_unlock(&tp->lock);
 
+restart_timer:
 	tp->timer.expires = jiffies + tp->timer_offset;
 	add_timer(&tp->timer);
 }
@@ -8399,8 +8410,11 @@
 		}
 		mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
 			   MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII;
-		if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)
+		if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
 			mac_mode &= ~MAC_MODE_LINK_POLARITY;
+			tg3_writephy(tp, MII_TG3_EXT_CTRL,
+				     MII_TG3_EXT_CTRL_LNK3_LED_MODE);
+		}
 		tw32(MAC_MODE, mac_mode);
 	}
 	else
@@ -10531,6 +10545,7 @@
 {
 	struct net_device *dev = tp->dev;
 	u32 hi, lo, mac_offset;
+	int addr_ok = 0;
 
 #ifdef CONFIG_SPARC64
 	if (!tg3_get_macaddr_sparc(tp))
@@ -10560,29 +10575,34 @@
 		dev->dev_addr[3] = (lo >> 16) & 0xff;
 		dev->dev_addr[4] = (lo >>  8) & 0xff;
 		dev->dev_addr[5] = (lo >>  0) & 0xff;
-	}
-	/* Next, try NVRAM. */
-	else if (!(tp->tg3_flags & TG3_FLG2_SUN_570X) &&
-		 !tg3_nvram_read(tp, mac_offset + 0, &hi) &&
-		 !tg3_nvram_read(tp, mac_offset + 4, &lo)) {
-		dev->dev_addr[0] = ((hi >> 16) & 0xff);
-		dev->dev_addr[1] = ((hi >> 24) & 0xff);
-		dev->dev_addr[2] = ((lo >>  0) & 0xff);
-		dev->dev_addr[3] = ((lo >>  8) & 0xff);
-		dev->dev_addr[4] = ((lo >> 16) & 0xff);
-		dev->dev_addr[5] = ((lo >> 24) & 0xff);
-	}
-	/* Finally just fetch it out of the MAC control regs. */
-	else {
-		hi = tr32(MAC_ADDR_0_HIGH);
-		lo = tr32(MAC_ADDR_0_LOW);
 
-		dev->dev_addr[5] = lo & 0xff;
-		dev->dev_addr[4] = (lo >> 8) & 0xff;
-		dev->dev_addr[3] = (lo >> 16) & 0xff;
-		dev->dev_addr[2] = (lo >> 24) & 0xff;
-		dev->dev_addr[1] = hi & 0xff;
-		dev->dev_addr[0] = (hi >> 8) & 0xff;
+		/* Some old bootcode may report a 0 MAC address in SRAM */
+		addr_ok = is_valid_ether_addr(&dev->dev_addr[0]);
+	}
+	if (!addr_ok) {
+		/* Next, try NVRAM. */
+		if (!(tp->tg3_flags & TG3_FLG2_SUN_570X) &&
+		    !tg3_nvram_read(tp, mac_offset + 0, &hi) &&
+		    !tg3_nvram_read(tp, mac_offset + 4, &lo)) {
+			dev->dev_addr[0] = ((hi >> 16) & 0xff);
+			dev->dev_addr[1] = ((hi >> 24) & 0xff);
+			dev->dev_addr[2] = ((lo >>  0) & 0xff);
+			dev->dev_addr[3] = ((lo >>  8) & 0xff);
+			dev->dev_addr[4] = ((lo >> 16) & 0xff);
+			dev->dev_addr[5] = ((lo >> 24) & 0xff);
+		}
+		/* Finally just fetch it out of the MAC control regs. */
+		else {
+			hi = tr32(MAC_ADDR_0_HIGH);
+			lo = tr32(MAC_ADDR_0_LOW);
+
+			dev->dev_addr[5] = lo & 0xff;
+			dev->dev_addr[4] = (lo >> 8) & 0xff;
+			dev->dev_addr[3] = (lo >> 16) & 0xff;
+			dev->dev_addr[2] = (lo >> 24) & 0xff;
+			dev->dev_addr[1] = hi & 0xff;
+			dev->dev_addr[0] = (hi >> 8) & 0xff;
+		}
 	}
 
 	if (!is_valid_ether_addr(&dev->dev_addr[0])) {
diff --git a/drivers/net/tokenring/Kconfig b/drivers/net/tokenring/Kconfig
index e4cfc80..99c4c19 100644
--- a/drivers/net/tokenring/Kconfig
+++ b/drivers/net/tokenring/Kconfig
@@ -3,7 +3,7 @@
 #
 
 menu "Token Ring devices"
-	depends on NETDEVICES
+	depends on NETDEVICES && !UML
 
 # So far, we only have PCI, ISA, and MCA token ring devices
 config TR
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index ee48bfd..f560941 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -513,7 +513,7 @@
     u_char  *rst;           /* Start of reset sequence in SROM           */
     u_int mc;               /* Media Capabilities                        */
     u_int ana;              /* NWay Advertisement                        */
-    u_int fdx;              /* Full DupleX capabilites for each media    */
+    u_int fdx;              /* Full DupleX capabilities for each media   */
     u_int ttm;              /* Transmit Threshold Mode for each media    */
     u_int mci;              /* 21142 MII Connector Interrupt info        */
 };
@@ -4160,7 +4160,7 @@
     ** If the address starts with 00 a0, we have to bit-reverse
     ** each byte of the address.
     */
-    if ( (_machine & _MACH_Pmac) &&
+    if ( machine_is(powermac) &&
 	 (dev->dev_addr[0] == 0) &&
 	 (dev->dev_addr[1] == 0xa0) )
     {
diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c
index 55f4a9a..ab98502 100644
--- a/drivers/net/tulip/pnic2.c
+++ b/drivers/net/tulip/pnic2.c
@@ -199,7 +199,7 @@
 	               /* negotiation ended successfully */
 
 	               /* get the link partners reply and mask out all but
-                        * bits 24-21 which show the partners capabilites
+                        * bits 24-21 which show the partners capabilities
                         * and match those to what we advertised
                         *
                         * then begin to interpret the results of the negotiation.
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index cde35dd..c1ce87a 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -208,7 +208,7 @@
 };
 
 /* Notes on the new subsystem numbering scheme:
- * bits 0-1 indicate crypto capabilites: (0) variable, (1) DES, or (2) 3DES
+ * bits 0-1 indicate crypto capabilities: (0) variable, (1) DES, or (2) 3DES
  * bit 4 indicates if this card has secured firmware (we don't support it)
  * bit 8 indicates if this is a (0) copper or (1) fiber card
  * bits 12-16 indicate card type: (0) client and (1) server
@@ -788,7 +788,7 @@
 	/* we have two rings to choose from, but we only use txLo for now
 	 * If we start using the Hi ring as well, we'll need to update
 	 * typhoon_stop_runtime(), typhoon_interrupt(), typhoon_num_free_tx(),
-	 * and TXHI_ENTIRES to match, as well as update the TSO code below
+	 * and TXHI_ENTRIES to match, as well as update the TSO code below
 	 * to get the right DMA address
 	 */
 	txRing = &tp->txLoRing;
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 241871589..a9b2150 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1085,6 +1085,25 @@
 	else
 	    iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex,
 		   ioaddr + ChipCmd1);
+	if (debug > 1)
+		printk(KERN_INFO "%s: force_media %d, carrier %d\n", dev->name,
+			rp->mii_if.force_media, netif_carrier_ok(dev));
+}
+
+/* Called after status of force_media possibly changed */
+void rhine_set_carrier(struct mii_if_info *mii)
+{
+	if (mii->force_media) {
+		/* autoneg is off: Link is always assumed to be up */
+		if (!netif_carrier_ok(mii->dev))
+			netif_carrier_on(mii->dev);
+	}
+	else	/* Let MMI library update carrier status */
+		rhine_check_media(mii->dev, 0);
+	if (debug > 1)
+		printk(KERN_INFO "%s: force_media %d, carrier %d\n",
+		       mii->dev->name, mii->force_media,
+		       netif_carrier_ok(mii->dev));
 }
 
 static void rhine_check_media_task(struct net_device *dev)
@@ -1782,6 +1801,7 @@
 	spin_lock_irq(&rp->lock);
 	rc = mii_ethtool_sset(&rp->mii_if, cmd);
 	spin_unlock_irq(&rp->lock);
+	rhine_set_carrier(&rp->mii_if);
 
 	return rc;
 }
@@ -1869,6 +1889,7 @@
 	spin_lock_irq(&rp->lock);
 	rc = generic_mii_ioctl(&rp->mii_if, if_mii(rq), cmd, NULL);
 	spin_unlock_irq(&rp->lock);
+	rhine_set_carrier(&rp->mii_if);
 
 	return rc;
 }
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 1ff5de0..4505540 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -105,6 +105,7 @@
 #include <linux/delay.h>
 #include <net/syncppp.h>
 #include <linux/hdlc.h>
+#include <linux/mutex.h>
 
 /* Version */
 static const char version[] = "$Id: dscc4.c,v 1.173 2003/09/20 23:55:34 romieu Exp $ for Linux\n";
@@ -112,7 +113,7 @@
 static int quartz;
 
 #ifdef CONFIG_DSCC4_PCI_RST
-static DECLARE_MUTEX(dscc4_sem);
+static DEFINE_MUTEX(dscc4_mutex);
 static u32 dscc4_pci_config_store[16];
 #endif
 
@@ -1018,7 +1019,7 @@
 {
 	int i;
 
-	down(&dscc4_sem);
+	mutex_lock(&dscc4_mutex);
 	for (i = 0; i < 16; i++)
 		pci_read_config_dword(pdev, i << 2, dscc4_pci_config_store + i);
 
@@ -1039,7 +1040,7 @@
 
 	for (i = 0; i < 16; i++)
 		pci_write_config_dword(pdev, i << 2, dscc4_pci_config_store[i]);
-	up(&dscc4_sem);
+	mutex_unlock(&dscc4_mutex);
 }
 #else
 #define dscc4_pci_reset(pdev,ioaddr)	do {} while (0)
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index 9d3b51c..29a756d 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -577,8 +577,8 @@
 	   We set both dma_mask and consistent_dma_mask to 28 bits
 	   and pray pci_alloc_consistent() will use this info. It should
 	   work on most platforms */
-	if (pci_set_consistent_dma_mask(pdev, 0x0FFFFFFF) ||
-	    pci_set_dma_mask(pdev, 0x0FFFFFFF)) {
+	if (pci_set_consistent_dma_mask(pdev, DMA_28BIT_MASK) ||
+	    pci_set_dma_mask(pdev, DMA_28BIT_MASK)) {
 		printk(KERN_ERR "wanXL: No usable DMA configuration\n");
 		return -EIO;
 	}
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index fd17aa8..bad09eb 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -309,7 +309,10 @@
 	  Say Y here to support the Airport 802.11b wireless Ethernet hardware
 	  built into the Macintosh iBook and other recent PowerPC-based
 	  Macintosh machines. This is essentially a Lucent Orinoco card with 
-	  a non-standard interface
+	  a non-standard interface.
+
+	  This driver does not support the Airport Extreme (802.11b/g). Use
+	  the BCM43xx driver for Airport Extreme cards.
 
 config PLX_HERMES
 	tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)"
@@ -353,7 +356,7 @@
 
 config ATMEL
       tristate "Atmel at76c50x chipset  802.11b support"
-      depends on NET_RADIO
+      depends on NET_RADIO && (PCI || PCMCIA)
       select FW_LOADER
       select CRC32
        ---help---
@@ -401,6 +404,7 @@
 config PCMCIA_SPECTRUM
 	tristate "Symbol Spectrum24 Trilogy PCMCIA card support"
 	depends on NET_RADIO && PCMCIA && HERMES
+	select FW_LOADER
 	---help---
 
 	  This is a driver for 802.11b cards using RAM-loadable Symbol
@@ -500,6 +504,7 @@
 	  will be called prism54.ko.
 
 source "drivers/net/wireless/hostap/Kconfig"
+source "drivers/net/wireless/bcm43xx/Kconfig"
 
 # yes, this works even when no drivers are selected
 config NET_WIRELESS
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 3a6f7ba..c867798 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -35,6 +35,7 @@
 obj-$(CONFIG_PRISM54)		+= prism54/
 
 obj-$(CONFIG_HOSTAP)		+= hostap/
+obj-$(CONFIG_BCM43XX)		+= bcm43xx/
 
 # 16-bit wireless PCMCIA client drivers
 obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig
new file mode 100644
index 0000000..4184656
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/Kconfig
@@ -0,0 +1,62 @@
+config BCM43XX
+	tristate "Broadcom BCM43xx wireless support"
+	depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL
+	select FW_LOADER
+	---help---
+	  This is an experimental driver for the Broadcom 43xx wireless chip,
+	  found in the Apple Airport Extreme and various other devices.
+
+config BCM43XX_DEBUG
+	bool "Broadcom BCM43xx debugging (RECOMMENDED)"
+	depends on BCM43XX
+	default y
+	---help---
+	  Broadcom 43xx debugging messages.
+	  Say Y, because the driver is still very experimental and
+	  this will help you get it running.
+
+config BCM43XX_DMA
+	bool
+config BCM43XX_PIO
+	bool
+
+choice
+	prompt "BCM43xx data transfer mode"
+	depends on BCM43XX
+	default BCM43XX_DMA_AND_PIO_MODE
+
+config BCM43XX_DMA_AND_PIO_MODE
+	bool "DMA + PIO"
+	select BCM43XX_DMA
+	select BCM43XX_PIO
+	---help---
+	  Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
+	  data transfer modes.
+	  The actually used mode is selectable through the module
+	  parameter "pio". If the module parameter is pio=0, DMA is used.
+	  Otherwise PIO is used. DMA is default.
+
+	  If unsure, choose this option.
+
+config BCM43XX_DMA_MODE
+	bool "DMA (Direct Memory Access) only"
+	select BCM43XX_DMA
+	---help---
+	  Only include Direct Memory Access (DMA).
+	  This reduces the size of the driver module, by omitting the PIO code.
+
+config BCM43XX_PIO_MODE
+	bool "PIO (Programmed I/O) only"
+	select BCM43XX_PIO
+	---help---
+	  Only include Programmed I/O (PIO).
+	  This reduces the size of the driver module, by omitting the DMA code.
+	  Please note that PIO transfers are slow (compared to DMA).
+
+	  Also note that not all devices of the 43xx series support PIO.
+	  The 4306 (Apple Airport Extreme and others) supports PIO, while
+	  the 4318 is known to _not_ support PIO.
+
+	  Only use PIO, if DMA does not work for you.
+
+endchoice
diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile
new file mode 100644
index 0000000..bb5220c
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/Makefile
@@ -0,0 +1,12 @@
+obj-$(CONFIG_BCM43XX) += bcm43xx.o
+bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.o
+
+bcm43xx-obj-$(CONFIG_BCM43XX_DMA) += bcm43xx_dma.o
+bcm43xx-obj-$(CONFIG_BCM43XX_PIO) += bcm43xx_pio.o
+
+bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \
+		bcm43xx_radio.o bcm43xx_phy.o \
+		bcm43xx_power.o bcm43xx_wx.o \
+		bcm43xx_leds.o bcm43xx_ethtool.o \
+		bcm43xx_xmit.o bcm43xx_sysfs.o \
+		$(bcm43xx-obj-y)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
new file mode 100644
index 0000000..dcadd29
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -0,0 +1,926 @@
+#ifndef BCM43xx_H_
+#define BCM43xx_H_
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/stringify.h>
+#include <linux/pci.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211softmac.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+
+
+#include "bcm43xx_debugfs.h"
+#include "bcm43xx_leds.h"
+#include "bcm43xx_sysfs.h"
+
+
+#define PFX				KBUILD_MODNAME ": "
+
+#define BCM43xx_SWITCH_CORE_MAX_RETRIES	50
+#define BCM43xx_IRQWAIT_MAX_RETRIES	50
+
+#define BCM43xx_IO_SIZE			8192
+
+/* Active Core PCI Configuration Register. */
+#define BCM43xx_PCICFG_ACTIVE_CORE	0x80
+/* SPROM control register. */
+#define BCM43xx_PCICFG_SPROMCTL		0x88
+/* Interrupt Control PCI Configuration Register. (Only on PCI cores with rev >= 6) */
+#define BCM43xx_PCICFG_ICR		0x94
+
+/* MMIO offsets */
+#define BCM43xx_MMIO_DMA1_REASON	0x20
+#define BCM43xx_MMIO_DMA1_IRQ_MASK	0x24
+#define BCM43xx_MMIO_DMA2_REASON	0x28
+#define BCM43xx_MMIO_DMA2_IRQ_MASK	0x2C
+#define BCM43xx_MMIO_DMA3_REASON	0x30
+#define BCM43xx_MMIO_DMA3_IRQ_MASK	0x34
+#define BCM43xx_MMIO_DMA4_REASON	0x38
+#define BCM43xx_MMIO_DMA4_IRQ_MASK	0x3C
+#define BCM43xx_MMIO_STATUS_BITFIELD	0x120
+#define BCM43xx_MMIO_STATUS2_BITFIELD	0x124
+#define BCM43xx_MMIO_GEN_IRQ_REASON	0x128
+#define BCM43xx_MMIO_GEN_IRQ_MASK	0x12C
+#define BCM43xx_MMIO_RAM_CONTROL	0x130
+#define BCM43xx_MMIO_RAM_DATA		0x134
+#define BCM43xx_MMIO_PS_STATUS		0x140
+#define BCM43xx_MMIO_RADIO_HWENABLED_HI	0x158
+#define BCM43xx_MMIO_SHM_CONTROL	0x160
+#define BCM43xx_MMIO_SHM_DATA		0x164
+#define BCM43xx_MMIO_SHM_DATA_UNALIGNED	0x166
+#define BCM43xx_MMIO_XMITSTAT_0		0x170
+#define BCM43xx_MMIO_XMITSTAT_1		0x174
+#define BCM43xx_MMIO_REV3PLUS_TSF_LOW	0x180 /* core rev >= 3 only */
+#define BCM43xx_MMIO_REV3PLUS_TSF_HIGH	0x184 /* core rev >= 3 only */
+#define BCM43xx_MMIO_DMA1_BASE		0x200
+#define BCM43xx_MMIO_DMA2_BASE		0x220
+#define BCM43xx_MMIO_DMA3_BASE		0x240
+#define BCM43xx_MMIO_DMA4_BASE		0x260
+#define BCM43xx_MMIO_PIO1_BASE		0x300
+#define BCM43xx_MMIO_PIO2_BASE		0x310
+#define BCM43xx_MMIO_PIO3_BASE		0x320
+#define BCM43xx_MMIO_PIO4_BASE		0x330
+#define BCM43xx_MMIO_PHY_VER		0x3E0
+#define BCM43xx_MMIO_PHY_RADIO		0x3E2
+#define BCM43xx_MMIO_ANTENNA		0x3E8
+#define BCM43xx_MMIO_CHANNEL		0x3F0
+#define BCM43xx_MMIO_CHANNEL_EXT	0x3F4
+#define BCM43xx_MMIO_RADIO_CONTROL	0x3F6
+#define BCM43xx_MMIO_RADIO_DATA_HIGH	0x3F8
+#define BCM43xx_MMIO_RADIO_DATA_LOW	0x3FA
+#define BCM43xx_MMIO_PHY_CONTROL	0x3FC
+#define BCM43xx_MMIO_PHY_DATA		0x3FE
+#define BCM43xx_MMIO_MACFILTER_CONTROL	0x420
+#define BCM43xx_MMIO_MACFILTER_DATA	0x422
+#define BCM43xx_MMIO_RADIO_HWENABLED_LO	0x49A
+#define BCM43xx_MMIO_GPIO_CONTROL	0x49C
+#define BCM43xx_MMIO_GPIO_MASK		0x49E
+#define BCM43xx_MMIO_TSF_0		0x632 /* core rev < 3 only */
+#define BCM43xx_MMIO_TSF_1		0x634 /* core rev < 3 only */
+#define BCM43xx_MMIO_TSF_2		0x636 /* core rev < 3 only */
+#define BCM43xx_MMIO_TSF_3		0x638 /* core rev < 3 only */
+#define BCM43xx_MMIO_POWERUP_DELAY	0x6A8
+
+/* SPROM offsets. */
+#define BCM43xx_SPROM_BASE		0x1000
+#define BCM43xx_SPROM_BOARDFLAGS2	0x1c
+#define BCM43xx_SPROM_IL0MACADDR	0x24
+#define BCM43xx_SPROM_ET0MACADDR	0x27
+#define BCM43xx_SPROM_ET1MACADDR	0x2a
+#define BCM43xx_SPROM_ETHPHY		0x2d
+#define BCM43xx_SPROM_BOARDREV		0x2e
+#define BCM43xx_SPROM_PA0B0		0x2f
+#define BCM43xx_SPROM_PA0B1		0x30
+#define BCM43xx_SPROM_PA0B2		0x31
+#define BCM43xx_SPROM_WL0GPIO0		0x32
+#define BCM43xx_SPROM_WL0GPIO2		0x33
+#define BCM43xx_SPROM_MAXPWR		0x34
+#define BCM43xx_SPROM_PA1B0		0x35
+#define BCM43xx_SPROM_PA1B1		0x36
+#define BCM43xx_SPROM_PA1B2		0x37
+#define BCM43xx_SPROM_IDL_TSSI_TGT	0x38
+#define BCM43xx_SPROM_BOARDFLAGS	0x39
+#define BCM43xx_SPROM_ANTENNA_GAIN	0x3a
+#define BCM43xx_SPROM_VERSION		0x3f
+
+/* BCM43xx_SPROM_BOARDFLAGS values */
+#define BCM43xx_BFL_BTCOEXIST		0x0001 /* implements Bluetooth coexistance */
+#define BCM43xx_BFL_PACTRL		0x0002 /* GPIO 9 controlling the PA */
+#define BCM43xx_BFL_AIRLINEMODE		0x0004 /* implements GPIO 13 radio disable indication */
+#define BCM43xx_BFL_RSSI		0x0008 /* software calculates nrssi slope. */
+#define BCM43xx_BFL_ENETSPI		0x0010 /* has ephy roboswitch spi */
+#define BCM43xx_BFL_XTAL_NOSLOW		0x0020 /* no slow clock available */
+#define BCM43xx_BFL_CCKHIPWR		0x0040 /* can do high power CCK transmission */
+#define BCM43xx_BFL_ENETADM		0x0080 /* has ADMtek switch */
+#define BCM43xx_BFL_ENETVLAN		0x0100 /* can do vlan */
+#define BCM43xx_BFL_AFTERBURNER		0x0200 /* supports Afterburner mode */
+#define BCM43xx_BFL_NOPCI		0x0400 /* leaves PCI floating */
+#define BCM43xx_BFL_FEM			0x0800 /* supports the Front End Module */
+#define BCM43xx_BFL_EXTLNA		0x1000 /* has an external LNA */
+#define BCM43xx_BFL_HGPA		0x2000 /* had high gain PA */
+#define BCM43xx_BFL_BTCMOD		0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */
+#define BCM43xx_BFL_ALTIQ		0x8000 /* alternate I/Q settings */
+
+/* GPIO register offset, in both ChipCommon and PCI core. */
+#define BCM43xx_GPIO_CONTROL		0x6c
+
+/* SHM Routing */
+#define BCM43xx_SHM_SHARED		0x0001
+#define BCM43xx_SHM_WIRELESS		0x0002
+#define BCM43xx_SHM_PCM			0x0003
+#define BCM43xx_SHM_HWMAC		0x0004
+#define BCM43xx_SHM_UCODE		0x0300
+
+/* MacFilter offsets. */
+#define BCM43xx_MACFILTER_SELF		0x0000
+#define BCM43xx_MACFILTER_ASSOC		0x0003
+
+/* Chipcommon registers. */
+#define BCM43xx_CHIPCOMMON_CAPABILITIES 	0x04
+#define BCM43xx_CHIPCOMMON_PLLONDELAY		0xB0
+#define BCM43xx_CHIPCOMMON_FREFSELDELAY		0xB4
+#define BCM43xx_CHIPCOMMON_SLOWCLKCTL		0xB8
+#define BCM43xx_CHIPCOMMON_SYSCLKCTL		0xC0
+
+/* PCI core specific registers. */
+#define BCM43xx_PCICORE_BCAST_ADDR	0x50
+#define BCM43xx_PCICORE_BCAST_DATA	0x54
+#define BCM43xx_PCICORE_SBTOPCI2	0x108
+
+/* SBTOPCI2 values. */
+#define BCM43xx_SBTOPCI2_PREFETCH	0x4
+#define BCM43xx_SBTOPCI2_BURST		0x8
+
+/* Chipcommon capabilities. */
+#define BCM43xx_CAPABILITIES_PCTL		0x00040000
+#define BCM43xx_CAPABILITIES_PLLMASK		0x00030000
+#define BCM43xx_CAPABILITIES_PLLSHIFT		16
+#define BCM43xx_CAPABILITIES_FLASHMASK		0x00000700
+#define BCM43xx_CAPABILITIES_FLASHSHIFT		8
+#define BCM43xx_CAPABILITIES_EXTBUSPRESENT	0x00000040
+#define BCM43xx_CAPABILITIES_UARTGPIO		0x00000020
+#define BCM43xx_CAPABILITIES_UARTCLOCKMASK	0x00000018
+#define BCM43xx_CAPABILITIES_UARTCLOCKSHIFT	3
+#define BCM43xx_CAPABILITIES_MIPSBIGENDIAN	0x00000004
+#define BCM43xx_CAPABILITIES_NRUARTSMASK	0x00000003
+
+/* PowerControl */
+#define BCM43xx_PCTL_IN			0xB0
+#define BCM43xx_PCTL_OUT		0xB4
+#define BCM43xx_PCTL_OUTENABLE		0xB8
+#define BCM43xx_PCTL_XTAL_POWERUP	0x40
+#define BCM43xx_PCTL_PLL_POWERDOWN	0x80
+
+/* PowerControl Clock Modes */
+#define BCM43xx_PCTL_CLK_FAST		0x00
+#define BCM43xx_PCTL_CLK_SLOW		0x01
+#define BCM43xx_PCTL_CLK_DYNAMIC	0x02
+
+#define BCM43xx_PCTL_FORCE_SLOW		0x0800
+#define BCM43xx_PCTL_FORCE_PLL		0x1000
+#define BCM43xx_PCTL_DYN_XTAL		0x2000
+
+/* COREIDs */
+#define BCM43xx_COREID_CHIPCOMMON	0x800
+#define BCM43xx_COREID_ILINE20          0x801
+#define BCM43xx_COREID_SDRAM            0x803
+#define BCM43xx_COREID_PCI		0x804
+#define BCM43xx_COREID_MIPS             0x805
+#define BCM43xx_COREID_ETHERNET         0x806
+#define BCM43xx_COREID_V90		0x807
+#define BCM43xx_COREID_USB11_HOSTDEV    0x80a
+#define BCM43xx_COREID_IPSEC            0x80b
+#define BCM43xx_COREID_PCMCIA		0x80d
+#define BCM43xx_COREID_EXT_IF           0x80f
+#define BCM43xx_COREID_80211		0x812
+#define BCM43xx_COREID_MIPS_3302        0x816
+#define BCM43xx_COREID_USB11_HOST       0x817
+#define BCM43xx_COREID_USB11_DEV        0x818
+#define BCM43xx_COREID_USB20_HOST       0x819
+#define BCM43xx_COREID_USB20_DEV        0x81a
+#define BCM43xx_COREID_SDIO_HOST        0x81b
+
+/* Core Information Registers */
+#define BCM43xx_CIR_BASE		0xf00
+#define BCM43xx_CIR_SBTPSFLAG		(BCM43xx_CIR_BASE + 0x18)
+#define BCM43xx_CIR_SBIMSTATE		(BCM43xx_CIR_BASE + 0x90)
+#define BCM43xx_CIR_SBINTVEC		(BCM43xx_CIR_BASE + 0x94)
+#define BCM43xx_CIR_SBTMSTATELOW	(BCM43xx_CIR_BASE + 0x98)
+#define BCM43xx_CIR_SBTMSTATEHIGH	(BCM43xx_CIR_BASE + 0x9c)
+#define BCM43xx_CIR_SBIMCONFIGLOW	(BCM43xx_CIR_BASE + 0xa8)
+#define BCM43xx_CIR_SB_ID_HI		(BCM43xx_CIR_BASE + 0xfc)
+
+/* Mask to get the Backplane Flag Number from SBTPSFLAG. */
+#define BCM43xx_BACKPLANE_FLAG_NR_MASK	0x3f
+
+/* SBIMCONFIGLOW values/masks. */
+#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK		0x00000007
+#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT	0
+#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK		0x00000070
+#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT	4
+#define BCM43xx_SBIMCONFIGLOW_CONNID_MASK		0x00ff0000
+#define BCM43xx_SBIMCONFIGLOW_CONNID_SHIFT		16
+
+/* sbtmstatelow state flags */
+#define BCM43xx_SBTMSTATELOW_RESET		0x01
+#define BCM43xx_SBTMSTATELOW_REJECT		0x02
+#define BCM43xx_SBTMSTATELOW_CLOCK		0x10000
+#define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK	0x20000
+
+/* sbtmstatehigh state flags */
+#define BCM43xx_SBTMSTATEHIGH_SERROR		0x1
+#define BCM43xx_SBTMSTATEHIGH_BUSY		0x4
+
+/* sbimstate flags */
+#define BCM43xx_SBIMSTATE_IB_ERROR		0x20000
+#define BCM43xx_SBIMSTATE_TIMEOUT		0x40000
+
+/* PHYVersioning */
+#define BCM43xx_PHYTYPE_A		0x00
+#define BCM43xx_PHYTYPE_B		0x01
+#define BCM43xx_PHYTYPE_G		0x02
+
+/* PHYRegisters */
+#define BCM43xx_PHY_ILT_A_CTRL		0x0072
+#define BCM43xx_PHY_ILT_A_DATA1		0x0073
+#define BCM43xx_PHY_ILT_A_DATA2		0x0074
+#define BCM43xx_PHY_G_LO_CONTROL	0x0810
+#define BCM43xx_PHY_ILT_G_CTRL		0x0472
+#define BCM43xx_PHY_ILT_G_DATA1		0x0473
+#define BCM43xx_PHY_ILT_G_DATA2		0x0474
+#define BCM43xx_PHY_A_PCTL		0x007B
+#define BCM43xx_PHY_G_PCTL		0x0029
+#define BCM43xx_PHY_A_CRS		0x0029
+#define BCM43xx_PHY_RADIO_BITFIELD	0x0401
+#define BCM43xx_PHY_G_CRS		0x0429
+#define BCM43xx_PHY_NRSSILT_CTRL	0x0803
+#define BCM43xx_PHY_NRSSILT_DATA	0x0804
+
+/* RadioRegisters */
+#define BCM43xx_RADIOCTL_ID		0x01
+
+/* StatusBitField */
+#define BCM43xx_SBF_MAC_ENABLED		0x00000001
+#define BCM43xx_SBF_2			0x00000002 /*FIXME: fix name*/
+#define BCM43xx_SBF_CORE_READY		0x00000004
+#define BCM43xx_SBF_400			0x00000400 /*FIXME: fix name*/
+#define BCM43xx_SBF_4000		0x00004000 /*FIXME: fix name*/
+#define BCM43xx_SBF_8000		0x00008000 /*FIXME: fix name*/
+#define BCM43xx_SBF_XFER_REG_BYTESWAP	0x00010000
+#define BCM43xx_SBF_MODE_NOTADHOC	0x00020000
+#define BCM43xx_SBF_MODE_AP		0x00040000
+#define BCM43xx_SBF_RADIOREG_LOCK	0x00080000
+#define BCM43xx_SBF_MODE_MONITOR	0x00400000
+#define BCM43xx_SBF_MODE_PROMISC	0x01000000
+#define BCM43xx_SBF_PS1			0x02000000
+#define BCM43xx_SBF_PS2			0x04000000
+#define BCM43xx_SBF_NO_SSID_BCAST	0x08000000
+#define BCM43xx_SBF_TIME_UPDATE		0x10000000
+#define BCM43xx_SBF_80000000		0x80000000 /*FIXME: fix name*/
+
+/* MicrocodeFlagsBitfield (addr + lo-word values?)*/
+#define BCM43xx_UCODEFLAGS_OFFSET	0x005E
+
+#define BCM43xx_UCODEFLAG_AUTODIV	0x0001
+#define BCM43xx_UCODEFLAG_UNKBGPHY	0x0002
+#define BCM43xx_UCODEFLAG_UNKBPHY	0x0004
+#define BCM43xx_UCODEFLAG_UNKGPHY	0x0020
+#define BCM43xx_UCODEFLAG_UNKPACTRL	0x0040
+#define BCM43xx_UCODEFLAG_JAPAN		0x0080
+
+/* Generic-Interrupt reasons. */
+#define BCM43xx_IRQ_READY		(1 << 0)
+#define BCM43xx_IRQ_BEACON		(1 << 1)
+#define BCM43xx_IRQ_PS			(1 << 2)
+#define BCM43xx_IRQ_REG124		(1 << 5)
+#define BCM43xx_IRQ_PMQ			(1 << 6)
+#define BCM43xx_IRQ_PIO_WORKAROUND	(1 << 8)
+#define BCM43xx_IRQ_XMIT_ERROR		(1 << 11)
+#define BCM43xx_IRQ_RX			(1 << 15)
+#define BCM43xx_IRQ_SCAN		(1 << 16)
+#define BCM43xx_IRQ_NOISE		(1 << 18)
+#define BCM43xx_IRQ_XMIT_STATUS		(1 << 29)
+
+#define BCM43xx_IRQ_ALL			0xffffffff
+#define BCM43xx_IRQ_INITIAL		(BCM43xx_IRQ_PS |		\
+					 BCM43xx_IRQ_REG124 |		\
+					 BCM43xx_IRQ_PMQ |		\
+					 BCM43xx_IRQ_XMIT_ERROR |	\
+					 BCM43xx_IRQ_RX |		\
+					 BCM43xx_IRQ_SCAN |		\
+					 BCM43xx_IRQ_NOISE |		\
+					 BCM43xx_IRQ_XMIT_STATUS)
+					 
+
+/* Initial default iw_mode */
+#define BCM43xx_INITIAL_IWMODE			IW_MODE_INFRA
+
+/* Bus type PCI. */
+#define BCM43xx_BUSTYPE_PCI	0
+/* Bus type Silicone Backplane Bus. */
+#define BCM43xx_BUSTYPE_SB	1
+/* Bus type PCMCIA. */
+#define BCM43xx_BUSTYPE_PCMCIA	2
+
+/* Threshold values. */
+#define BCM43xx_MIN_RTS_THRESHOLD		1U
+#define BCM43xx_MAX_RTS_THRESHOLD		2304U
+#define BCM43xx_DEFAULT_RTS_THRESHOLD		BCM43xx_MAX_RTS_THRESHOLD
+
+#define BCM43xx_DEFAULT_SHORT_RETRY_LIMIT	7
+#define BCM43xx_DEFAULT_LONG_RETRY_LIMIT	4
+
+/* Max size of a security key */
+#define BCM43xx_SEC_KEYSIZE			16
+/* Security algorithms. */
+enum {
+	BCM43xx_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
+	BCM43xx_SEC_ALGO_WEP,
+	BCM43xx_SEC_ALGO_UNKNOWN,
+	BCM43xx_SEC_ALGO_AES,
+	BCM43xx_SEC_ALGO_WEP104,
+	BCM43xx_SEC_ALGO_TKIP,
+};
+
+#ifdef assert
+# undef assert
+#endif
+#ifdef CONFIG_BCM43XX_DEBUG
+#define assert(expr) \
+	do {									\
+		if (unlikely(!(expr))) {					\
+		printk(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n",	\
+			#expr, __FILE__, __LINE__, __FUNCTION__);		\
+		}								\
+	} while (0)
+#else
+#define assert(expr)	do { /* nothing */ } while (0)
+#endif
+
+/* rate limited printk(). */
+#ifdef printkl
+# undef printkl
+#endif
+#define printkl(f, x...)  do { if (printk_ratelimit()) printk(f ,##x); } while (0)
+/* rate limited printk() for debugging */
+#ifdef dprintkl
+# undef dprintkl
+#endif
+#ifdef CONFIG_BCM43XX_DEBUG
+# define dprintkl		printkl
+#else
+# define dprintkl(f, x...)	do { /* nothing */ } while (0)
+#endif
+
+/* Helper macro for if branches.
+ * An if branch marked with this macro is only taken in DEBUG mode.
+ * Example:
+ *	if (DEBUG_ONLY(foo == bar)) {
+ *		do something
+ *	}
+ *	In DEBUG mode, the branch will be taken if (foo == bar).
+ *	In non-DEBUG mode, the branch will never be taken.
+ */
+#ifdef DEBUG_ONLY
+# undef DEBUG_ONLY
+#endif
+#ifdef CONFIG_BCM43XX_DEBUG
+# define DEBUG_ONLY(x)	(x)
+#else
+# define DEBUG_ONLY(x)	0
+#endif
+
+/* debugging printk() */
+#ifdef dprintk
+# undef dprintk
+#endif
+#ifdef CONFIG_BCM43XX_DEBUG
+# define dprintk(f, x...)  do { printk(f ,##x); } while (0)
+#else
+# define dprintk(f, x...)  do { /* nothing */ } while (0)
+#endif
+
+
+struct net_device;
+struct pci_dev;
+struct bcm43xx_dmaring;
+struct bcm43xx_pioqueue;
+
+struct bcm43xx_initval {
+	u16 offset;
+	u16 size;
+	u32 value;
+} __attribute__((__packed__));
+
+/* Values for bcm430x_sprominfo.locale */
+enum {
+	BCM43xx_LOCALE_WORLD = 0,
+	BCM43xx_LOCALE_THAILAND,
+	BCM43xx_LOCALE_ISRAEL,
+	BCM43xx_LOCALE_JORDAN,
+	BCM43xx_LOCALE_CHINA,
+	BCM43xx_LOCALE_JAPAN,
+	BCM43xx_LOCALE_USA_CANADA_ANZ,
+	BCM43xx_LOCALE_EUROPE,
+	BCM43xx_LOCALE_USA_LOW,
+	BCM43xx_LOCALE_JAPAN_HIGH,
+	BCM43xx_LOCALE_ALL,
+	BCM43xx_LOCALE_NONE,
+};
+
+#define BCM43xx_SPROM_SIZE	64 /* in 16-bit words. */
+struct bcm43xx_sprominfo {
+	u16 boardflags2;
+	u8 il0macaddr[6];
+	u8 et0macaddr[6];
+	u8 et1macaddr[6];
+	u8 et0phyaddr:5;
+	u8 et1phyaddr:5;
+	u8 et0mdcport:1;
+	u8 et1mdcport:1;
+	u8 boardrev;
+	u8 locale:4;
+	u8 antennas_aphy:2;
+	u8 antennas_bgphy:2;
+	u16 pa0b0;
+	u16 pa0b1;
+	u16 pa0b2;
+	u8 wl0gpio0;
+	u8 wl0gpio1;
+	u8 wl0gpio2;
+	u8 wl0gpio3;
+	u8 maxpower_aphy;
+	u8 maxpower_bgphy;
+	u16 pa1b0;
+	u16 pa1b1;
+	u16 pa1b2;
+	u8 idle_tssi_tgt_aphy;
+	u8 idle_tssi_tgt_bgphy;
+	u16 boardflags;
+	u16 antennagain_aphy;
+	u16 antennagain_bgphy;
+};
+
+/* Value pair to measure the LocalOscillator. */
+struct bcm43xx_lopair {
+	s8 low;
+	s8 high;
+	u8 used:1;
+};
+#define BCM43xx_LO_COUNT	(14*4)
+
+struct bcm43xx_phyinfo {
+	/* Hardware Data */
+	u8 version;
+	u8 type;
+	u8 rev;
+	u16 antenna_diversity;
+	u16 savedpctlreg;
+	u16 minlowsig[2];
+	u16 minlowsigpos[2];
+	u8 connected:1,
+	   calibrated:1,
+	   is_locked:1, /* used in bcm43xx_phy_{un}lock() */
+	   dyn_tssi_tbl:1; /* used in bcm43xx_phy_init_tssi2dbm_table() */
+	/* LO Measurement Data.
+	 * Use bcm43xx_get_lopair() to get a value.
+	 */
+	struct bcm43xx_lopair *_lo_pairs;
+
+	/* TSSI to dBm table in use */
+	const s8 *tssi2dbm;
+	/* idle TSSI value */
+	s8 idle_tssi;
+
+	/* Values from bcm43xx_calc_loopback_gain() */
+	u16 loopback_gain[2];
+
+	/* PHY lock for core.rev < 3
+	 * This lock is only used by bcm43xx_phy_{un}lock()
+	 */
+	spinlock_t lock;
+};
+
+
+struct bcm43xx_radioinfo {
+	u16 manufact;
+	u16 version;
+	u8 revision;
+
+	/* Desired TX power in dBm Q5.2 */
+	u16 txpower_desired;
+	/* TX Power control values. */
+	union {
+		/* B/G PHY */
+		struct {
+			u16 baseband_atten;
+			u16 radio_atten;
+			u16 txctl1;
+			u16 txctl2;
+		};
+		/* A PHY */
+		struct {
+			u16 txpwr_offset;
+		};
+	};
+
+	/* Current Interference Mitigation mode */
+	int interfmode;
+	/* Stack of saved values from the Interference Mitigation code.
+	 * Each value in the stack is layed out as follows:
+	 * bit 0-11:  offset
+	 * bit 12-15: register ID
+	 * bit 16-32: value
+	 * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
+	 */
+#define BCM43xx_INTERFSTACK_SIZE	26
+	u32 interfstack[BCM43xx_INTERFSTACK_SIZE];
+
+	/* Saved values from the NRSSI Slope calculation */
+	s16 nrssi[2];
+	s32 nrssislope;
+	/* In memory nrssi lookup table. */
+	s8 nrssi_lt[64];
+
+	/* current channel */
+	u8 channel;
+	u8 initial_channel;
+
+	u16 lofcal;
+
+	u16 initval;
+
+	u8 enabled:1;
+	/* ACI (adjacent channel interference) flags. */
+	u8 aci_enable:1,
+	   aci_wlan_automatic:1,
+	   aci_hw_rssi:1;
+};
+
+/* Data structures for DMA transmission, per 80211 core. */
+struct bcm43xx_dma {
+	struct bcm43xx_dmaring *tx_ring0;
+	struct bcm43xx_dmaring *tx_ring1;
+	struct bcm43xx_dmaring *tx_ring2;
+	struct bcm43xx_dmaring *tx_ring3;
+	struct bcm43xx_dmaring *rx_ring0;
+	struct bcm43xx_dmaring *rx_ring1; /* only available on core.rev < 5 */
+};
+
+/* Data structures for PIO transmission, per 80211 core. */
+struct bcm43xx_pio {
+	struct bcm43xx_pioqueue *queue0;
+	struct bcm43xx_pioqueue *queue1;
+	struct bcm43xx_pioqueue *queue2;
+	struct bcm43xx_pioqueue *queue3;
+};
+
+#define BCM43xx_MAX_80211_CORES		2
+
+#ifdef CONFIG_BCM947XX
+#define core_offset(bcm) (bcm)->current_core_offset
+#else
+#define core_offset(bcm) 0
+#endif
+
+/* Generic information about a core. */
+struct bcm43xx_coreinfo {
+	u8 available:1,
+	   enabled:1,
+	   initialized:1;
+	/** core_id ID number */
+	u16 id;
+	/** core_rev revision number */
+	u8 rev;
+	/** Index number for _switch_core() */
+	u8 index;
+};
+
+/* Additional information for each 80211 core. */
+struct bcm43xx_coreinfo_80211 {
+	/* PHY device. */
+	struct bcm43xx_phyinfo phy;
+	/* Radio device. */
+	struct bcm43xx_radioinfo radio;
+	union {
+		/* DMA context. */
+		struct bcm43xx_dma dma;
+		/* PIO context. */
+		struct bcm43xx_pio pio;
+	};
+};
+
+/* Context information for a noise calculation (Link Quality). */
+struct bcm43xx_noise_calculation {
+	struct bcm43xx_coreinfo *core_at_start;
+	u8 channel_at_start;
+	u8 calculation_running:1;
+	u8 nr_samples;
+	s8 samples[8][4];
+};
+
+struct bcm43xx_stats {
+	u8 link_quality;
+	u8 noise;
+	struct iw_statistics wstats;
+	/* Store the last TX/RX times here for updating the leds. */
+	unsigned long last_tx;
+	unsigned long last_rx;
+};
+
+struct bcm43xx_key {
+	u8 enabled:1;
+	u8 algorithm;
+};
+
+struct bcm43xx_private {
+	struct bcm43xx_sysfs sysfs;
+
+	struct ieee80211_device *ieee;
+	struct ieee80211softmac_device *softmac;
+
+	struct net_device *net_dev;
+	struct pci_dev *pci_dev;
+	unsigned int irq;
+
+	void __iomem *mmio_addr;
+	unsigned int mmio_len;
+
+	/* Do not use the lock directly. Use the bcm43xx_lock* helper
+	 * functions, to be MMIO-safe. */
+	spinlock_t _lock;
+
+	/* Driver status flags. */
+	u32 initialized:1,		/* init_board() succeed */
+	    was_initialized:1,		/* for PCI suspend/resume. */
+	    shutting_down:1,		/* free_board() in progress */
+	    __using_pio:1,		/* Internal, use bcm43xx_using_pio(). */
+	    bad_frames_preempt:1,	/* Use "Bad Frames Preemption" (default off) */
+	    reg124_set_0x4:1,		/* Some variable to keep track of IRQ stuff. */
+	    powersaving:1,		/* TRUE if we are in PowerSaving mode. FALSE otherwise. */
+	    short_preamble:1,		/* TRUE, if short preamble is enabled. */
+	    firmware_norelease:1;	/* Do not release the firmware. Used on suspend. */
+
+	struct bcm43xx_stats stats;
+
+	/* Bus type we are connected to.
+	 * This is currently always BCM43xx_BUSTYPE_PCI
+	 */
+	u8 bustype;
+
+	u16 board_vendor;
+	u16 board_type;
+	u16 board_revision;
+
+	u16 chip_id;
+	u8 chip_rev;
+	u8 chip_package;
+
+	struct bcm43xx_sprominfo sprom;
+#define BCM43xx_NR_LEDS		4
+	struct bcm43xx_led leds[BCM43xx_NR_LEDS];
+
+	/* The currently active core. */
+	struct bcm43xx_coreinfo *current_core;
+#ifdef CONFIG_BCM947XX
+	/** current core memory offset */
+	u32 current_core_offset;
+#endif
+	struct bcm43xx_coreinfo *active_80211_core;
+	/* coreinfo structs for all possible cores follow.
+	 * Note that a core might not exist.
+	 * So check the coreinfo flags before using it.
+	 */
+	struct bcm43xx_coreinfo core_chipcommon;
+	struct bcm43xx_coreinfo core_pci;
+	struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ];
+	/* Additional information, specific to the 80211 cores. */
+	struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ];
+	/* Index of the current 80211 core. If current_core is not
+	 * an 80211 core, this is -1.
+	 */
+	int current_80211_core_idx;
+	/* Number of available 80211 cores. */
+	int nr_80211_available;
+
+	u32 chipcommon_capabilities;
+
+	/* Reason code of the last interrupt. */
+	u32 irq_reason;
+	u32 dma_reason[4];
+	/* saved irq enable/disable state bitfield. */
+	u32 irq_savedstate;
+	/* Link Quality calculation context. */
+	struct bcm43xx_noise_calculation noisecalc;
+
+	/* Threshold values. */
+	//TODO: The RTS thr has to be _used_. Currently, it is only set via WX.
+	u32 rts_threshold;
+
+	/* Interrupt Service Routine tasklet (bottom-half) */
+	struct tasklet_struct isr_tasklet;
+
+	/* Periodic tasks */
+	struct timer_list periodic_tasks;
+	unsigned int periodic_state;
+
+	struct work_struct restart_work;
+
+	/* Informational stuff. */
+	char nick[IW_ESSID_MAX_SIZE + 1];
+
+	/* encryption/decryption */
+	u16 security_offset;
+	struct bcm43xx_key key[54];
+	u8 default_key_idx;
+
+	/* Firmware. */
+	const struct firmware *ucode;
+	const struct firmware *pcm;
+	const struct firmware *initvals0;
+	const struct firmware *initvals1;
+
+	/* Debugging stuff follows. */
+#ifdef CONFIG_BCM43XX_DEBUG
+	struct bcm43xx_dfsentry *dfsentry;
+#endif
+};
+
+/* bcm43xx_(un)lock() protect struct bcm43xx_private.
+ * Note that _NO_ MMIO writes are allowed. If you want to
+ * write to the device through MMIO in the critical section, use
+ * the *_mmio lock functions.
+ * MMIO read-access is allowed, though.
+ */
+#define bcm43xx_lock(bcm, flags)	spin_lock_irqsave(&(bcm)->_lock, flags)
+#define bcm43xx_unlock(bcm, flags)	spin_unlock_irqrestore(&(bcm)->_lock, flags)
+/* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO.
+ * MMIO write-access to the device is allowed.
+ * All MMIO writes are flushed on unlock, so it is guaranteed to not
+ * interfere with other threads writing MMIO registers.
+ */
+#define bcm43xx_lock_mmio(bcm, flags)	bcm43xx_lock(bcm, flags)
+#define bcm43xx_unlock_mmio(bcm, flags)	do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0)
+
+static inline
+struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
+{
+	return ieee80211softmac_priv(dev);
+}
+
+
+/* Helper function, which returns a boolean.
+ * TRUE, if PIO is used; FALSE, if DMA is used.
+ */
+#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
+static inline
+int bcm43xx_using_pio(struct bcm43xx_private *bcm)
+{
+	return bcm->__using_pio;
+}
+#elif defined(CONFIG_BCM43XX_DMA)
+static inline
+int bcm43xx_using_pio(struct bcm43xx_private *bcm)
+{
+	return 0;
+}
+#elif defined(CONFIG_BCM43XX_PIO)
+static inline
+int bcm43xx_using_pio(struct bcm43xx_private *bcm)
+{
+	return 1;
+}
+#else
+# error "Using neither DMA nor PIO? Confused..."
+#endif
+
+/* Helper functions to access data structures private to the 80211 cores.
+ * Note that we _must_ have an 80211 core mapped when calling
+ * any of these functions.
+ */
+static inline
+struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm)
+{
+	assert(bcm43xx_using_pio(bcm));
+	assert(bcm->current_80211_core_idx >= 0);
+	assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
+	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio);
+}
+static inline
+struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm)
+{
+	assert(!bcm43xx_using_pio(bcm));
+	assert(bcm->current_80211_core_idx >= 0);
+	assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
+	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma);
+}
+static inline
+struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm)
+{
+	assert(bcm->current_80211_core_idx >= 0);
+	assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
+	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy);
+}
+static inline
+struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
+{
+	assert(bcm->current_80211_core_idx >= 0);
+	assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
+	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
+}
+
+/* Are we running in init_board() context? */
+static inline
+int bcm43xx_is_initializing(struct bcm43xx_private *bcm)
+{
+	if (bcm->initialized)
+		return 0;
+	if (bcm->shutting_down)
+		return 0;
+	return 1;
+}
+
+static inline
+struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy,
+					   u16 radio_attenuation,
+					   u16 baseband_attenuation)
+{
+	return phy->_lo_pairs + (radio_attenuation + 14 * (baseband_attenuation / 2));
+}
+
+
+static inline
+u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset)
+{
+	return ioread16(bcm->mmio_addr + core_offset(bcm) + offset);
+}
+
+static inline
+void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value)
+{
+	iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset);
+}
+
+static inline
+u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset)
+{
+	return ioread32(bcm->mmio_addr + core_offset(bcm) + offset);
+}
+
+static inline
+void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value)
+{
+	iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset);
+}
+
+static inline
+int bcm43xx_pci_read_config16(struct bcm43xx_private *bcm, int offset, u16 *value)
+{
+	return pci_read_config_word(bcm->pci_dev, offset, value);
+}
+
+static inline
+int bcm43xx_pci_read_config32(struct bcm43xx_private *bcm, int offset, u32 *value)
+{
+	return pci_read_config_dword(bcm->pci_dev, offset, value);
+}
+
+static inline
+int bcm43xx_pci_write_config16(struct bcm43xx_private *bcm, int offset, u16 value)
+{
+	return pci_write_config_word(bcm->pci_dev, offset, value);
+}
+
+static inline
+int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 value)
+{
+	return pci_write_config_dword(bcm->pci_dev, offset, value);
+}
+
+/** Limit a value between two limits */
+#ifdef limit_value
+# undef limit_value
+#endif
+#define limit_value(value, min, max)  \
+	({						\
+		typeof(value) __value = (value);	\
+	 	typeof(value) __min = (min);		\
+	 	typeof(value) __max = (max);		\
+	 	if (__value < __min)			\
+	 		__value = __min;		\
+	 	else if (__value > __max)		\
+	 		__value = __max;		\
+	 	__value;				\
+	})
+
+/** Helpers to print MAC addresses. */
+#define BCM43xx_MACFMT		"%02x:%02x:%02x:%02x:%02x:%02x"
+#define BCM43xx_MACARG(x)	((u8*)(x))[0], ((u8*)(x))[1], \
+				((u8*)(x))[2], ((u8*)(x))[3], \
+				((u8*)(x))[4], ((u8*)(x))[5]
+
+#endif /* BCM43xx_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
new file mode 100644
index 0000000..d2c3401
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -0,0 +1,499 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  debugfs driver debugging code
+
+  Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+
+
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include "bcm43xx.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_debugfs.h"
+#include "bcm43xx_dma.h"
+#include "bcm43xx_pio.h"
+#include "bcm43xx_xmit.h"
+
+#define REALLY_BIG_BUFFER_SIZE	(1024*256)
+
+static struct bcm43xx_debugfs fs;
+static char really_big_buffer[REALLY_BIG_BUFFER_SIZE];
+static DECLARE_MUTEX(big_buffer_sem);
+
+
+static ssize_t write_file_dummy(struct file *file, const char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	return count;
+}
+
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->u.generic_ip;
+	return 0;
+}
+
+#define fappend(fmt, x...)	pos += snprintf(buf + pos, len - pos, fmt , ##x)
+
+static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	const size_t len = REALLY_BIG_BUFFER_SIZE;
+
+	struct bcm43xx_private *bcm = file->private_data;
+	char *buf = really_big_buffer;
+	size_t pos = 0;
+	ssize_t res;
+	struct net_device *net_dev;
+	struct pci_dev *pci_dev;
+	unsigned long flags;
+	u16 tmp16;
+	int i;
+
+	down(&big_buffer_sem);
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if (!bcm->initialized) {
+		fappend("Board not initialized.\n");
+		goto out;
+	}
+	net_dev = bcm->net_dev;
+	pci_dev = bcm->pci_dev;
+
+	/* This is where the information is written to the "devinfo" file */
+	fappend("*** %s devinfo ***\n", net_dev->name);
+	fappend("vendor:           0x%04x   device:           0x%04x\n",
+		pci_dev->vendor, pci_dev->device);
+	fappend("subsystem_vendor: 0x%04x   subsystem_device: 0x%04x\n",
+		pci_dev->subsystem_vendor, pci_dev->subsystem_device);
+	fappend("IRQ: %d\n", bcm->irq);
+	fappend("mmio_addr: 0x%p   mmio_len: %u\n", bcm->mmio_addr, bcm->mmio_len);
+	fappend("chip_id: 0x%04x   chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev);
+	if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16)))
+		fappend("Radio disabled by hardware!\n");
+	if ((bcm->core_80211[0].rev < 3) && !(bcm43xx_read16(bcm, 0x049A) & (1 << 4)))
+		fappend("Radio disabled by hardware!\n");
+	fappend("board_vendor: 0x%04x   board_type: 0x%04x\n", bcm->board_vendor,
+	        bcm->board_type);
+
+	fappend("\nCores:\n");
+#define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, "	\
+					 "rev: 0x%02x, index: 0x%02x\n",		\
+					 (info).available				\
+						? "available" : "nonavailable",		\
+					 (info).enabled					\
+						? "enabled" : "disabled",		\
+					 (info).id, (info).rev, (info).index)
+	fappend_core("CHIPCOMMON", bcm->core_chipcommon);
+	fappend_core("PCI", bcm->core_pci);
+	fappend_core("first 80211", bcm->core_80211[0]);
+	fappend_core("second 80211", bcm->core_80211[1]);
+#undef fappend_core
+	tmp16 = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
+	fappend("LEDs: ");
+	for (i = 0; i < BCM43xx_NR_LEDS; i++)
+		fappend("%d ", !!(tmp16 & (1 << i)));
+	fappend("\n");
+
+out:
+	bcm43xx_unlock_mmio(bcm, flags);
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	up(&big_buffer_sem);
+	return res;
+}
+
+static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	const size_t len = REALLY_BIG_BUFFER_SIZE;
+
+	char *buf = really_big_buffer;
+	size_t pos = 0;
+	ssize_t res;
+
+	down(&big_buffer_sem);
+
+	/* This is where the information is written to the "driver" file */
+	fappend(KBUILD_MODNAME " driver\n");
+	fappend("Compiled at: %s %s\n", __DATE__, __TIME__);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	up(&big_buffer_sem);
+	return res;
+}
+
+static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	const size_t len = REALLY_BIG_BUFFER_SIZE;
+
+	struct bcm43xx_private *bcm = file->private_data;
+	char *buf = really_big_buffer;
+	size_t pos = 0;
+	ssize_t res;
+	unsigned long flags;
+
+	down(&big_buffer_sem);
+	bcm43xx_lock_mmio(bcm, flags);
+	if (!bcm->initialized) {
+		fappend("Board not initialized.\n");
+		goto out;
+	}
+
+	/* This is where the information is written to the "sprom_dump" file */
+	fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
+
+out:
+	bcm43xx_unlock_mmio(bcm, flags);
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	up(&big_buffer_sem);
+	return res;
+}
+
+static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
+			     size_t count, loff_t *ppos)
+{
+	const size_t len = REALLY_BIG_BUFFER_SIZE;
+
+	struct bcm43xx_private *bcm = file->private_data;
+	char *buf = really_big_buffer;
+	size_t pos = 0;
+	ssize_t res;
+	unsigned long flags;
+	u64 tsf;
+
+	down(&big_buffer_sem);
+	bcm43xx_lock_mmio(bcm, flags);
+	if (!bcm->initialized) {
+		fappend("Board not initialized.\n");
+		goto out;
+	}
+	bcm43xx_tsf_read(bcm, &tsf);
+	fappend("0x%08x%08x\n",
+		(unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
+		(unsigned int)(tsf & 0xFFFFFFFFULL));
+
+out:
+	bcm43xx_unlock_mmio(bcm, flags);
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	up(&big_buffer_sem);
+	return res;
+}
+
+static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
+			      size_t count, loff_t *ppos)
+{
+	struct bcm43xx_private *bcm = file->private_data;
+	char *buf = really_big_buffer;
+	ssize_t buf_size;
+	ssize_t res;
+	unsigned long flags;
+	u64 tsf;
+
+	buf_size = min(count, sizeof (really_big_buffer) - 1);
+	down(&big_buffer_sem);
+	if (copy_from_user(buf, user_buf, buf_size)) {
+	        res = -EFAULT;
+		goto out_up;
+	}
+	bcm43xx_lock_mmio(bcm, flags);
+	if (!bcm->initialized) {
+		printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	if (sscanf(buf, "%lli", &tsf) != 1) {
+		printk(KERN_INFO PFX "debugfs: invalid values for \"tsf\"\n");
+		res = -EINVAL;
+		goto out_unlock;
+	}
+	bcm43xx_tsf_write(bcm, tsf);
+	res = buf_size;
+	
+out_unlock:
+	bcm43xx_unlock_mmio(bcm, flags);
+out_up:
+	up(&big_buffer_sem);
+	return res;
+}
+
+static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
+				size_t count, loff_t *ppos)
+{
+	const size_t len = REALLY_BIG_BUFFER_SIZE;
+
+	struct bcm43xx_private *bcm = file->private_data;
+	char *buf = really_big_buffer;
+	size_t pos = 0;
+	ssize_t res;
+	unsigned long flags;
+	struct bcm43xx_dfsentry *e;
+	struct bcm43xx_xmitstatus *status;
+	int i, cnt, j = 0;
+
+	down(&big_buffer_sem);
+	bcm43xx_lock(bcm, flags);
+
+	fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
+		BCM43xx_NR_LOGGED_XMITSTATUS);
+	e = bcm->dfsentry;
+	if (e->xmitstatus_printing == 0) {
+		/* At the beginning, make a copy of all data to avoid
+		 * concurrency, as this function is called multiple
+		 * times for big logs. Without copying, the data might
+		 * change between reads. This would result in total trash.
+		 */
+		e->xmitstatus_printing = 1;
+		e->saved_xmitstatus_ptr = e->xmitstatus_ptr;
+		e->saved_xmitstatus_cnt = e->xmitstatus_cnt;
+		memcpy(e->xmitstatus_print_buffer, e->xmitstatus_buffer,
+		       BCM43xx_NR_LOGGED_XMITSTATUS * sizeof(*(e->xmitstatus_buffer)));
+	}
+	i = e->saved_xmitstatus_ptr - 1;
+	if (i < 0)
+		i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
+	cnt = e->saved_xmitstatus_cnt;
+	while (cnt) {
+		status = e->xmitstatus_print_buffer + i;
+		fappend("0x%02x:   cookie: 0x%04x,  flags: 0x%02x,  "
+			"cnt1: 0x%02x,  cnt2: 0x%02x,  seq: 0x%04x,  "
+			"unk: 0x%04x\n", j,
+			status->cookie, status->flags,
+			status->cnt1, status->cnt2, status->seq,
+			status->unknown);
+		j++;
+		cnt--;
+		i--;
+		if (i < 0)
+			i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
+	}
+
+	bcm43xx_unlock(bcm, flags);
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	bcm43xx_lock(bcm, flags);
+	if (*ppos == pos) {
+		/* Done. Drop the copied data. */
+		e->xmitstatus_printing = 0;
+	}
+	bcm43xx_unlock(bcm, flags);
+	up(&big_buffer_sem);
+	return res;
+}
+
+#undef fappend
+
+
+static struct file_operations devinfo_fops = {
+	.read = devinfo_read_file,
+	.write = write_file_dummy,
+	.open = open_file_generic,
+};
+
+static struct file_operations spromdump_fops = {
+	.read = spromdump_read_file,
+	.write = write_file_dummy,
+	.open = open_file_generic,
+};
+
+static struct file_operations drvinfo_fops = {
+	.read = drvinfo_read_file,
+	.write = write_file_dummy,
+	.open = open_file_generic,
+};
+
+static struct file_operations tsf_fops = {
+	.read = tsf_read_file,
+	.write = tsf_write_file,
+	.open = open_file_generic,
+};
+
+static struct file_operations txstat_fops = {
+	.read = txstat_read_file,
+	.write = write_file_dummy,
+	.open = open_file_generic,
+};
+
+
+void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_dfsentry *e;
+	char devdir[IFNAMSIZ];
+
+	assert(bcm);
+	e = kzalloc(sizeof(*e), GFP_KERNEL);
+	if (!e) {
+		printk(KERN_ERR PFX "out of memory\n");
+		return;
+	}
+	e->bcm = bcm;
+	e->xmitstatus_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS
+				       * sizeof(*(e->xmitstatus_buffer)),
+				       GFP_KERNEL);
+	if (!e->xmitstatus_buffer) {
+		printk(KERN_ERR PFX "out of memory\n");
+		kfree(e);
+		return;
+	}
+	e->xmitstatus_print_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS
+					     * sizeof(*(e->xmitstatus_buffer)),
+					     GFP_KERNEL);
+	if (!e->xmitstatus_print_buffer) {
+		printk(KERN_ERR PFX "out of memory\n");
+		kfree(e);
+		return;
+	}
+
+
+	bcm->dfsentry = e;
+
+	strncpy(devdir, bcm->net_dev->name, ARRAY_SIZE(devdir));
+	e->subdir = debugfs_create_dir(devdir, fs.root);
+	e->dentry_devinfo = debugfs_create_file("devinfo", 0444, e->subdir,
+						bcm, &devinfo_fops);
+	if (!e->dentry_devinfo)
+		printk(KERN_ERR PFX "debugfs: creating \"devinfo\" for \"%s\" failed!\n", devdir);
+	e->dentry_spromdump = debugfs_create_file("sprom_dump", 0444, e->subdir,
+						  bcm, &spromdump_fops);
+	if (!e->dentry_spromdump)
+		printk(KERN_ERR PFX "debugfs: creating \"sprom_dump\" for \"%s\" failed!\n", devdir);
+	e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir,
+	                                    bcm, &tsf_fops);
+	if (!e->dentry_tsf)
+		printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir);
+	e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir,
+						bcm, &txstat_fops);
+	if (!e->dentry_txstat)
+		printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
+}
+
+void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_dfsentry *e;
+
+	if (!bcm)
+		return;
+
+	e = bcm->dfsentry;
+	assert(e);
+	debugfs_remove(e->dentry_spromdump);
+	debugfs_remove(e->dentry_devinfo);
+	debugfs_remove(e->dentry_tsf);
+	debugfs_remove(e->dentry_txstat);
+	debugfs_remove(e->subdir);
+	kfree(e->xmitstatus_buffer);
+	kfree(e->xmitstatus_print_buffer);
+	kfree(e);
+}
+
+void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
+				struct bcm43xx_xmitstatus *status)
+{
+	struct bcm43xx_dfsentry *e;
+	struct bcm43xx_xmitstatus *savedstatus;
+
+	/* This is protected by bcm->_lock */
+	e = bcm->dfsentry;
+	assert(e);
+	savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr;
+	memcpy(savedstatus, status, sizeof(*status));
+	e->xmitstatus_ptr++;
+	if (e->xmitstatus_ptr >= BCM43xx_NR_LOGGED_XMITSTATUS)
+		e->xmitstatus_ptr = 0;
+	if (e->xmitstatus_cnt < BCM43xx_NR_LOGGED_XMITSTATUS)
+		e->xmitstatus_cnt++;
+}
+
+void bcm43xx_debugfs_init(void)
+{
+	memset(&fs, 0, sizeof(fs));
+	fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+	if (!fs.root)
+		printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n");
+	fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops);
+	if (!fs.dentry_driverinfo)
+		printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n");
+}
+
+void bcm43xx_debugfs_exit(void)
+{
+	debugfs_remove(fs.dentry_driverinfo);
+	debugfs_remove(fs.root);
+}
+
+void bcm43xx_printk_dump(const char *data,
+			 size_t size,
+			 const char *description)
+{
+	size_t i;
+	char c;
+
+	printk(KERN_INFO PFX "Data dump (%s, %u bytes):",
+	       description, size);
+	for (i = 0; i < size; i++) {
+		c = data[i];
+		if (i % 8 == 0)
+			printk("\n" KERN_INFO PFX "0x%08x:  0x%02x, ", i, c & 0xff);
+		else
+			printk("0x%02x, ", c & 0xff);
+	}
+	printk("\n");
+}
+
+void bcm43xx_printk_bitdump(const unsigned char *data,
+			    size_t bytes, int msb_to_lsb,
+			    const char *description)
+{
+	size_t i;
+	int j;
+	const unsigned char *d;
+
+	printk(KERN_INFO PFX "*** Bitdump (%s, %u bytes, %s) ***",
+	       description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB");
+	for (i = 0; i < bytes; i++) {
+		d = data + i;
+		if (i % 8 == 0)
+			printk("\n" KERN_INFO PFX "0x%08x:  ", i);
+		if (msb_to_lsb) {
+			for (j = 7; j >= 0; j--) {
+				if (*d & (1 << j))
+					printk("1");
+				else
+					printk("0");
+			}
+		} else {
+			for (j = 0; j < 8; j++) {
+				if (*d & (1 << j))
+					printk("1");
+				else
+					printk("0");
+			}
+		}
+		printk(" ");
+	}
+	printk("\n");
+}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
new file mode 100644
index 0000000..50ce267
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
@@ -0,0 +1,117 @@
+#ifndef BCM43xx_DEBUGFS_H_
+#define BCM43xx_DEBUGFS_H_
+
+struct bcm43xx_private;
+struct bcm43xx_xmitstatus;
+
+#ifdef CONFIG_BCM43XX_DEBUG
+
+#include <linux/list.h>
+#include <asm/semaphore.h>
+
+struct dentry;
+
+/* limited by the size of the "really_big_buffer" */
+#define BCM43xx_NR_LOGGED_XMITSTATUS	100
+
+struct bcm43xx_dfsentry {
+	struct dentry *subdir;
+	struct dentry *dentry_devinfo;
+	struct dentry *dentry_spromdump;
+	struct dentry *dentry_tsf;
+	struct dentry *dentry_txstat;
+
+	struct bcm43xx_private *bcm;
+
+	/* saved xmitstatus. */
+	struct bcm43xx_xmitstatus *xmitstatus_buffer;
+	int xmitstatus_ptr;
+	int xmitstatus_cnt;
+	/* We need a seperate buffer while printing to avoid
+	 * concurrency issues. (New xmitstatus can arrive
+	 * while we are printing).
+	 */
+	struct bcm43xx_xmitstatus *xmitstatus_print_buffer;
+	int saved_xmitstatus_ptr;
+	int saved_xmitstatus_cnt;
+	int xmitstatus_printing;
+};
+
+struct bcm43xx_debugfs {
+	struct dentry *root;
+	struct dentry *dentry_driverinfo;
+};
+
+void bcm43xx_debugfs_init(void);
+void bcm43xx_debugfs_exit(void);
+void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm);
+void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm);
+void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
+				struct bcm43xx_xmitstatus *status);
+
+/* Debug helper: Dump binary data through printk. */
+void bcm43xx_printk_dump(const char *data,
+			 size_t size,
+			 const char *description);
+/* Debug helper: Dump bitwise binary data through printk. */
+void bcm43xx_printk_bitdump(const unsigned char *data,
+			    size_t bytes, int msb_to_lsb,
+			    const char *description);
+#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) \
+	do {									\
+		bcm43xx_printk_bitdump((const unsigned char *)(pointer),	\
+				       sizeof(*(pointer)),			\
+				       (msb_to_lsb),				\
+				       (description));				\
+	} while (0)
+
+#else /* CONFIG_BCM43XX_DEBUG*/
+
+static inline
+void bcm43xx_debugfs_init(void) { }
+static inline
+void bcm43xx_debugfs_exit(void) { }
+static inline
+void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) { }
+static inline
+void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) { }
+static inline
+void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
+				struct bcm43xx_xmitstatus *status) { }
+
+static inline
+void bcm43xx_printk_dump(const char *data,
+			 size_t size,
+			 const char *description)
+{
+}
+static inline
+void bcm43xx_printk_bitdump(const unsigned char *data,
+			    size_t bytes, int msb_to_lsb,
+			    const char *description)
+{
+}
+#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description)  do { /* nothing */ } while (0)
+
+#endif /* CONFIG_BCM43XX_DEBUG*/
+
+/* Ugly helper macros to make incomplete code more verbose on runtime */
+#ifdef TODO
+# undef TODO
+#endif
+#define TODO()  \
+	do {										\
+		printk(KERN_INFO PFX "TODO: Incomplete code in %s() at %s:%d\n",	\
+		       __FUNCTION__, __FILE__, __LINE__);				\
+	} while (0)
+
+#ifdef FIXME
+# undef FIXME
+#endif
+#define FIXME()  \
+	do {										\
+		printk(KERN_INFO PFX "FIXME: Possibly broken code in %s() at %s:%d\n",	\
+		       __FUNCTION__, __FILE__, __LINE__);				\
+	} while (0)
+
+#endif /* BCM43xx_DEBUGFS_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
new file mode 100644
index 0000000..c3681b8
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -0,0 +1,968 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  DMA ringbuffer and descriptor allocation/management
+
+  Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
+
+  Some code in this file is derived from the b44.c driver
+  Copyright (C) 2002 David S. Miller
+  Copyright (C) Pekka Pietikainen
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx.h"
+#include "bcm43xx_dma.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_debugfs.h"
+#include "bcm43xx_power.h"
+#include "bcm43xx_xmit.h"
+
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+
+
+static inline int free_slots(struct bcm43xx_dmaring *ring)
+{
+	return (ring->nr_slots - ring->used_slots);
+}
+
+static inline int next_slot(struct bcm43xx_dmaring *ring, int slot)
+{
+	assert(slot >= -1 && slot <= ring->nr_slots - 1);
+	if (slot == ring->nr_slots - 1)
+		return 0;
+	return slot + 1;
+}
+
+static inline int prev_slot(struct bcm43xx_dmaring *ring, int slot)
+{
+	assert(slot >= 0 && slot <= ring->nr_slots - 1);
+	if (slot == 0)
+		return ring->nr_slots - 1;
+	return slot - 1;
+}
+
+/* Request a slot for usage. */
+static inline
+int request_slot(struct bcm43xx_dmaring *ring)
+{
+	int slot;
+
+	assert(ring->tx);
+	assert(!ring->suspended);
+	assert(free_slots(ring) != 0);
+
+	slot = next_slot(ring, ring->current_slot);
+	ring->current_slot = slot;
+	ring->used_slots++;
+
+	/* Check the number of available slots and suspend TX,
+	 * if we are running low on free slots.
+	 */
+	if (unlikely(free_slots(ring) < ring->suspend_mark)) {
+		netif_stop_queue(ring->bcm->net_dev);
+		ring->suspended = 1;
+	}
+#ifdef CONFIG_BCM43XX_DEBUG
+	if (ring->used_slots > ring->max_used_slots)
+		ring->max_used_slots = ring->used_slots;
+#endif /* CONFIG_BCM43XX_DEBUG*/
+
+	return slot;
+}
+
+/* Return a slot to the free slots. */
+static inline
+void return_slot(struct bcm43xx_dmaring *ring, int slot)
+{
+	assert(ring->tx);
+
+	ring->used_slots--;
+
+	/* Check if TX is suspended and check if we have
+	 * enough free slots to resume it again.
+	 */
+	if (unlikely(ring->suspended)) {
+		if (free_slots(ring) >= ring->resume_mark) {
+			ring->suspended = 0;
+			netif_wake_queue(ring->bcm->net_dev);
+		}
+	}
+}
+
+static inline
+dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
+			  unsigned char *buf,
+			  size_t len,
+			  int tx)
+{
+	dma_addr_t dmaaddr;
+
+	if (tx) {
+		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+					 buf, len,
+					 DMA_TO_DEVICE);
+	} else {
+		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+					 buf, len,
+					 DMA_FROM_DEVICE);
+	}
+
+	return dmaaddr;
+}
+
+static inline
+void unmap_descbuffer(struct bcm43xx_dmaring *ring,
+		      dma_addr_t addr,
+		      size_t len,
+		      int tx)
+{
+	if (tx) {
+		dma_unmap_single(&ring->bcm->pci_dev->dev,
+				 addr, len,
+				 DMA_TO_DEVICE);
+	} else {
+		dma_unmap_single(&ring->bcm->pci_dev->dev,
+				 addr, len,
+				 DMA_FROM_DEVICE);
+	}
+}
+
+static inline
+void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring,
+			     dma_addr_t addr,
+			     size_t len)
+{
+	assert(!ring->tx);
+
+	dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev,
+				addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
+				dma_addr_t addr,
+				size_t len)
+{
+	assert(!ring->tx);
+
+	dma_sync_single_for_device(&ring->bcm->pci_dev->dev,
+				   addr, len, DMA_FROM_DEVICE);
+}
+
+/* Unmap and free a descriptor buffer. */
+static inline
+void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
+			    struct bcm43xx_dmadesc *desc,
+			    struct bcm43xx_dmadesc_meta *meta,
+			    int irq_context)
+{
+	assert(meta->skb);
+	if (irq_context)
+		dev_kfree_skb_irq(meta->skb);
+	else
+		dev_kfree_skb(meta->skb);
+	meta->skb = NULL;
+}
+
+static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
+{
+	struct device *dev = &(ring->bcm->pci_dev->dev);
+
+	ring->vbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+					 &(ring->dmabase), GFP_KERNEL);
+	if (!ring->vbase) {
+		printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
+		return -ENOMEM;
+	}
+	if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) {
+		printk(KERN_ERR PFX ">>>FATAL ERROR<<<  DMA RINGMEMORY >1G "
+				    "(0x%08x, len: %lu)\n",
+		       ring->dmabase, BCM43xx_DMA_RINGMEMSIZE);
+		dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+				  ring->vbase, ring->dmabase);
+		return -ENOMEM;
+	}
+	assert(!(ring->dmabase & 0x000003FF));
+	memset(ring->vbase, 0, BCM43xx_DMA_RINGMEMSIZE);
+
+	return 0;
+}
+
+static void free_ringmemory(struct bcm43xx_dmaring *ring)
+{
+	struct device *dev = &(ring->bcm->pci_dev->dev);
+
+	dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+			  ring->vbase, ring->dmabase);
+}
+
+/* Reset the RX DMA channel */
+int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
+				   u16 mmio_base)
+{
+	int i;
+	u32 value;
+
+	bcm43xx_write32(bcm,
+			mmio_base + BCM43xx_DMA_RX_CONTROL,
+			0x00000000);
+	for (i = 0; i < 1000; i++) {
+		value = bcm43xx_read32(bcm,
+				       mmio_base + BCM43xx_DMA_RX_STATUS);
+		value &= BCM43xx_DMA_RXSTAT_STAT_MASK;
+		if (value == BCM43xx_DMA_RXSTAT_STAT_DISABLED) {
+			i = -1;
+			break;
+		}
+		udelay(10);
+	}
+	if (i != -1) {
+		printk(KERN_ERR PFX "Error: Wait on DMA RX status timed out.\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/* Reset the RX DMA channel */
+int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
+				   u16 mmio_base)
+{
+	int i;
+	u32 value;
+
+	for (i = 0; i < 1000; i++) {
+		value = bcm43xx_read32(bcm,
+				       mmio_base + BCM43xx_DMA_TX_STATUS);
+		value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
+		if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED ||
+		    value == BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT ||
+		    value == BCM43xx_DMA_TXSTAT_STAT_STOPPED)
+			break;
+		udelay(10);
+	}
+	bcm43xx_write32(bcm,
+			mmio_base + BCM43xx_DMA_TX_CONTROL,
+			0x00000000);
+	for (i = 0; i < 1000; i++) {
+		value = bcm43xx_read32(bcm,
+				       mmio_base + BCM43xx_DMA_TX_STATUS);
+		value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
+		if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED) {
+			i = -1;
+			break;
+		}
+		udelay(10);
+	}
+	if (i != -1) {
+		printk(KERN_ERR PFX "Error: Wait on DMA TX status timed out.\n");
+		return -ENODEV;
+	}
+	/* ensure the reset is completed. */
+	udelay(300);
+
+	return 0;
+}
+
+static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
+			       struct bcm43xx_dmadesc *desc,
+			       struct bcm43xx_dmadesc_meta *meta,
+			       gfp_t gfp_flags)
+{
+	struct bcm43xx_rxhdr *rxhdr;
+	dma_addr_t dmaaddr;
+	u32 desc_addr;
+	u32 desc_ctl;
+	const int slot = (int)(desc - ring->vbase);
+	struct sk_buff *skb;
+
+	assert(slot >= 0 && slot < ring->nr_slots);
+	assert(!ring->tx);
+
+	skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+	if (unlikely(!skb))
+		return -ENOMEM;
+	dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
+	if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) {
+		unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
+		dev_kfree_skb_any(skb);
+		printk(KERN_ERR PFX ">>>FATAL ERROR<<<  DMA RX SKB >1G "
+				    "(0x%08x, len: %u)\n",
+		       dmaaddr, ring->rx_buffersize);
+		return -ENOMEM;
+	}
+	meta->skb = skb;
+	meta->dmaaddr = dmaaddr;
+	skb->dev = ring->bcm->net_dev;
+	desc_addr = (u32)(dmaaddr + ring->memoffset);
+	desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK &
+		    (u32)(ring->rx_buffersize - ring->frameoffset));
+	if (slot == ring->nr_slots - 1)
+		desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
+	set_desc_addr(desc, desc_addr);
+	set_desc_ctl(desc, desc_ctl);
+
+	rxhdr = (struct bcm43xx_rxhdr *)(skb->data);
+	rxhdr->frame_length = 0;
+	rxhdr->flags1 = 0;
+
+	return 0;
+}
+
+/* Allocate the initial descbuffers.
+ * This is used for an RX ring only.
+ */
+static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring)
+{
+	int i, err = -ENOMEM;
+	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_meta *meta;
+
+	for (i = 0; i < ring->nr_slots; i++) {
+		desc = ring->vbase + i;
+		meta = ring->meta + i;
+
+		err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
+		if (err)
+			goto err_unwind;
+	}
+	ring->used_slots = ring->nr_slots;
+	err = 0;
+out:
+	return err;
+
+err_unwind:
+	for (i--; i >= 0; i--) {
+		desc = ring->vbase + i;
+		meta = ring->meta + i;
+
+		unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
+		dev_kfree_skb(meta->skb);
+	}
+	goto out;
+}
+
+/* Do initial setup of the DMA controller.
+ * Reset the controller, write the ring busaddress
+ * and switch the "enable" bit on.
+ */
+static int dmacontroller_setup(struct bcm43xx_dmaring *ring)
+{
+	int err = 0;
+	u32 value;
+
+	if (ring->tx) {
+		/* Set Transmit Control register to "transmit enable" */
+		bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
+				  BCM43xx_DMA_TXCTRL_ENABLE);
+		/* Set Transmit Descriptor ring address. */
+		bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING,
+				  ring->dmabase + ring->memoffset);
+	} else {
+		err = alloc_initial_descbuffers(ring);
+		if (err)
+			goto out;
+		/* Set Receive Control "receive enable" and frame offset */
+		value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT);
+		value |= BCM43xx_DMA_RXCTRL_ENABLE;
+		bcm43xx_dma_write(ring, BCM43xx_DMA_RX_CONTROL, value);
+		/* Set Receive Descriptor ring address. */
+		bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING,
+				  ring->dmabase + ring->memoffset);
+		/* Init the descriptor pointer. */
+		bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, 200);
+	}
+
+out:
+	return err;
+}
+
+/* Shutdown the DMA controller. */
+static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring)
+{
+	if (ring->tx) {
+		bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base);
+		/* Zero out Transmit Descriptor ring address. */
+		bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, 0);
+	} else {
+		bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base);
+		/* Zero out Receive Descriptor ring address. */
+		bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, 0);
+	}
+}
+
+static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
+{
+	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_meta *meta;
+	int i;
+
+	if (!ring->used_slots)
+		return;
+	for (i = 0; i < ring->nr_slots; i++) {
+		desc = ring->vbase + i;
+		meta = ring->meta + i;
+
+		if (!meta->skb) {
+			assert(ring->tx);
+			continue;
+		}
+		if (ring->tx) {
+			unmap_descbuffer(ring, meta->dmaaddr,
+					 meta->skb->len, 1);
+		} else {
+			unmap_descbuffer(ring, meta->dmaaddr,
+					 ring->rx_buffersize, 0);
+		}
+		free_descriptor_buffer(ring, desc, meta, 0);
+	}
+}
+
+/* Main initialization function. */
+static
+struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
+					       u16 dma_controller_base,
+					       int nr_descriptor_slots,
+					       int tx)
+{
+	struct bcm43xx_dmaring *ring;
+	int err;
+
+	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+	if (!ring)
+		goto out;
+
+	ring->meta = kzalloc(sizeof(*ring->meta) * nr_descriptor_slots,
+			     GFP_KERNEL);
+	if (!ring->meta)
+		goto err_kfree_ring;
+
+	ring->memoffset = BCM43xx_DMA_DMABUSADDROFFSET;
+#ifdef CONFIG_BCM947XX
+	if (bcm->pci_dev->bus->number == 0)
+		ring->memoffset = 0;
+#endif
+
+	ring->bcm = bcm;
+	ring->nr_slots = nr_descriptor_slots;
+	ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100;
+	ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100;
+	assert(ring->suspend_mark < ring->resume_mark);
+	ring->mmio_base = dma_controller_base;
+	if (tx) {
+		ring->tx = 1;
+		ring->current_slot = -1;
+	} else {
+		switch (dma_controller_base) {
+		case BCM43xx_MMIO_DMA1_BASE:
+			ring->rx_buffersize = BCM43xx_DMA1_RXBUFFERSIZE;
+			ring->frameoffset = BCM43xx_DMA1_RX_FRAMEOFFSET;
+			break;
+		case BCM43xx_MMIO_DMA4_BASE:
+			ring->rx_buffersize = BCM43xx_DMA4_RXBUFFERSIZE;
+			ring->frameoffset = BCM43xx_DMA4_RX_FRAMEOFFSET;
+			break;
+		default:
+			assert(0);
+		}
+	}
+
+	err = alloc_ringmemory(ring);
+	if (err)
+		goto err_kfree_meta;
+	err = dmacontroller_setup(ring);
+	if (err)
+		goto err_free_ringmemory;
+
+out:
+	return ring;
+
+err_free_ringmemory:
+	free_ringmemory(ring);
+err_kfree_meta:
+	kfree(ring->meta);
+err_kfree_ring:
+	kfree(ring);
+	ring = NULL;
+	goto out;
+}
+
+/* Main cleanup function. */
+static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring)
+{
+	if (!ring)
+		return;
+
+	dprintk(KERN_INFO PFX "DMA 0x%04x (%s) max used slots: %d/%d\n",
+		ring->mmio_base,
+		(ring->tx) ? "TX" : "RX",
+		ring->max_used_slots, ring->nr_slots);
+	/* Device IRQs are disabled prior entering this function,
+	 * so no need to take care of concurrency with rx handler stuff.
+	 */
+	dmacontroller_cleanup(ring);
+	free_all_descbuffers(ring);
+	free_ringmemory(ring);
+
+	kfree(ring->meta);
+	kfree(ring);
+}
+
+void bcm43xx_dma_free(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_dma *dma;
+
+	if (bcm43xx_using_pio(bcm))
+		return;
+	dma = bcm43xx_current_dma(bcm);
+
+	bcm43xx_destroy_dmaring(dma->rx_ring1);
+	dma->rx_ring1 = NULL;
+	bcm43xx_destroy_dmaring(dma->rx_ring0);
+	dma->rx_ring0 = NULL;
+	bcm43xx_destroy_dmaring(dma->tx_ring3);
+	dma->tx_ring3 = NULL;
+	bcm43xx_destroy_dmaring(dma->tx_ring2);
+	dma->tx_ring2 = NULL;
+	bcm43xx_destroy_dmaring(dma->tx_ring1);
+	dma->tx_ring1 = NULL;
+	bcm43xx_destroy_dmaring(dma->tx_ring0);
+	dma->tx_ring0 = NULL;
+}
+
+int bcm43xx_dma_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
+	struct bcm43xx_dmaring *ring;
+	int err = -ENOMEM;
+
+	/* setup TX DMA channels. */
+	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
+				     BCM43xx_TXRING_SLOTS, 1);
+	if (!ring)
+		goto out;
+	dma->tx_ring0 = ring;
+
+	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE,
+				     BCM43xx_TXRING_SLOTS, 1);
+	if (!ring)
+		goto err_destroy_tx0;
+	dma->tx_ring1 = ring;
+
+	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE,
+				     BCM43xx_TXRING_SLOTS, 1);
+	if (!ring)
+		goto err_destroy_tx1;
+	dma->tx_ring2 = ring;
+
+	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
+				     BCM43xx_TXRING_SLOTS, 1);
+	if (!ring)
+		goto err_destroy_tx2;
+	dma->tx_ring3 = ring;
+
+	/* setup RX DMA channels. */
+	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
+				     BCM43xx_RXRING_SLOTS, 0);
+	if (!ring)
+		goto err_destroy_tx3;
+	dma->rx_ring0 = ring;
+
+	if (bcm->current_core->rev < 5) {
+		ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
+					     BCM43xx_RXRING_SLOTS, 0);
+		if (!ring)
+			goto err_destroy_rx0;
+		dma->rx_ring1 = ring;
+	}
+
+	dprintk(KERN_INFO PFX "DMA initialized\n");
+	err = 0;
+out:
+	return err;
+
+err_destroy_rx0:
+	bcm43xx_destroy_dmaring(dma->rx_ring0);
+	dma->rx_ring0 = NULL;
+err_destroy_tx3:
+	bcm43xx_destroy_dmaring(dma->tx_ring3);
+	dma->tx_ring3 = NULL;
+err_destroy_tx2:
+	bcm43xx_destroy_dmaring(dma->tx_ring2);
+	dma->tx_ring2 = NULL;
+err_destroy_tx1:
+	bcm43xx_destroy_dmaring(dma->tx_ring1);
+	dma->tx_ring1 = NULL;
+err_destroy_tx0:
+	bcm43xx_destroy_dmaring(dma->tx_ring0);
+	dma->tx_ring0 = NULL;
+	goto out;
+}
+
+/* Generate a cookie for the TX header. */
+static u16 generate_cookie(struct bcm43xx_dmaring *ring,
+			   int slot)
+{
+	u16 cookie = 0x0000;
+
+	/* Use the upper 4 bits of the cookie as
+	 * DMA controller ID and store the slot number
+	 * in the lower 12 bits
+	 */
+	switch (ring->mmio_base) {
+	default:
+		assert(0);
+	case BCM43xx_MMIO_DMA1_BASE:
+		break;
+	case BCM43xx_MMIO_DMA2_BASE:
+		cookie = 0x1000;
+		break;
+	case BCM43xx_MMIO_DMA3_BASE:
+		cookie = 0x2000;
+		break;
+	case BCM43xx_MMIO_DMA4_BASE:
+		cookie = 0x3000;
+		break;
+	}
+	assert(((u16)slot & 0xF000) == 0x0000);
+	cookie |= (u16)slot;
+
+	return cookie;
+}
+
+/* Inspect a cookie and find out to which controller/slot it belongs. */
+static
+struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm,
+				      u16 cookie, int *slot)
+{
+	struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
+	struct bcm43xx_dmaring *ring = NULL;
+
+	switch (cookie & 0xF000) {
+	case 0x0000:
+		ring = dma->tx_ring0;
+		break;
+	case 0x1000:
+		ring = dma->tx_ring1;
+		break;
+	case 0x2000:
+		ring = dma->tx_ring2;
+		break;
+	case 0x3000:
+		ring = dma->tx_ring3;
+		break;
+	default:
+		assert(0);
+	}
+	*slot = (cookie & 0x0FFF);
+	assert(*slot >= 0 && *slot < ring->nr_slots);
+
+	return ring;
+}
+
+static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
+				  int slot)
+{
+	/* Everything is ready to start. Buffers are DMA mapped and
+	 * associated with slots.
+	 * "slot" is the last slot of the new frame we want to transmit.
+	 * Close your seat belts now, please.
+	 */
+	wmb();
+	slot = next_slot(ring, slot);
+	bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_INDEX,
+			  (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
+}
+
+static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
+			   struct sk_buff *skb,
+			   u8 cur_frag)
+{
+	int slot;
+	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_meta *meta;
+	u32 desc_ctl;
+	u32 desc_addr;
+
+	assert(skb_shinfo(skb)->nr_frags == 0);
+
+	slot = request_slot(ring);
+	desc = ring->vbase + slot;
+	meta = ring->meta + slot;
+
+	/* Add a device specific TX header. */
+	assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr));
+	/* Reserve enough headroom for the device tx header. */
+	__skb_push(skb, sizeof(struct bcm43xx_txhdr));
+	/* Now calculate and add the tx header.
+	 * The tx header includes the PLCP header.
+	 */
+	bcm43xx_generate_txhdr(ring->bcm,
+			       (struct bcm43xx_txhdr *)skb->data,
+			       skb->data + sizeof(struct bcm43xx_txhdr),
+			       skb->len - sizeof(struct bcm43xx_txhdr),
+			       (cur_frag == 0),
+			       generate_cookie(ring, slot));
+
+	meta->skb = skb;
+	meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+	if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) {
+		return_slot(ring, slot);
+		printk(KERN_ERR PFX ">>>FATAL ERROR<<<  DMA TX SKB >1G "
+				    "(0x%08x, len: %u)\n",
+		       meta->dmaaddr, skb->len);
+		return -ENOMEM;
+	}
+
+	desc_addr = (u32)(meta->dmaaddr + ring->memoffset);
+	desc_ctl = BCM43xx_DMADTOR_FRAMESTART | BCM43xx_DMADTOR_FRAMEEND;
+	desc_ctl |= BCM43xx_DMADTOR_COMPIRQ;
+	desc_ctl |= (BCM43xx_DMADTOR_BYTECNT_MASK &
+		     (u32)(meta->skb->len - ring->frameoffset));
+	if (slot == ring->nr_slots - 1)
+		desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
+
+	set_desc_ctl(desc, desc_ctl);
+	set_desc_addr(desc, desc_addr);
+	/* Now transfer the whole frame. */
+	dmacontroller_poke_tx(ring, slot);
+
+	return 0;
+}
+
+int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
+		   struct ieee80211_txb *txb)
+{
+	/* We just received a packet from the kernel network subsystem.
+	 * Add headers and DMA map the memory. Poke
+	 * the device to send the stuff.
+	 * Note that this is called from atomic context.
+	 */
+	struct bcm43xx_dmaring *ring = bcm43xx_current_dma(bcm)->tx_ring1;
+	u8 i;
+	struct sk_buff *skb;
+
+	assert(ring->tx);
+	if (unlikely(free_slots(ring) < txb->nr_frags)) {
+		/* The queue should be stopped,
+		 * if we are low on free slots.
+		 * If this ever triggers, we have to lower the suspend_mark.
+		 */
+		dprintkl(KERN_ERR PFX "Out of DMA descriptor slots!\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < txb->nr_frags; i++) {
+		skb = txb->fragments[i];
+		/* Take skb from ieee80211_txb_free */
+		txb->fragments[i] = NULL;
+		dma_tx_fragment(ring, skb, i);
+		//TODO: handle failure of dma_tx_fragment
+	}
+	ieee80211_txb_free(txb);
+
+	return 0;
+}
+
+void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
+				   struct bcm43xx_xmitstatus *status)
+{
+	struct bcm43xx_dmaring *ring;
+	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_meta *meta;
+	int is_last_fragment;
+	int slot;
+
+	ring = parse_cookie(bcm, status->cookie, &slot);
+	assert(ring);
+	assert(ring->tx);
+	assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART);
+	while (1) {
+		assert(slot >= 0 && slot < ring->nr_slots);
+		desc = ring->vbase + slot;
+		meta = ring->meta + slot;
+
+		is_last_fragment = !!(get_desc_ctl(desc) & BCM43xx_DMADTOR_FRAMEEND);
+		unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
+		free_descriptor_buffer(ring, desc, meta, 1);
+		/* Everything belonging to the slot is unmapped
+		 * and freed, so we can return it.
+		 */
+		return_slot(ring, slot);
+
+		if (is_last_fragment)
+			break;
+		slot = next_slot(ring, slot);
+	}
+	bcm->stats.last_tx = jiffies;
+}
+
+static void dma_rx(struct bcm43xx_dmaring *ring,
+		   int *slot)
+{
+	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_meta *meta;
+	struct bcm43xx_rxhdr *rxhdr;
+	struct sk_buff *skb;
+	u16 len;
+	int err;
+	dma_addr_t dmaaddr;
+
+	desc = ring->vbase + *slot;
+	meta = ring->meta + *slot;
+
+	sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
+	skb = meta->skb;
+
+	if (ring->mmio_base == BCM43xx_MMIO_DMA4_BASE) {
+		/* We received an xmit status. */
+		struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data;
+		struct bcm43xx_xmitstatus stat;
+
+		stat.cookie = le16_to_cpu(hw->cookie);
+		stat.flags = hw->flags;
+		stat.cnt1 = hw->cnt1;
+		stat.cnt2 = hw->cnt2;
+		stat.seq = le16_to_cpu(hw->seq);
+		stat.unknown = le16_to_cpu(hw->unknown);
+
+		bcm43xx_debugfs_log_txstat(ring->bcm, &stat);
+		bcm43xx_dma_handle_xmitstatus(ring->bcm, &stat);
+		/* recycle the descriptor buffer. */
+		sync_descbuffer_for_device(ring, meta->dmaaddr, ring->rx_buffersize);
+
+		return;
+	}
+	rxhdr = (struct bcm43xx_rxhdr *)skb->data;
+	len = le16_to_cpu(rxhdr->frame_length);
+	if (len == 0) {
+		int i = 0;
+
+		do {
+			udelay(2);
+			barrier();
+			len = le16_to_cpu(rxhdr->frame_length);
+		} while (len == 0 && i++ < 5);
+		if (unlikely(len == 0)) {
+			/* recycle the descriptor buffer. */
+			sync_descbuffer_for_device(ring, meta->dmaaddr,
+						   ring->rx_buffersize);
+			goto drop;
+		}
+	}
+	if (unlikely(len > ring->rx_buffersize)) {
+		/* The data did not fit into one descriptor buffer
+		 * and is split over multiple buffers.
+		 * This should never happen, as we try to allocate buffers
+		 * big enough. So simply ignore this packet.
+		 */
+		int cnt = 0;
+		s32 tmp = len;
+
+		while (1) {
+			desc = ring->vbase + *slot;
+			meta = ring->meta + *slot;
+			/* recycle the descriptor buffer. */
+			sync_descbuffer_for_device(ring, meta->dmaaddr,
+						   ring->rx_buffersize);
+			*slot = next_slot(ring, *slot);
+			cnt++;
+			tmp -= ring->rx_buffersize;
+			if (tmp <= 0)
+				break;
+		}
+		printkl(KERN_ERR PFX "DMA RX buffer too small "
+				     "(len: %u, buffer: %u, nr-dropped: %d)\n",
+		        len, ring->rx_buffersize, cnt);
+		goto drop;
+	}
+	len -= IEEE80211_FCS_LEN;
+
+	dmaaddr = meta->dmaaddr;
+	err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
+	if (unlikely(err)) {
+		dprintkl(KERN_ERR PFX "DMA RX: setup_rx_descbuffer() failed\n");
+		sync_descbuffer_for_device(ring, dmaaddr,
+					   ring->rx_buffersize);
+		goto drop;
+	}
+
+	unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
+	skb_put(skb, len + ring->frameoffset);
+	skb_pull(skb, ring->frameoffset);
+
+	err = bcm43xx_rx(ring->bcm, skb, rxhdr);
+	if (err) {
+		dev_kfree_skb_irq(skb);
+		goto drop;
+	}
+
+drop:
+	return;
+}
+
+void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
+{
+	u32 status;
+	u16 descptr;
+	int slot, current_slot;
+#ifdef CONFIG_BCM43XX_DEBUG
+	int used_slots = 0;
+#endif
+
+	assert(!ring->tx);
+	status = bcm43xx_dma_read(ring, BCM43xx_DMA_RX_STATUS);
+	descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK);
+	current_slot = descptr / sizeof(struct bcm43xx_dmadesc);
+	assert(current_slot >= 0 && current_slot < ring->nr_slots);
+
+	slot = ring->current_slot;
+	for ( ; slot != current_slot; slot = next_slot(ring, slot)) {
+		dma_rx(ring, &slot);
+#ifdef CONFIG_BCM43XX_DEBUG
+		if (++used_slots > ring->max_used_slots)
+			ring->max_used_slots = used_slots;
+#endif
+	}
+	bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX,
+			  (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
+	ring->current_slot = slot;
+}
+
+void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring)
+{
+	assert(ring->tx);
+	bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1);
+	bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
+			  bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
+			  | BCM43xx_DMA_TXCTRL_SUSPEND);
+}
+
+void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
+{
+	assert(ring->tx);
+	bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
+			  bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
+			  & ~BCM43xx_DMA_TXCTRL_SUSPEND);
+	bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1);
+}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
new file mode 100644
index 0000000..2d520e4
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
@@ -0,0 +1,218 @@
+#ifndef BCM43xx_DMA_H_
+#define BCM43xx_DMA_H_
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/linkage.h>
+#include <asm/atomic.h>
+
+
+/* DMA-Interrupt reasons. */
+#define BCM43xx_DMAIRQ_FATALMASK	((1 << 10) | (1 << 11) | (1 << 12) \
+					 | (1 << 14) | (1 << 15))
+#define BCM43xx_DMAIRQ_NONFATALMASK	(1 << 13)
+#define BCM43xx_DMAIRQ_RX_DONE		(1 << 16)
+
+/* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */
+#define BCM43xx_DMA_TX_CONTROL		0x00
+#define BCM43xx_DMA_TX_DESC_RING	0x04
+#define BCM43xx_DMA_TX_DESC_INDEX	0x08
+#define BCM43xx_DMA_TX_STATUS		0x0c
+#define BCM43xx_DMA_RX_CONTROL		0x10
+#define BCM43xx_DMA_RX_DESC_RING	0x14
+#define BCM43xx_DMA_RX_DESC_INDEX	0x18
+#define BCM43xx_DMA_RX_STATUS		0x1c
+
+/* DMA controller channel control word values. */
+#define BCM43xx_DMA_TXCTRL_ENABLE		(1 << 0)
+#define BCM43xx_DMA_TXCTRL_SUSPEND		(1 << 1)
+#define BCM43xx_DMA_TXCTRL_LOOPBACK		(1 << 2)
+#define BCM43xx_DMA_TXCTRL_FLUSH		(1 << 4)
+#define BCM43xx_DMA_RXCTRL_ENABLE		(1 << 0)
+#define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK	0x000000fe
+#define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT	1
+#define BCM43xx_DMA_RXCTRL_PIO			(1 << 8)
+/* DMA controller channel status word values. */
+#define BCM43xx_DMA_TXSTAT_DPTR_MASK		0x00000fff
+#define BCM43xx_DMA_TXSTAT_STAT_MASK		0x0000f000
+#define BCM43xx_DMA_TXSTAT_STAT_DISABLED	0x00000000
+#define BCM43xx_DMA_TXSTAT_STAT_ACTIVE		0x00001000
+#define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT	0x00002000
+#define BCM43xx_DMA_TXSTAT_STAT_STOPPED		0x00003000
+#define BCM43xx_DMA_TXSTAT_STAT_SUSP		0x00004000
+#define BCM43xx_DMA_TXSTAT_ERROR_MASK		0x000f0000
+#define BCM43xx_DMA_TXSTAT_FLUSHED		(1 << 20)
+#define BCM43xx_DMA_RXSTAT_DPTR_MASK		0x00000fff
+#define BCM43xx_DMA_RXSTAT_STAT_MASK		0x0000f000
+#define BCM43xx_DMA_RXSTAT_STAT_DISABLED	0x00000000
+#define BCM43xx_DMA_RXSTAT_STAT_ACTIVE		0x00001000
+#define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT	0x00002000
+#define BCM43xx_DMA_RXSTAT_STAT_RESERVED	0x00003000
+#define BCM43xx_DMA_RXSTAT_STAT_ERRORS		0x00004000
+#define BCM43xx_DMA_RXSTAT_ERROR_MASK		0x000f0000
+
+/* DMA descriptor control field values. */
+#define BCM43xx_DMADTOR_BYTECNT_MASK		0x00001fff
+#define BCM43xx_DMADTOR_DTABLEEND		(1 << 28) /* End of descriptor table */
+#define BCM43xx_DMADTOR_COMPIRQ			(1 << 29) /* IRQ on completion request */
+#define BCM43xx_DMADTOR_FRAMEEND		(1 << 30)
+#define BCM43xx_DMADTOR_FRAMESTART		(1 << 31)
+
+/* Misc DMA constants */
+#define BCM43xx_DMA_RINGMEMSIZE		PAGE_SIZE
+#define BCM43xx_DMA_BUSADDRMAX		0x3FFFFFFF
+#define BCM43xx_DMA_DMABUSADDROFFSET	(1 << 30)
+#define BCM43xx_DMA1_RX_FRAMEOFFSET	30
+#define BCM43xx_DMA4_RX_FRAMEOFFSET	0
+
+/* DMA engine tuning knobs */
+#define BCM43xx_TXRING_SLOTS		512
+#define BCM43xx_RXRING_SLOTS		64
+#define BCM43xx_DMA1_RXBUFFERSIZE	(2304 + 100)
+#define BCM43xx_DMA4_RXBUFFERSIZE	16
+/* Suspend the tx queue, if less than this percent slots are free. */
+#define BCM43xx_TXSUSPEND_PERCENT	20
+/* Resume the tx queue, if more than this percent slots are free. */
+#define BCM43xx_TXRESUME_PERCENT	50
+
+
+
+#ifdef CONFIG_BCM43XX_DMA
+
+
+struct sk_buff;
+struct bcm43xx_private;
+struct bcm43xx_xmitstatus;
+
+
+struct bcm43xx_dmadesc {
+	__le32 _control;
+	__le32 _address;
+} __attribute__((__packed__));
+
+/* Macros to access the bcm43xx_dmadesc struct */
+#define get_desc_ctl(desc)		le32_to_cpu((desc)->_control)
+#define set_desc_ctl(desc, ctl)		do { (desc)->_control = cpu_to_le32(ctl); } while (0)
+#define get_desc_addr(desc)		le32_to_cpu((desc)->_address)
+#define set_desc_addr(desc, addr)	do { (desc)->_address = cpu_to_le32(addr); } while (0)
+
+struct bcm43xx_dmadesc_meta {
+	/* The kernel DMA-able buffer. */
+	struct sk_buff *skb;
+	/* DMA base bus-address of the descriptor buffer. */
+	dma_addr_t dmaaddr;
+};
+
+struct bcm43xx_dmaring {
+	struct bcm43xx_private *bcm;
+	/* Kernel virtual base address of the ring memory. */
+	struct bcm43xx_dmadesc *vbase;
+	/* DMA memory offset */
+	dma_addr_t memoffset;
+	/* (Unadjusted) DMA base bus-address of the ring memory. */
+	dma_addr_t dmabase;
+	/* Meta data about all descriptors. */
+	struct bcm43xx_dmadesc_meta *meta;
+	/* Number of descriptor slots in the ring. */
+	int nr_slots;
+	/* Number of used descriptor slots. */
+	int used_slots;
+	/* Currently used slot in the ring. */
+	int current_slot;
+	/* Marks to suspend/resume the queue. */
+	int suspend_mark;
+	int resume_mark;
+	/* Frameoffset in octets. */
+	u32 frameoffset;
+	/* Descriptor buffer size. */
+	u16 rx_buffersize;
+	/* The MMIO base register of the DMA controller, this
+	 * ring is posted to.
+	 */
+	u16 mmio_base;
+	u8 tx:1,	/* TRUE, if this is a TX ring. */
+	   suspended:1;	/* TRUE, if transfers are suspended on this ring. */
+#ifdef CONFIG_BCM43XX_DEBUG
+	/* Maximum number of used slots. */
+	int max_used_slots;
+#endif /* CONFIG_BCM43XX_DEBUG*/
+};
+
+
+static inline
+u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring,
+		     u16 offset)
+{
+	return bcm43xx_read32(ring->bcm, ring->mmio_base + offset);
+}
+
+static inline
+void bcm43xx_dma_write(struct bcm43xx_dmaring *ring,
+		       u16 offset, u32 value)
+{
+	bcm43xx_write32(ring->bcm, ring->mmio_base + offset, value);
+}
+
+
+int bcm43xx_dma_init(struct bcm43xx_private *bcm);
+void bcm43xx_dma_free(struct bcm43xx_private *bcm);
+
+int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
+				   u16 dmacontroller_mmio_base);
+int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
+				   u16 dmacontroller_mmio_base);
+
+void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring);
+void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring);
+
+void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
+				   struct bcm43xx_xmitstatus *status);
+
+int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
+		   struct ieee80211_txb *txb);
+void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);
+
+
+#else /* CONFIG_BCM43XX_DMA */
+
+
+static inline
+int bcm43xx_dma_init(struct bcm43xx_private *bcm)
+{
+	return 0;
+}
+static inline
+void bcm43xx_dma_free(struct bcm43xx_private *bcm)
+{
+}
+static inline
+int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
+				   u16 dmacontroller_mmio_base)
+{
+	return 0;
+}
+static inline
+int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
+				   u16 dmacontroller_mmio_base)
+{
+	return 0;
+}
+static inline
+int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
+		   struct ieee80211_txb *txb)
+{
+	return 0;
+}
+static inline
+void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
+				   struct bcm43xx_xmitstatus *status)
+{
+}
+static inline
+void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
+{
+}
+
+#endif /* CONFIG_BCM43XX_DMA */
+#endif /* BCM43xx_DMA_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
new file mode 100644
index 0000000..b3ffcf5
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
@@ -0,0 +1,50 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  ethtool support
+
+  Copyright (c) 2006 Jason Lunz <lunz@falooley.org>
+
+  Some code in this file is derived from the 8139too.c driver
+  Copyright (C) 2002 Jeff Garzik
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx.h"
+#include "bcm43xx_ethtool.h"
+
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/version.h>
+
+
+static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(dev);
+
+	strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+	strncpy(info->version, UTS_RELEASE, sizeof(info->version));
+	strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN);
+}
+
+struct ethtool_ops bcm43xx_ethtool_ops = {
+	.get_drvinfo = bcm43xx_get_drvinfo,
+	.get_link = ethtool_op_get_link,
+};
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h
new file mode 100644
index 0000000..8137049
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h
@@ -0,0 +1,8 @@
+#ifndef BCM43xx_ETHTOOL_H_
+#define BCM43xx_ETHTOOL_H_
+
+#include <linux/ethtool.h>
+
+extern struct ethtool_ops bcm43xx_ethtool_ops;
+
+#endif /* BCM43xx_ETHTOOL_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c
new file mode 100644
index 0000000..ad8e569
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c
@@ -0,0 +1,337 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx.h"
+#include "bcm43xx_ilt.h"
+#include "bcm43xx_phy.h"
+
+
+/**** Initial Internal Lookup Tables ****/
+
+const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE] = {
+	0xFEB93FFD, 0xFEC63FFD, /* 0 */
+	0xFED23FFD, 0xFEDF3FFD,
+	0xFEEC3FFE, 0xFEF83FFE,
+	0xFF053FFE, 0xFF113FFE,
+	0xFF1E3FFE, 0xFF2A3FFF, /* 8 */
+	0xFF373FFF, 0xFF443FFF,
+	0xFF503FFF, 0xFF5D3FFF,
+	0xFF693FFF, 0xFF763FFF,
+	0xFF824000, 0xFF8F4000, /* 16 */
+	0xFF9B4000, 0xFFA84000,
+	0xFFB54000, 0xFFC14000,
+	0xFFCE4000, 0xFFDA4000,
+	0xFFE74000, 0xFFF34000, /* 24 */
+	0x00004000, 0x000D4000,
+	0x00194000, 0x00264000,
+	0x00324000, 0x003F4000,
+	0x004B4000, 0x00584000, /* 32 */
+	0x00654000, 0x00714000,
+	0x007E4000, 0x008A3FFF,
+	0x00973FFF, 0x00A33FFF,
+	0x00B03FFF, 0x00BC3FFF, /* 40 */
+	0x00C93FFF, 0x00D63FFF,
+	0x00E23FFE, 0x00EF3FFE,
+	0x00FB3FFE, 0x01083FFE,
+	0x01143FFE, 0x01213FFD, /* 48 */
+	0x012E3FFD, 0x013A3FFD,
+	0x01473FFD,
+};
+
+const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE] = {
+	0xDB93CB87, 0xD666CF64, /* 0 */
+	0xD1FDD358, 0xCDA6D826,
+	0xCA38DD9F, 0xC729E2B4,
+	0xC469E88E, 0xC26AEE2B,
+	0xC0DEF46C, 0xC073FA62, /* 8 */
+	0xC01D00D5, 0xC0760743,
+	0xC1560D1E, 0xC2E51369,
+	0xC4ED18FF, 0xC7AC1ED7,
+	0xCB2823B2, 0xCEFA28D9, /* 16 */
+	0xD2F62D3F, 0xD7BB3197,
+	0xDCE53568, 0xE1FE3875,
+	0xE7D13B35, 0xED663D35,
+	0xF39B3EC4, 0xF98E3FA7, /* 24 */
+	0x00004000, 0x06723FA7,
+	0x0C653EC4, 0x129A3D35,
+	0x182F3B35, 0x1E023875,
+	0x231B3568, 0x28453197, /* 32 */
+	0x2D0A2D3F, 0x310628D9,
+	0x34D823B2, 0x38541ED7,
+	0x3B1318FF, 0x3D1B1369,
+	0x3EAA0D1E, 0x3F8A0743, /* 40 */
+	0x3FE300D5, 0x3F8DFA62,
+	0x3F22F46C, 0x3D96EE2B,
+	0x3B97E88E, 0x38D7E2B4,
+	0x35C8DD9F, 0x325AD826, /* 48 */
+	0x2E03D358, 0x299ACF64,
+	0x246DCB87,
+};
+
+const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE] = {
+	0x0082, 0x0082, 0x0102, 0x0182, /* 0 */
+ 	0x0202, 0x0282, 0x0302, 0x0382,
+ 	0x0402, 0x0482, 0x0502, 0x0582,
+ 	0x05E2, 0x0662, 0x06E2, 0x0762,
+ 	0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */
+ 	0x09C2, 0x0A22, 0x0AA2, 0x0B02,
+ 	0x0B82, 0x0BE2, 0x0C62, 0x0CC2,
+ 	0x0D42, 0x0DA2, 0x0E02, 0x0E62,
+ 	0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */
+ 	0x1062, 0x10C2, 0x1122, 0x1182,
+ 	0x11E2, 0x1242, 0x12A2, 0x12E2,
+ 	0x1342, 0x13A2, 0x1402, 0x1442,
+ 	0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */
+ 	0x15E2, 0x1622, 0x1662, 0x16C1,
+ 	0x1701, 0x1741, 0x1781, 0x17E1,
+ 	0x1821, 0x1861, 0x18A1, 0x18E1,
+ 	0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */
+ 	0x1A21, 0x1A61, 0x1AA1, 0x1AC1,
+ 	0x1B01, 0x1B41, 0x1B81, 0x1BA1,
+ 	0x1BE1, 0x1C21, 0x1C41, 0x1C81,
+ 	0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */
+ 	0x1D61, 0x1DA1, 0x1DC1, 0x1E01,
+ 	0x1E21, 0x1E61, 0x1E81, 0x1EA1,
+ 	0x1EE1, 0x1F01, 0x1F21, 0x1F41,
+ 	0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */
+ 	0x2001, 0x2041, 0x2061, 0x2081,
+ 	0x20A1, 0x20C1, 0x20E1, 0x2101,
+ 	0x2121, 0x2141, 0x2161, 0x2181,
+ 	0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */
+ 	0x2221, 0x2241, 0x2261, 0x2281,
+ 	0x22A1, 0x22C1, 0x22C1, 0x22E1,
+ 	0x2301, 0x2321, 0x2341, 0x2361,
+ 	0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */
+ 	0x23E1, 0x23E1, 0x2401, 0x2421,
+ 	0x2441, 0x2441, 0x2461, 0x2481,
+ 	0x2481, 0x24A1, 0x24C1, 0x24C1,
+ 	0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */
+ 	0x2541, 0x2541, 0x2561, 0x2561,
+ 	0x2581, 0x25A1, 0x25A1, 0x25C1,
+ 	0x25C1, 0x25E1, 0x2601, 0x2601,
+ 	0x2621, 0x2621, 0x2641, 0x2641, /* 160 */
+ 	0x2661, 0x2661, 0x2681, 0x2681,
+ 	0x26A1, 0x26A1, 0x26C1, 0x26C1,
+ 	0x26E1, 0x26E1, 0x2701, 0x2701,
+ 	0x2721, 0x2721, 0x2740, 0x2740, /* 176 */
+ 	0x2760, 0x2760, 0x2780, 0x2780,
+ 	0x2780, 0x27A0, 0x27A0, 0x27C0,
+ 	0x27C0, 0x27E0, 0x27E0, 0x27E0,
+ 	0x2800, 0x2800, 0x2820, 0x2820, /* 192 */
+ 	0x2820, 0x2840, 0x2840, 0x2840,
+ 	0x2860, 0x2860, 0x2880, 0x2880,
+ 	0x2880, 0x28A0, 0x28A0, 0x28A0,
+ 	0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */
+ 	0x28E0, 0x28E0, 0x2900, 0x2900,
+ 	0x2900, 0x2920, 0x2920, 0x2920,
+ 	0x2940, 0x2940, 0x2940, 0x2960,
+ 	0x2960, 0x2960, 0x2960, 0x2980, /* 224 */
+ 	0x2980, 0x2980, 0x29A0, 0x29A0,
+ 	0x29A0, 0x29A0, 0x29C0, 0x29C0,
+ 	0x29C0, 0x29E0, 0x29E0, 0x29E0,
+ 	0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */
+ 	0x2A00, 0x2A20, 0x2A20, 0x2A20,
+ 	0x2A20, 0x2A40, 0x2A40, 0x2A40,
+ 	0x2A40, 0x2A60, 0x2A60, 0x2A60,
+};
+
+const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE] = {
+	0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */
+	0x05A9, 0x0669, 0x0709, 0x0789,
+	0x0829, 0x08A9, 0x0929, 0x0989,
+	0x0A09, 0x0A69, 0x0AC9, 0x0B29,
+	0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */
+	0x0D09, 0x0D69, 0x0DA9, 0x0E09,
+	0x0E69, 0x0EA9, 0x0F09, 0x0F49,
+	0x0FA9, 0x0FE9, 0x1029, 0x1089,
+	0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */
+	0x11E9, 0x1229, 0x1289, 0x12C9,
+	0x1309, 0x1349, 0x1389, 0x13C9,
+	0x1409, 0x1449, 0x14A9, 0x14E9,
+	0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */
+	0x1629, 0x1669, 0x16A9, 0x16E8,
+	0x1728, 0x1768, 0x17A8, 0x17E8,
+	0x1828, 0x1868, 0x18A8, 0x18E8,
+	0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */
+	0x1A28, 0x1A68, 0x1AA8, 0x1AE8,
+	0x1B28, 0x1B68, 0x1BA8, 0x1BE8,
+	0x1C28, 0x1C68, 0x1CA8, 0x1CE8,
+	0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */
+	0x1E48, 0x1E88, 0x1EC8, 0x1F08,
+	0x1F48, 0x1F88, 0x1FE8, 0x2028,
+	0x2068, 0x20A8, 0x2108, 0x2148,
+	0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */
+	0x22C8, 0x2308, 0x2348, 0x23A8,
+	0x23E8, 0x2448, 0x24A8, 0x24E8,
+	0x2548, 0x25A8, 0x2608, 0x2668,
+	0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */
+	0x2847, 0x28C7, 0x2947, 0x29A7,
+	0x2A27, 0x2AC7, 0x2B47, 0x2BE7,
+	0x2CA7, 0x2D67, 0x2E47, 0x2F67,
+	0x3247, 0x3526, 0x3646, 0x3726, /* 128 */
+	0x3806, 0x38A6, 0x3946, 0x39E6,
+	0x3A66, 0x3AE6, 0x3B66, 0x3BC6,
+	0x3C45, 0x3CA5, 0x3D05, 0x3D85,
+	0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */
+	0x3F45, 0x3FA5, 0x4005, 0x4045,
+	0x40A5, 0x40E5, 0x4145, 0x4185,
+	0x41E5, 0x4225, 0x4265, 0x42C5,
+	0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */
+	0x4424, 0x4464, 0x44C4, 0x4504,
+	0x4544, 0x4584, 0x45C4, 0x4604,
+	0x4644, 0x46A4, 0x46E4, 0x4724,
+	0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */
+	0x4864, 0x48A4, 0x48E4, 0x4924,
+	0x4964, 0x49A4, 0x49E4, 0x4A24,
+	0x4A64, 0x4AA4, 0x4AE4, 0x4B23,
+	0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */
+	0x4C63, 0x4CA3, 0x4CE3, 0x4D23,
+	0x4D63, 0x4DA3, 0x4DE3, 0x4E23,
+	0x4E63, 0x4EA3, 0x4EE3, 0x4F23,
+	0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */
+	0x5083, 0x50C3, 0x5103, 0x5143,
+	0x5183, 0x51E2, 0x5222, 0x5262,
+	0x52A2, 0x52E2, 0x5342, 0x5382,
+	0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */
+	0x5502, 0x5542, 0x55A2, 0x55E2,
+	0x5642, 0x5682, 0x56E2, 0x5722,
+	0x5782, 0x57E1, 0x5841, 0x58A1,
+	0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */
+	0x5AA1, 0x5B01, 0x5B81, 0x5BE1,
+	0x5C61, 0x5D01, 0x5D80, 0x5E20,
+	0x5EE0, 0x5FA0, 0x6080, 0x61C0,
+};
+
+const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE] = {
+	0x0001, 0x0001, 0x0001, 0xFFFE,
+	0xFFFE, 0x3FFF, 0x1000, 0x0393,
+};
+
+const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE] = {
+	0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+	0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+};
+
+const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE] = {
+	0x013C, 0x01F5, 0x031A, 0x0631,
+	0x0001, 0x0001, 0x0001, 0x0001,
+};
+
+const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE] = {
+	0x5484, 0x3C40, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE] = {
+	0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */
+	0x2F2D, 0x2A2A, 0x2527, 0x1F21,
+	0x1A1D, 0x1719, 0x1616, 0x1414,
+	0x1414, 0x1400, 0x1414, 0x1614,
+	0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */
+	0x2A27, 0x2F2A, 0x332D, 0x3B35,
+	0x5140, 0x6C62, 0x0077,
+};
+
+const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE] = {
+	0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */
+	0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
+	0x969B, 0x9195, 0x8F8F, 0x8A8A,
+	0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
+	0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */
+	0xADA9, 0xB2AD, 0xB6B0, 0xBCB7,
+	0xCBC0, 0xD8D4, 0x00DD,
+};
+
+const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE] = {
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA400, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA4A4, 0x00A4,
+};
+
+const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE] = {
+	0x007A, 0x0075, 0x0071, 0x006C, /* 0 */
+	0x0067, 0x0063, 0x005E, 0x0059,
+	0x0054, 0x0050, 0x004B, 0x0046,
+	0x0042, 0x003D, 0x003D, 0x003D,
+	0x003D, 0x003D, 0x003D, 0x003D, /* 16 */
+	0x003D, 0x003D, 0x003D, 0x003D,
+	0x003D, 0x003D, 0x0000, 0x003D,
+	0x003D, 0x003D, 0x003D, 0x003D,
+	0x003D, 0x003D, 0x003D, 0x003D, /* 32 */
+	0x003D, 0x003D, 0x003D, 0x003D,
+	0x0042, 0x0046, 0x004B, 0x0050,
+	0x0054, 0x0059, 0x005E, 0x0063,
+	0x0067, 0x006C, 0x0071, 0x0075, /* 48 */
+	0x007A,
+};
+
+const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE] = {
+	0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */
+	0x00D6, 0x00D4, 0x00D2, 0x00CF,
+	0x00CD, 0x00CA, 0x00C7, 0x00C4,
+	0x00C1, 0x00BE, 0x00BE, 0x00BE,
+	0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,
+	0x00BE, 0x00BE, 0x0000, 0x00BE,
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,
+	0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,
+	0x00C1, 0x00C4, 0x00C7, 0x00CA,
+	0x00CD, 0x00CF, 0x00D2, 0x00D4,
+	0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */
+	0x00DE,
+};
+
+/**** Helper functions to access the device Internal Lookup Tables ****/
+
+void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val)
+{
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) {
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset);
+		mmiowb();
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val);
+	} else {
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
+		mmiowb();
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val);
+	}
+}
+
+u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset)
+{
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) {
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset);
+		return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1);
+	} else {
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
+		return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1);
+	}
+}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h
new file mode 100644
index 0000000..464521a
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h
@@ -0,0 +1,32 @@
+#ifndef BCM43xx_ILT_H_
+#define BCM43xx_ILT_H_
+
+#define BCM43xx_ILT_ROTOR_SIZE		53
+extern const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE];
+#define BCM43xx_ILT_RETARD_SIZE		53
+extern const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE];
+#define BCM43xx_ILT_FINEFREQA_SIZE	256
+extern const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE];
+#define BCM43xx_ILT_FINEFREQG_SIZE	256
+extern const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE];
+#define BCM43xx_ILT_NOISEA2_SIZE	8
+extern const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE];
+#define BCM43xx_ILT_NOISEA3_SIZE	8
+extern const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE];
+#define BCM43xx_ILT_NOISEG1_SIZE	8
+extern const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE];
+#define BCM43xx_ILT_NOISEG2_SIZE	8
+extern const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE];
+#define BCM43xx_ILT_NOISESCALEG_SIZE	27
+extern const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE];
+extern const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE];
+extern const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE];
+#define BCM43xx_ILT_SIGMASQR_SIZE	53
+extern const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE];
+extern const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE];
+
+
+void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
+u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset);
+
+#endif /* BCM43xx_ILT_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
new file mode 100644
index 0000000..4b2c02c
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -0,0 +1,293 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx_leds.h"
+#include "bcm43xx.h"
+
+#include <asm/bitops.h>
+
+
+static void bcm43xx_led_changestate(struct bcm43xx_led *led)
+{
+	struct bcm43xx_private *bcm = led->bcm;
+	const int index = bcm43xx_led_index(led);
+	const u16 mask = (1 << index);
+	u16 ledctl;
+
+	assert(index >= 0 && index < BCM43xx_NR_LEDS);
+	assert(led->blink_interval);
+	ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
+	ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+}
+
+static void bcm43xx_led_blink(unsigned long d)
+{
+	struct bcm43xx_led *led = (struct bcm43xx_led *)d;
+	struct bcm43xx_private *bcm = led->bcm;
+	unsigned long flags;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if (led->blink_interval) {
+		bcm43xx_led_changestate(led);
+		mod_timer(&led->blink_timer, jiffies + led->blink_interval);
+	}
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
+				    unsigned long interval)
+{
+	if (led->blink_interval)
+		return;
+	led->blink_interval = interval;
+	bcm43xx_led_changestate(led);
+	led->blink_timer.expires = jiffies + interval;
+	add_timer(&led->blink_timer);
+}
+
+static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync)
+{
+	struct bcm43xx_private *bcm = led->bcm;
+	const int index = bcm43xx_led_index(led);
+	u16 ledctl;
+
+	if (!led->blink_interval)
+		return;
+	if (unlikely(sync))
+		del_timer_sync(&led->blink_timer);
+	else
+		del_timer(&led->blink_timer);
+	led->blink_interval = 0;
+
+	/* Make sure the LED is turned off. */
+	assert(index >= 0 && index < BCM43xx_NR_LEDS);
+	ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
+	if (led->activelow)
+		ledctl |= (1 << index);
+	else
+		ledctl &= ~(1 << index);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+}
+
+static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm,
+				       struct bcm43xx_led *led,
+				       int led_index)
+{
+	/* This function is called, if the behaviour (and activelow)
+	 * information for a LED is missing in the SPROM.
+	 * We hardcode the behaviour values for various devices here.
+	 * Note that the BCM43xx_LED_TEST_XXX behaviour values can
+	 * be used to figure out which led is mapped to which index.
+	 */
+
+	switch (led_index) {
+	case 0:
+		led->behaviour = BCM43xx_LED_ACTIVITY;
+		if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
+			led->behaviour = BCM43xx_LED_RADIO_ALL;
+		break;
+	case 1:
+		led->behaviour = BCM43xx_LED_RADIO_B;
+		if (bcm->board_vendor == PCI_VENDOR_ID_ASUSTEK)
+			led->behaviour = BCM43xx_LED_ASSOC;
+		break;
+	case 2:
+		led->behaviour = BCM43xx_LED_RADIO_A;
+		break;
+	case 3:
+		led->behaviour = BCM43xx_LED_OFF;
+		break;
+	default:
+		assert(0);
+	}
+}
+
+int bcm43xx_leds_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_led *led;
+	u8 sprom[4];
+	int i;
+
+	sprom[0] = bcm->sprom.wl0gpio0;
+	sprom[1] = bcm->sprom.wl0gpio1;
+	sprom[2] = bcm->sprom.wl0gpio2;
+	sprom[3] = bcm->sprom.wl0gpio3;
+
+	for (i = 0; i < BCM43xx_NR_LEDS; i++) {
+		led = &(bcm->leds[i]);
+		led->bcm = bcm;
+		setup_timer(&led->blink_timer,
+			    bcm43xx_led_blink,
+			    (unsigned long)led);
+
+		if (sprom[i] == 0xFF) {
+			bcm43xx_led_init_hardcoded(bcm, led, i);
+		} else {
+			led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR;
+			led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW);
+		}
+	}
+
+	return 0;
+}
+
+void bcm43xx_leds_exit(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_led *led;
+	int i;
+
+	for (i = 0; i < BCM43xx_NR_LEDS; i++) {
+		led = &(bcm->leds[i]);
+		bcm43xx_led_blink_stop(led, 1);
+	}
+	bcm43xx_leds_switch_all(bcm, 0);
+}
+
+void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
+{
+	struct bcm43xx_led *led;
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES;
+	int i, turn_on;
+	unsigned long interval = 0;
+	u16 ledctl;
+
+	ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
+	for (i = 0; i < BCM43xx_NR_LEDS; i++) {
+		led = &(bcm->leds[i]);
+
+		turn_on = 0;
+		switch (led->behaviour) {
+		case BCM43xx_LED_INACTIVE:
+			continue;
+		case BCM43xx_LED_OFF:
+			break;
+		case BCM43xx_LED_ON:
+			turn_on = 1;
+			break;
+		case BCM43xx_LED_ACTIVITY:
+			turn_on = activity;
+			break;
+		case BCM43xx_LED_RADIO_ALL:
+			turn_on = radio->enabled;
+			break;
+		case BCM43xx_LED_RADIO_A:
+			turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A);
+			break;
+		case BCM43xx_LED_RADIO_B:
+			turn_on = (radio->enabled &&
+				   (phy->type == BCM43xx_PHYTYPE_B ||
+				    phy->type == BCM43xx_PHYTYPE_G));
+			break;
+		case BCM43xx_LED_MODE_BG:
+			if (phy->type == BCM43xx_PHYTYPE_G &&
+			    1/*FIXME: using G rates.*/)
+				turn_on = 1;
+			break;
+		case BCM43xx_LED_TRANSFER:
+			if (transferring)
+				bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
+			else
+				bcm43xx_led_blink_stop(led, 0);
+			continue;
+		case BCM43xx_LED_APTRANSFER:
+			if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
+				if (transferring) {
+					interval = BCM43xx_LEDBLINK_FAST;
+					turn_on = 1;
+				}
+			} else {
+				turn_on = 1;
+				if (0/*TODO: not assoc*/)
+					interval = BCM43xx_LEDBLINK_SLOW;
+				else if (transferring)
+					interval = BCM43xx_LEDBLINK_FAST;
+				else
+					turn_on = 0;
+			}
+			if (turn_on)
+				bcm43xx_led_blink_start(led, interval);
+			else
+				bcm43xx_led_blink_stop(led, 0);
+			continue;
+		case BCM43xx_LED_WEIRD:
+			//TODO
+			break;
+		case BCM43xx_LED_ASSOC:
+			if (bcm->softmac->associated)
+				turn_on = 1;
+			break;
+#ifdef CONFIG_BCM43XX_DEBUG
+		case BCM43xx_LED_TEST_BLINKSLOW:
+			bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW);
+			continue;
+		case BCM43xx_LED_TEST_BLINKMEDIUM:
+			bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
+			continue;
+		case BCM43xx_LED_TEST_BLINKFAST:
+			bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST);
+			continue;
+#endif /* CONFIG_BCM43XX_DEBUG */
+		default:
+			assert(0);
+		};
+
+		if (led->activelow)
+			turn_on = !turn_on;
+		if (turn_on)
+			ledctl |= (1 << i);
+		else
+			ledctl &= ~(1 << i);
+	}
+	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+}
+
+void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
+{
+	struct bcm43xx_led *led;
+	u16 ledctl;
+	int i;
+	int bit_on;
+
+	ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
+	for (i = 0; i < BCM43xx_NR_LEDS; i++) {
+		led = &(bcm->leds[i]);
+		if (led->behaviour == BCM43xx_LED_INACTIVE)
+			continue;
+		if (on)
+			bit_on = led->activelow ? 0 : 1;
+		else
+			bit_on = led->activelow ? 1 : 0;
+		if (bit_on)
+			ledctl |= (1 << i);
+		else
+			ledctl &= ~(1 << i);
+	}
+	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h
new file mode 100644
index 0000000..d3716cf
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h
@@ -0,0 +1,56 @@
+#ifndef BCM43xx_LEDS_H_
+#define BCM43xx_LEDS_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+
+
+struct bcm43xx_led {
+	u8 behaviour:7;
+	u8 activelow:1;
+
+	struct bcm43xx_private *bcm;
+	struct timer_list blink_timer;
+	unsigned long blink_interval;
+};
+#define bcm43xx_led_index(led)	((int)((led) - (led)->bcm->leds))
+
+/* Delay between state changes when blinking in jiffies */
+#define BCM43xx_LEDBLINK_SLOW		(HZ / 1)
+#define BCM43xx_LEDBLINK_MEDIUM		(HZ / 4)
+#define BCM43xx_LEDBLINK_FAST		(HZ / 8)
+
+#define BCM43xx_LED_XFER_THRES		(HZ / 100)
+
+#define BCM43xx_LED_BEHAVIOUR		0x7F
+#define BCM43xx_LED_ACTIVELOW		0x80
+enum { /* LED behaviour values */
+	BCM43xx_LED_OFF,
+	BCM43xx_LED_ON,
+	BCM43xx_LED_ACTIVITY,
+	BCM43xx_LED_RADIO_ALL,
+	BCM43xx_LED_RADIO_A,
+	BCM43xx_LED_RADIO_B,
+	BCM43xx_LED_MODE_BG,
+	BCM43xx_LED_TRANSFER,
+	BCM43xx_LED_APTRANSFER,
+	BCM43xx_LED_WEIRD,//FIXME
+	BCM43xx_LED_ASSOC,
+	BCM43xx_LED_INACTIVE,
+
+	/* Behaviour values for testing.
+	 * With these values it is easier to figure out
+	 * the real behaviour of leds, in case the SPROM
+	 * is missing information.
+	 */
+	BCM43xx_LED_TEST_BLINKSLOW,
+	BCM43xx_LED_TEST_BLINKMEDIUM,
+	BCM43xx_LED_TEST_BLINKFAST,
+};
+
+int bcm43xx_leds_init(struct bcm43xx_private *bcm);
+void bcm43xx_leds_exit(struct bcm43xx_private *bcm);
+void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity);
+void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on);
+
+#endif /* BCM43xx_LEDS_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
new file mode 100644
index 0000000..c37371f
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -0,0 +1,3973 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/version.h>
+#include <linux/firmware.h>
+#include <linux/wireless.h>
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <net/iw_handler.h>
+
+#include "bcm43xx.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_debugfs.h"
+#include "bcm43xx_radio.h"
+#include "bcm43xx_phy.h"
+#include "bcm43xx_dma.h"
+#include "bcm43xx_pio.h"
+#include "bcm43xx_power.h"
+#include "bcm43xx_wx.h"
+#include "bcm43xx_ethtool.h"
+#include "bcm43xx_xmit.h"
+
+
+MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");
+MODULE_AUTHOR("Martin Langer");
+MODULE_AUTHOR("Stefano Brivio");
+MODULE_AUTHOR("Michael Buesch");
+MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_BCM947XX
+extern char *nvram_get(char *name);
+#endif
+
+#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
+static int modparam_pio;
+module_param_named(pio, modparam_pio, int, 0444);
+MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
+#elif defined(CONFIG_BCM43XX_DMA)
+# define modparam_pio	0
+#elif defined(CONFIG_BCM43XX_PIO)
+# define modparam_pio	1
+#endif
+
+static int modparam_bad_frames_preempt;
+module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
+MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption");
+
+static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT;
+module_param_named(short_retry, modparam_short_retry, int, 0444);
+MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
+
+static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT;
+module_param_named(long_retry, modparam_long_retry, int, 0444);
+MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
+
+static int modparam_locale = -1;
+module_param_named(locale, modparam_locale, int, 0444);
+MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)");
+
+static int modparam_noleds;
+module_param_named(noleds, modparam_noleds, int, 0444);
+MODULE_PARM_DESC(noleds, "Turn off all LED activity");
+
+#ifdef CONFIG_BCM43XX_DEBUG
+static char modparam_fwpostfix[64];
+module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
+MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
+#else
+# define modparam_fwpostfix  ""
+#endif /* CONFIG_BCM43XX_DEBUG*/
+
+
+/* If you want to debug with just a single device, enable this,
+ * where the string is the pci device ID (as given by the kernel's
+ * pci_name function) of the device to be used.
+ */
+//#define DEBUG_SINGLE_DEVICE_ONLY	"0001:11:00.0"
+
+/* If you want to enable printing of each MMIO access, enable this. */
+//#define DEBUG_ENABLE_MMIO_PRINT
+
+/* If you want to enable printing of MMIO access within
+ * ucode/pcm upload, initvals write, enable this.
+ */
+//#define DEBUG_ENABLE_UCODE_MMIO_PRINT
+
+/* If you want to enable printing of PCI Config Space access, enable this */
+//#define DEBUG_ENABLE_PCILOG
+
+
+/* Detailed list maintained at:
+ * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices
+ */
+	static struct pci_device_id bcm43xx_pci_tbl[] = {
+	/* Broadcom 4303 802.11b */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+		/* Broadcom 4307 802.11b */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+		/* Broadcom 4318 802.11b/g */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	/* Broadcom 4306 802.11b/g */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+		/* Broadcom 4306 802.11a */
+//	{ PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	/* Broadcom 4309 802.11a/b/g */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	/* Broadcom 43XG 802.11b/g */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#ifdef CONFIG_BCM947XX
+	/* SB bus on BCM947xx */
+	{ PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#endif
+	{ 0 },
+};
+MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
+
+static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val)
+{
+	u32 status;
+
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP))
+		val = swab32(val);
+
+	bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset);
+	mmiowb();
+	bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val);
+}
+
+static inline
+void bcm43xx_shm_control_word(struct bcm43xx_private *bcm,
+			      u16 routing, u16 offset)
+{
+	u32 control;
+
+	/* "offset" is the WORD offset. */
+
+	control = routing;
+	control <<= 16;
+	control |= offset;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control);
+}
+
+u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm,
+		       u16 routing, u16 offset)
+{
+	u32 ret;
+
+	if (routing == BCM43xx_SHM_SHARED) {
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			bcm43xx_shm_control_word(bcm, routing, offset >> 2);
+			ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
+			ret <<= 16;
+			bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
+			ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
+
+			return ret;
+		}
+		offset >>= 2;
+	}
+	bcm43xx_shm_control_word(bcm, routing, offset);
+	ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA);
+
+	return ret;
+}
+
+u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm,
+		       u16 routing, u16 offset)
+{
+	u16 ret;
+
+	if (routing == BCM43xx_SHM_SHARED) {
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			bcm43xx_shm_control_word(bcm, routing, offset >> 2);
+			ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
+
+			return ret;
+		}
+		offset >>= 2;
+	}
+	bcm43xx_shm_control_word(bcm, routing, offset);
+	ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
+
+	return ret;
+}
+
+void bcm43xx_shm_write32(struct bcm43xx_private *bcm,
+			 u16 routing, u16 offset,
+			 u32 value)
+{
+	if (routing == BCM43xx_SHM_SHARED) {
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			bcm43xx_shm_control_word(bcm, routing, offset >> 2);
+			mmiowb();
+			bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
+					(value >> 16) & 0xffff);
+			mmiowb();
+			bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
+			mmiowb();
+			bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA,
+					value & 0xffff);
+			return;
+		}
+		offset >>= 2;
+	}
+	bcm43xx_shm_control_word(bcm, routing, offset);
+	mmiowb();
+	bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value);
+}
+
+void bcm43xx_shm_write16(struct bcm43xx_private *bcm,
+			 u16 routing, u16 offset,
+			 u16 value)
+{
+	if (routing == BCM43xx_SHM_SHARED) {
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			bcm43xx_shm_control_word(bcm, routing, offset >> 2);
+			mmiowb();
+			bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
+					value);
+			return;
+		}
+		offset >>= 2;
+	}
+	bcm43xx_shm_control_word(bcm, routing, offset);
+	mmiowb();
+	bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value);
+}
+
+void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf)
+{
+	/* We need to be careful. As we read the TSF from multiple
+	 * registers, we should take care of register overflows.
+	 * In theory, the whole tsf read process should be atomic.
+	 * We try to be atomic here, by restaring the read process,
+	 * if any of the high registers changed (overflew).
+	 */
+	if (bcm->current_core->rev >= 3) {
+		u32 low, high, high2;
+
+		do {
+			high = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
+			low = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW);
+			high2 = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
+		} while (unlikely(high != high2));
+
+		*tsf = high;
+		*tsf <<= 32;
+		*tsf |= low;
+	} else {
+		u64 tmp;
+		u16 v0, v1, v2, v3;
+		u16 test1, test2, test3;
+
+		do {
+			v3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
+			v2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
+			v1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
+			v0 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_0);
+
+			test3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
+			test2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
+			test1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
+		} while (v3 != test3 || v2 != test2 || v1 != test1);
+
+		*tsf = v3;
+		*tsf <<= 48;
+		tmp = v2;
+		tmp <<= 32;
+		*tsf |= tmp;
+		tmp = v1;
+		tmp <<= 16;
+		*tsf |= tmp;
+		*tsf |= v0;
+	}
+}
+
+void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf)
+{
+	u32 status;
+
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	status |= BCM43xx_SBF_TIME_UPDATE;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+	mmiowb();
+
+	/* Be careful with the in-progress timer.
+	 * First zero out the low register, so we have a full
+	 * register-overflow duration to complete the operation.
+	 */
+	if (bcm->current_core->rev >= 3) {
+		u32 lo = (tsf & 0x00000000FFFFFFFFULL);
+		u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
+
+		bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0);
+		mmiowb();
+		bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi);
+		mmiowb();
+		bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo);
+	} else {
+		u16 v0 = (tsf & 0x000000000000FFFFULL);
+		u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
+		u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
+		u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
+
+		bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0);
+		mmiowb();
+		bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3);
+		mmiowb();
+		bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2);
+		mmiowb();
+		bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1);
+		mmiowb();
+		bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0);
+	}
+
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	status &= ~BCM43xx_SBF_TIME_UPDATE;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+}
+
+static
+void bcm43xx_macfilter_set(struct bcm43xx_private *bcm,
+			   u16 offset,
+			   const u8 *mac)
+{
+	u16 data;
+
+	offset |= 0x0020;
+	bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset);
+
+	data = mac[0];
+	data |= mac[1] << 8;
+	bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
+	data = mac[2];
+	data |= mac[3] << 8;
+	bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
+	data = mac[4];
+	data |= mac[5] << 8;
+	bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
+}
+
+static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm,
+				    u16 offset)
+{
+	const u8 zero_addr[ETH_ALEN] = { 0 };
+
+	bcm43xx_macfilter_set(bcm, offset, zero_addr);
+}
+
+static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm)
+{
+	const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr);
+	const u8 *bssid = (const u8 *)(bcm->ieee->bssid);
+	u8 mac_bssid[ETH_ALEN * 2];
+	int i;
+
+	memcpy(mac_bssid, mac, ETH_ALEN);
+	memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
+
+	/* Write our MAC address and BSSID to template ram */
+	for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
+		bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i)));
+	for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
+		bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i)));
+	for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
+		bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i)));
+}
+
+//FIXME: Well, we should probably call them from somewhere.
+#if 0
+static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time)
+{
+	/* slot_time is in usec. */
+	if (bcm43xx_current_phy(bcm)->type != BCM43xx_PHYTYPE_G)
+		return;
+	bcm43xx_write16(bcm, 0x684, 510 + slot_time);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time);
+}
+
+static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm)
+{
+	bcm43xx_set_slot_time(bcm, 9);
+}
+
+static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm)
+{
+	bcm43xx_set_slot_time(bcm, 20);
+}
+#endif
+
+/* FIXME: To get the MAC-filter working, we need to implement the
+ *        following functions (and rename them :)
+ */
+#if 0
+static void bcm43xx_disassociate(struct bcm43xx_private *bcm)
+{
+	bcm43xx_mac_suspend(bcm);
+	bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
+
+	bcm43xx_ram_write(bcm, 0x0026, 0x0000);
+	bcm43xx_ram_write(bcm, 0x0028, 0x0000);
+	bcm43xx_ram_write(bcm, 0x007E, 0x0000);
+	bcm43xx_ram_write(bcm, 0x0080, 0x0000);
+	bcm43xx_ram_write(bcm, 0x047E, 0x0000);
+	bcm43xx_ram_write(bcm, 0x0480, 0x0000);
+
+	if (bcm->current_core->rev < 3) {
+		bcm43xx_write16(bcm, 0x0610, 0x8000);
+		bcm43xx_write16(bcm, 0x060E, 0x0000);
+	} else
+		bcm43xx_write32(bcm, 0x0188, 0x80000000);
+
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
+
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G &&
+	    ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate))
+		bcm43xx_short_slot_timing_enable(bcm);
+
+	bcm43xx_mac_enable(bcm);
+}
+
+static void bcm43xx_associate(struct bcm43xx_private *bcm,
+			      const u8 *mac)
+{
+	memcpy(bcm->ieee->bssid, mac, ETH_ALEN);
+
+	bcm43xx_mac_suspend(bcm);
+	bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac);
+	bcm43xx_write_mac_bssid_templates(bcm);
+	bcm43xx_mac_enable(bcm);
+}
+#endif
+
+/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 bcm43xx_interrupt_enable(struct bcm43xx_private *bcm, u32 mask)
+{
+	u32 old_mask;
+
+	old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask);
+
+	return old_mask;
+}
+
+/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask)
+{
+	u32 old_mask;
+
+	old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
+
+	return old_mask;
+}
+
+/* Make sure we don't receive more data from the device. */
+static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
+{
+	u32 old;
+	unsigned long flags;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
+		bcm43xx_unlock_mmio(bcm, flags);
+		return -EBUSY;
+	}
+	old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+	tasklet_disable(&bcm->isr_tasklet);
+	bcm43xx_unlock_mmio(bcm, flags);
+	if (oldstate)
+		*oldstate = old;
+
+	return 0;
+}
+
+static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u32 radio_id;
+	u16 manufact;
+	u16 version;
+	u8 revision;
+	s8 i;
+
+	if (bcm->chip_id == 0x4317) {
+		if (bcm->chip_rev == 0x00)
+			radio_id = 0x3205017F;
+		else if (bcm->chip_rev == 0x01)
+			radio_id = 0x4205017F;
+		else
+			radio_id = 0x5205017F;
+	} else {
+		bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
+		radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH);
+		radio_id <<= 16;
+		bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
+		radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);
+	}
+
+	manufact = (radio_id & 0x00000FFF);
+	version = (radio_id & 0x0FFFF000) >> 12;
+	revision = (radio_id & 0xF0000000) >> 28;
+
+	dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n",
+		radio_id, manufact, version, revision);
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+		if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f))
+			goto err_unsupported_radio;
+		break;
+	case BCM43xx_PHYTYPE_B:
+		if ((version & 0xFFF0) != 0x2050)
+			goto err_unsupported_radio;
+		break;
+	case BCM43xx_PHYTYPE_G:
+		if (version != 0x2050)
+			goto err_unsupported_radio;
+		break;
+	}
+
+	radio->manufact = manufact;
+	radio->version = version;
+	radio->revision = revision;
+
+	/* Set default attenuation values. */
+	radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
+	radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
+	radio->txctl1 = bcm43xx_default_txctl1(bcm);
+	radio->txctl2 = 0xFFFF;
+	if (phy->type == BCM43xx_PHYTYPE_A)
+		radio->txpower_desired = bcm->sprom.maxpower_aphy;
+	else
+		radio->txpower_desired = bcm->sprom.maxpower_bgphy;
+
+	/* Initialize the in-memory nrssi Lookup Table. */
+	for (i = 0; i < 64; i++)
+		radio->nrssi_lt[i] = i;
+
+	return 0;
+
+err_unsupported_radio:
+	printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n");
+	return -ENODEV;
+}
+
+static const char * bcm43xx_locale_iso(u8 locale)
+{
+	/* ISO 3166-1 country codes.
+	 * Note that there aren't ISO 3166-1 codes for
+	 * all or locales. (Not all locales are countries)
+	 */
+	switch (locale) {
+	case BCM43xx_LOCALE_WORLD:
+	case BCM43xx_LOCALE_ALL:
+		return "XX";
+	case BCM43xx_LOCALE_THAILAND:
+		return "TH";
+	case BCM43xx_LOCALE_ISRAEL:
+		return "IL";
+	case BCM43xx_LOCALE_JORDAN:
+		return "JO";
+	case BCM43xx_LOCALE_CHINA:
+		return "CN";
+	case BCM43xx_LOCALE_JAPAN:
+	case BCM43xx_LOCALE_JAPAN_HIGH:
+		return "JP";
+	case BCM43xx_LOCALE_USA_CANADA_ANZ:
+	case BCM43xx_LOCALE_USA_LOW:
+		return "US";
+	case BCM43xx_LOCALE_EUROPE:
+		return "EU";
+	case BCM43xx_LOCALE_NONE:
+		return "  ";
+	}
+	assert(0);
+	return "  ";
+}
+
+static const char * bcm43xx_locale_string(u8 locale)
+{
+	switch (locale) {
+	case BCM43xx_LOCALE_WORLD:
+		return "World";
+	case BCM43xx_LOCALE_THAILAND:
+		return "Thailand";
+	case BCM43xx_LOCALE_ISRAEL:
+		return "Israel";
+	case BCM43xx_LOCALE_JORDAN:
+		return "Jordan";
+	case BCM43xx_LOCALE_CHINA:
+		return "China";
+	case BCM43xx_LOCALE_JAPAN:
+		return "Japan";
+	case BCM43xx_LOCALE_USA_CANADA_ANZ:
+		return "USA/Canada/ANZ";
+	case BCM43xx_LOCALE_EUROPE:
+		return "Europe";
+	case BCM43xx_LOCALE_USA_LOW:
+		return "USAlow";
+	case BCM43xx_LOCALE_JAPAN_HIGH:
+		return "JapanHigh";
+	case BCM43xx_LOCALE_ALL:
+		return "All";
+	case BCM43xx_LOCALE_NONE:
+		return "None";
+	}
+	assert(0);
+	return "";
+}
+
+static inline u8 bcm43xx_crc8(u8 crc, u8 data)
+{
+	static const u8 t[] = {
+		0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
+		0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
+		0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
+		0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
+		0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
+		0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
+		0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
+		0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
+		0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
+		0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
+		0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
+		0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
+		0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
+		0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
+		0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
+		0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
+		0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
+		0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
+		0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
+		0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
+		0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
+		0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
+		0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
+		0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
+		0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
+		0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
+		0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
+		0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
+		0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
+		0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
+		0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
+		0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
+	};
+	return t[crc ^ data];
+}
+
+static u8 bcm43xx_sprom_crc(const u16 *sprom)
+{
+	int word;
+	u8 crc = 0xFF;
+
+	for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) {
+		crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF);
+		crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8);
+	}
+	crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF);
+	crc ^= 0xFF;
+
+	return crc;
+}
+
+int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom)
+{
+	int i;
+	u8 crc, expected_crc;
+
+	for (i = 0; i < BCM43xx_SPROM_SIZE; i++)
+		sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));
+	/* CRC-8 check. */
+	crc = bcm43xx_sprom_crc(sprom);
+	expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
+	if (crc != expected_crc) {
+		printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum "
+					"(0x%02X, expected: 0x%02X)\n",
+		       crc, expected_crc);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom)
+{
+	int i, err;
+	u8 crc, expected_crc;
+	u32 spromctl;
+
+	/* CRC-8 validation of the input data. */
+	crc = bcm43xx_sprom_crc(sprom);
+	expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
+	if (crc != expected_crc) {
+		printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n");
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
+	err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl);
+	if (err)
+		goto err_ctlreg;
+	spromctl |= 0x10; /* SPROM WRITE enable. */
+	bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
+	if (err)
+		goto err_ctlreg;
+	/* We must burn lots of CPU cycles here, but that does not
+	 * really matter as one does not write the SPROM every other minute...
+	 */
+	printk(KERN_INFO PFX "[ 0%%");
+	mdelay(500);
+	for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
+		if (i == 16)
+			printk("25%%");
+		else if (i == 32)
+			printk("50%%");
+		else if (i == 48)
+			printk("75%%");
+		else if (i % 2)
+			printk(".");
+		bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);
+		mmiowb();
+		mdelay(20);
+	}
+	spromctl &= ~0x10; /* SPROM WRITE enable. */
+	bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
+	if (err)
+		goto err_ctlreg;
+	mdelay(500);
+	printk("100%% ]\n");
+	printk(KERN_INFO PFX "SPROM written.\n");
+	bcm43xx_controller_restart(bcm, "SPROM update");
+
+	return 0;
+err_ctlreg:
+	printk(KERN_ERR PFX "Could not access SPROM control register.\n");
+	return -ENODEV;
+}
+
+static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
+{
+	u16 value;
+	u16 *sprom;
+#ifdef CONFIG_BCM947XX
+	char *c;
+#endif
+
+	sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
+			GFP_KERNEL);
+	if (!sprom) {
+		printk(KERN_ERR PFX "sprom_extract OOM\n");
+		return -ENOMEM;
+	}
+#ifdef CONFIG_BCM947XX
+	sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
+	sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
+
+	if ((c = nvram_get("il0macaddr")) != NULL)
+		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
+
+	if ((c = nvram_get("et1macaddr")) != NULL)
+		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
+
+	sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
+	sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
+	sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
+
+	sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
+	sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
+	sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
+
+	sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
+#else
+	bcm43xx_sprom_read(bcm, sprom);
+#endif
+
+	/* boardflags2 */
+	value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
+	bcm->sprom.boardflags2 = value;
+
+	/* il0macaddr */
+	value = sprom[BCM43xx_SPROM_IL0MACADDR + 0];
+	*(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);
+	value = sprom[BCM43xx_SPROM_IL0MACADDR + 1];
+	*(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);
+	value = sprom[BCM43xx_SPROM_IL0MACADDR + 2];
+	*(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);
+
+	/* et0macaddr */
+	value = sprom[BCM43xx_SPROM_ET0MACADDR + 0];
+	*(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);
+	value = sprom[BCM43xx_SPROM_ET0MACADDR + 1];
+	*(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);
+	value = sprom[BCM43xx_SPROM_ET0MACADDR + 2];
+	*(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);
+
+	/* et1macaddr */
+	value = sprom[BCM43xx_SPROM_ET1MACADDR + 0];
+	*(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);
+	value = sprom[BCM43xx_SPROM_ET1MACADDR + 1];
+	*(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);
+	value = sprom[BCM43xx_SPROM_ET1MACADDR + 2];
+	*(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value);
+
+	/* ethernet phy settings */
+	value = sprom[BCM43xx_SPROM_ETHPHY];
+	bcm->sprom.et0phyaddr = (value & 0x001F);
+	bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5;
+	bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14;
+	bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15;
+
+	/* boardrev, antennas, locale */
+	value = sprom[BCM43xx_SPROM_BOARDREV];
+	bcm->sprom.boardrev = (value & 0x00FF);
+	bcm->sprom.locale = (value & 0x0F00) >> 8;
+	bcm->sprom.antennas_aphy = (value & 0x3000) >> 12;
+	bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14;
+	if (modparam_locale != -1) {
+		if (modparam_locale >= 0 && modparam_locale <= 11) {
+			bcm->sprom.locale = modparam_locale;
+			printk(KERN_WARNING PFX "Operating with modified "
+						"LocaleCode %u (%s)\n",
+			       bcm->sprom.locale,
+			       bcm43xx_locale_string(bcm->sprom.locale));
+		} else {
+			printk(KERN_WARNING PFX "Module parameter \"locale\" "
+						"invalid value. (0 - 11)\n");
+		}
+	}
+
+	/* pa0b* */
+	value = sprom[BCM43xx_SPROM_PA0B0];
+	bcm->sprom.pa0b0 = value;
+	value = sprom[BCM43xx_SPROM_PA0B1];
+	bcm->sprom.pa0b1 = value;
+	value = sprom[BCM43xx_SPROM_PA0B2];
+	bcm->sprom.pa0b2 = value;
+
+	/* wl0gpio* */
+	value = sprom[BCM43xx_SPROM_WL0GPIO0];
+	if (value == 0x0000)
+		value = 0xFFFF;
+	bcm->sprom.wl0gpio0 = value & 0x00FF;
+	bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8;
+	value = sprom[BCM43xx_SPROM_WL0GPIO2];
+	if (value == 0x0000)
+		value = 0xFFFF;
+	bcm->sprom.wl0gpio2 = value & 0x00FF;
+	bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8;
+
+	/* maxpower */
+	value = sprom[BCM43xx_SPROM_MAXPWR];
+	bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8;
+	bcm->sprom.maxpower_bgphy = value & 0x00FF;
+
+	/* pa1b* */
+	value = sprom[BCM43xx_SPROM_PA1B0];
+	bcm->sprom.pa1b0 = value;
+	value = sprom[BCM43xx_SPROM_PA1B1];
+	bcm->sprom.pa1b1 = value;
+	value = sprom[BCM43xx_SPROM_PA1B2];
+	bcm->sprom.pa1b2 = value;
+
+	/* idle tssi target */
+	value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT];
+	bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF;
+	bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8;
+
+	/* boardflags */
+	value = sprom[BCM43xx_SPROM_BOARDFLAGS];
+	if (value == 0xFFFF)
+		value = 0x0000;
+	bcm->sprom.boardflags = value;
+	/* boardflags workarounds */
+	if (bcm->board_vendor == PCI_VENDOR_ID_DELL &&
+	    bcm->chip_id == 0x4301 &&
+	    bcm->board_revision == 0x74)
+		bcm->sprom.boardflags |= BCM43xx_BFL_BTCOEXIST;
+	if (bcm->board_vendor == PCI_VENDOR_ID_APPLE &&
+	    bcm->board_type == 0x4E &&
+	    bcm->board_revision > 0x40)
+		bcm->sprom.boardflags |= BCM43xx_BFL_PACTRL;
+
+	/* antenna gain */
+	value = sprom[BCM43xx_SPROM_ANTENNA_GAIN];
+	if (value == 0x0000 || value == 0xFFFF)
+		value = 0x0202;
+	/* convert values to Q5.2 */
+	bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4;
+	bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4;
+
+	kfree(sprom);
+
+	return 0;
+}
+
+static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
+{
+	struct ieee80211_geo geo;
+	struct ieee80211_channel *chan;
+	int have_a = 0, have_bg = 0;
+	int i;
+	u8 channel;
+	struct bcm43xx_phyinfo *phy;
+	const char *iso_country;
+
+	memset(&geo, 0, sizeof(geo));
+	for (i = 0; i < bcm->nr_80211_available; i++) {
+		phy = &(bcm->core_80211_ext[i].phy);
+		switch (phy->type) {
+		case BCM43xx_PHYTYPE_B:
+		case BCM43xx_PHYTYPE_G:
+			have_bg = 1;
+			break;
+		case BCM43xx_PHYTYPE_A:
+			have_a = 1;
+			break;
+		default:
+			assert(0);
+		}
+	}
+	iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
+
+ 	if (have_a) {
+		for (i = 0, channel = 0; channel < 201; channel++) {
+			chan = &geo.a[i++];
+			chan->freq = bcm43xx_channel_to_freq_a(channel);
+			chan->channel = channel;
+		}
+		geo.a_channels = i;
+	}
+	if (have_bg) {
+		for (i = 0, channel = 1; channel < 15; channel++) {
+			chan = &geo.bg[i++];
+			chan->freq = bcm43xx_channel_to_freq_bg(channel);
+			chan->channel = channel;
+		}
+		geo.bg_channels = i;
+	}
+	memcpy(geo.name, iso_country, 2);
+	if (0 /*TODO: Outdoor use only */)
+		geo.name[2] = 'O';
+	else if (0 /*TODO: Indoor use only */)
+		geo.name[2] = 'I';
+	else
+		geo.name[2] = ' ';
+	geo.name[3] = '\0';
+
+	ieee80211_set_geo(bcm->ieee, &geo);
+}
+
+/* DummyTransmission function, as documented on 
+ * http://bcm-specs.sipsolutions.net/DummyTransmission
+ */
+void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	unsigned int i, max_loop;
+	u16 value = 0;
+	u32 buffer[5] = {
+		0x00000000,
+		0x0000D400,
+		0x00000000,
+		0x00000001,
+		0x00000000,
+	};
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+		max_loop = 0x1E;
+		buffer[0] = 0xCC010200;
+		break;
+	case BCM43xx_PHYTYPE_B:
+	case BCM43xx_PHYTYPE_G:
+		max_loop = 0xFA;
+		buffer[0] = 0x6E840B00; 
+		break;
+	default:
+		assert(0);
+		return;
+	}
+
+	for (i = 0; i < 5; i++)
+		bcm43xx_ram_write(bcm, i * 4, buffer[i]);
+
+	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+
+	bcm43xx_write16(bcm, 0x0568, 0x0000);
+	bcm43xx_write16(bcm, 0x07C0, 0x0000);
+	bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0));
+	bcm43xx_write16(bcm, 0x0508, 0x0000);
+	bcm43xx_write16(bcm, 0x050A, 0x0000);
+	bcm43xx_write16(bcm, 0x054C, 0x0000);
+	bcm43xx_write16(bcm, 0x056A, 0x0014);
+	bcm43xx_write16(bcm, 0x0568, 0x0826);
+	bcm43xx_write16(bcm, 0x0500, 0x0000);
+	bcm43xx_write16(bcm, 0x0502, 0x0030);
+
+	if (radio->version == 0x2050 && radio->revision <= 0x5)
+		bcm43xx_radio_write16(bcm, 0x0051, 0x0017);
+	for (i = 0x00; i < max_loop; i++) {
+		value = bcm43xx_read16(bcm, 0x050E);
+		if (value & 0x0080)
+			break;
+		udelay(10);
+	}
+	for (i = 0x00; i < 0x0A; i++) {
+		value = bcm43xx_read16(bcm, 0x050E);
+		if (value & 0x0400)
+			break;
+		udelay(10);
+	}
+	for (i = 0x00; i < 0x0A; i++) {
+		value = bcm43xx_read16(bcm, 0x0690);
+		if (!(value & 0x0100))
+			break;
+		udelay(10);
+	}
+	if (radio->version == 0x2050 && radio->revision <= 0x5)
+		bcm43xx_radio_write16(bcm, 0x0051, 0x0037);
+}
+
+static void key_write(struct bcm43xx_private *bcm,
+		      u8 index, u8 algorithm, const u16 *key)
+{
+	unsigned int i, basic_wep = 0;
+	u32 offset;
+	u16 value;
+ 
+	/* Write associated key information */
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2),
+			    ((index << 4) | (algorithm & 0x0F)));
+ 
+	/* The first 4 WEP keys need extra love */
+	if (((algorithm == BCM43xx_SEC_ALGO_WEP) ||
+	    (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4))
+		basic_wep = 1;
+ 
+	/* Write key payload, 8 little endian words */
+	offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE);
+	for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) {
+		value = cpu_to_le16(key[i]);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
+				    offset + (i * 2), value);
+ 
+		if (!basic_wep)
+			continue;
+ 
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
+				    offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE,
+				    value);
+	}
+}
+
+static void keymac_write(struct bcm43xx_private *bcm,
+			 u8 index, const u32 *addr)
+{
+	/* for keys 0-3 there is no associated mac address */
+	if (index < 4)
+		return;
+
+	index -= 4;
+	if (bcm->current_core->rev >= 5) {
+		bcm43xx_shm_write32(bcm,
+				    BCM43xx_SHM_HWMAC,
+				    index * 2,
+				    cpu_to_be32(*addr));
+		bcm43xx_shm_write16(bcm,
+				    BCM43xx_SHM_HWMAC,
+				    (index * 2) + 1,
+				    cpu_to_be16(*((u16 *)(addr + 1))));
+	} else {
+		if (index < 8) {
+			TODO(); /* Put them in the macaddress filter */
+		} else {
+			TODO();
+			/* Put them BCM43xx_SHM_SHARED, stating index 0x0120.
+			   Keep in mind to update the count of keymacs in 0x003E as well! */
+		}
+	}
+}
+
+static int bcm43xx_key_write(struct bcm43xx_private *bcm,
+			     u8 index, u8 algorithm,
+			     const u8 *_key, int key_len,
+			     const u8 *mac_addr)
+{
+	u8 key[BCM43xx_SEC_KEYSIZE] = { 0 };
+
+	if (index >= ARRAY_SIZE(bcm->key))
+		return -EINVAL;
+	if (key_len > ARRAY_SIZE(key))
+		return -EINVAL;
+	if (algorithm < 1 || algorithm > 5)
+		return -EINVAL;
+
+	memcpy(key, _key, key_len);
+	key_write(bcm, index, algorithm, (const u16 *)key);
+	keymac_write(bcm, index, (const u32 *)mac_addr);
+
+	bcm->key[index].algorithm = algorithm;
+
+	return 0;
+}
+
+static void bcm43xx_clear_keys(struct bcm43xx_private *bcm)
+{
+	static const u32 zero_mac[2] = { 0 };
+	unsigned int i,j, nr_keys = 54;
+	u16 offset;
+
+	if (bcm->current_core->rev < 5)
+		nr_keys = 16;
+	assert(nr_keys <= ARRAY_SIZE(bcm->key));
+
+	for (i = 0; i < nr_keys; i++) {
+		bcm->key[i].enabled = 0;
+		/* returns for i < 4 immediately */
+		keymac_write(bcm, i, zero_mac);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
+				    0x100 + (i * 2), 0x0000);
+		for (j = 0; j < 8; j++) {
+			offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE);
+			bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
+					    offset, 0x0000);
+		}
+	}
+	dprintk(KERN_INFO PFX "Keys cleared\n");
+}
+
+/* Lowlevel core-switch function. This is only to be used in
+ * bcm43xx_switch_core() and bcm43xx_probe_cores()
+ */
+static int _switch_core(struct bcm43xx_private *bcm, int core)
+{
+	int err;
+	int attempts = 0;
+	u32 current_core;
+
+	assert(core >= 0);
+	while (1) {
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
+						 (core * 0x1000) + 0x18000000);
+		if (unlikely(err))
+			goto error;
+		err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
+						&current_core);
+		if (unlikely(err))
+			goto error;
+		current_core = (current_core - 0x18000000) / 0x1000;
+		if (current_core == core)
+			break;
+
+		if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES))
+			goto error;
+		udelay(10);
+	}
+#ifdef CONFIG_BCM947XX
+	if (bcm->pci_dev->bus->number == 0)
+		bcm->current_core_offset = 0x1000 * core;
+	else
+		bcm->current_core_offset = 0;
+#endif
+
+	return 0;
+error:
+	printk(KERN_ERR PFX "Failed to switch to core %d\n", core);
+	return -ENODEV;
+}
+
+int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core)
+{
+	int err;
+
+	if (unlikely(!new_core))
+		return 0;
+	if (!new_core->available)
+		return -ENODEV;
+	if (bcm->current_core == new_core)
+		return 0;
+	err = _switch_core(bcm, new_core->index);
+	if (unlikely(err))
+		goto out;
+
+	bcm->current_core = new_core;
+	bcm->current_80211_core_idx = -1;
+	if (new_core->id == BCM43xx_COREID_80211)
+		bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0]));
+
+out:
+	return err;
+}
+
+static int bcm43xx_core_enabled(struct bcm43xx_private *bcm)
+{
+	u32 value;
+
+	value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+	value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET
+		 | BCM43xx_SBTMSTATELOW_REJECT;
+
+	return (value == BCM43xx_SBTMSTATELOW_CLOCK);
+}
+
+/* disable current core */
+static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags)
+{
+	u32 sbtmstatelow;
+	u32 sbtmstatehigh;
+	int i;
+
+	/* fetch sbtmstatelow from core information registers */
+	sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+
+	/* core is already in reset */
+	if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET)
+		goto out;
+
+	if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) {
+		sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
+			       BCM43xx_SBTMSTATELOW_REJECT;
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+
+		for (i = 0; i < 1000; i++) {
+			sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+			if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) {
+				i = -1;
+				break;
+			}
+			udelay(10);
+		}
+		if (i != -1) {
+			printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n");
+			return -EBUSY;
+		}
+
+		for (i = 0; i < 1000; i++) {
+			sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
+			if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) {
+				i = -1;
+				break;
+			}
+			udelay(10);
+		}
+		if (i != -1) {
+			printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n");
+			return -EBUSY;
+		}
+
+		sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
+			       BCM43xx_SBTMSTATELOW_REJECT |
+			       BCM43xx_SBTMSTATELOW_RESET |
+			       BCM43xx_SBTMSTATELOW_CLOCK |
+			       core_flags;
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+		udelay(10);
+	}
+
+	sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET |
+		       BCM43xx_SBTMSTATELOW_REJECT |
+		       core_flags;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+
+out:
+	bcm->current_core->enabled = 0;
+
+	return 0;
+}
+
+/* enable (reset) current core */
+static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags)
+{
+	u32 sbtmstatelow;
+	u32 sbtmstatehigh;
+	u32 sbimstate;
+	int err;
+
+	err = bcm43xx_core_disable(bcm, core_flags);
+	if (err)
+		goto out;
+
+	sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
+		       BCM43xx_SBTMSTATELOW_RESET |
+		       BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
+		       core_flags;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+	udelay(1);
+
+	sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
+	if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) {
+		sbtmstatehigh = 0x00000000;
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh);
+	}
+
+	sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE);
+	if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) {
+		sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT);
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate);
+	}
+
+	sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
+		       BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
+		       core_flags;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+	udelay(1);
+
+	sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+	udelay(1);
+
+	bcm->current_core->enabled = 1;
+	assert(err == 0);
+out:
+	return err;
+}
+
+/* http://bcm-specs.sipsolutions.net/80211CoreReset */
+void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
+{
+	u32 flags = 0x00040000;
+
+	if ((bcm43xx_core_enabled(bcm)) &&
+	    !bcm43xx_using_pio(bcm)) {
+//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
+#ifndef CONFIG_BCM947XX
+		/* reset all used DMA controllers. */
+		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
+		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
+		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
+		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
+		bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
+		if (bcm->current_core->rev < 5)
+			bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
+#endif
+	}
+	if (bcm->shutting_down) {
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+		                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+				& ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
+	} else {
+		if (connect_phy)
+			flags |= 0x20000000;
+		bcm43xx_phy_connect(bcm, connect_phy);
+		bcm43xx_core_enable(bcm, flags);
+		bcm43xx_write16(bcm, 0x03E6, 0x0000);
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+				bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+				| BCM43xx_SBF_400);
+	}
+}
+
+static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
+{
+	bcm43xx_radio_turn_off(bcm);
+	bcm43xx_write16(bcm, 0x03E6, 0x00F4);
+	bcm43xx_core_disable(bcm, 0);
+}
+
+/* Mark the current 80211 core inactive.
+ * "active_80211_core" is the other 80211 core, which is used.
+ */
+static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
+					       struct bcm43xx_coreinfo *active_80211_core)
+{
+	u32 sbtmstatelow;
+	struct bcm43xx_coreinfo *old_core;
+	int err = 0;
+
+	bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+	bcm43xx_radio_turn_off(bcm);
+	sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+	sbtmstatelow &= ~0x200a0000;
+	sbtmstatelow |= 0xa0000;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+	udelay(1);
+	sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+	sbtmstatelow &= ~0xa0000;
+	sbtmstatelow |= 0x80000;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+	udelay(1);
+
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) {
+		old_core = bcm->current_core;
+		err = bcm43xx_switch_core(bcm, active_80211_core);
+		if (err)
+			goto out;
+		sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+		sbtmstatelow &= ~0x20000000;
+		sbtmstatelow |= 0x20000000;
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+		err = bcm43xx_switch_core(bcm, old_core);
+	}
+
+out:
+	return err;
+}
+
+static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
+{
+	u32 v0, v1;
+	u16 tmp;
+	struct bcm43xx_xmitstatus stat;
+
+	while (1) {
+		v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);
+		if (!v0)
+			break;
+		v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);
+
+		stat.cookie = (v0 >> 16) & 0x0000FFFF;
+		tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1));
+		stat.flags = tmp & 0xFF;
+		stat.cnt1 = (tmp & 0x0F00) >> 8;
+		stat.cnt2 = (tmp & 0xF000) >> 12;
+		stat.seq = (u16)(v1 & 0xFFFF);
+		stat.unknown = (u16)((v1 >> 16) & 0xFF);
+
+		bcm43xx_debugfs_log_txstat(bcm, &stat);
+
+		if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE)
+			continue;
+		if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) {
+			//TODO: packet was not acked (was lost)
+		}
+		//TODO: There are more (unknown) flags to test. see bcm43xx_main.h
+
+		if (bcm43xx_using_pio(bcm))
+			bcm43xx_pio_handle_xmitstatus(bcm, &stat);
+		else
+			bcm43xx_dma_handle_xmitstatus(bcm, &stat);
+	}
+}
+
+static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm)
+{
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
+			bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4));
+	assert(bcm->noisecalc.core_at_start == bcm->current_core);
+	assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel);
+}
+
+static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm)
+{
+	/* Top half of Link Quality calculation. */
+
+	if (bcm->noisecalc.calculation_running)
+		return;
+	bcm->noisecalc.core_at_start = bcm->current_core;
+	bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel;
+	bcm->noisecalc.calculation_running = 1;
+	bcm->noisecalc.nr_samples = 0;
+
+	bcm43xx_generate_noise_sample(bcm);
+}
+
+static void handle_irq_noise(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 tmp;
+	u8 noise[4];
+	u8 i, j;
+	s32 average;
+
+	/* Bottom half of Link Quality calculation. */
+
+	assert(bcm->noisecalc.calculation_running);
+	if (bcm->noisecalc.core_at_start != bcm->current_core ||
+	    bcm->noisecalc.channel_at_start != radio->channel)
+		goto drop_calculation;
+	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408);
+	noise[0] = (tmp & 0x00FF);
+	noise[1] = (tmp & 0xFF00) >> 8;
+	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A);
+	noise[2] = (tmp & 0x00FF);
+	noise[3] = (tmp & 0xFF00) >> 8;
+	if (noise[0] == 0x7F || noise[1] == 0x7F ||
+	    noise[2] == 0x7F || noise[3] == 0x7F)
+		goto generate_new;
+
+	/* Get the noise samples. */
+	assert(bcm->noisecalc.nr_samples <= 8);
+	i = bcm->noisecalc.nr_samples;
+	noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
+	noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
+	noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
+	noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
+	bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]];
+	bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]];
+	bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]];
+	bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]];
+	bcm->noisecalc.nr_samples++;
+	if (bcm->noisecalc.nr_samples == 8) {
+		/* Calculate the Link Quality by the noise samples. */
+		average = 0;
+		for (i = 0; i < 8; i++) {
+			for (j = 0; j < 4; j++)
+				average += bcm->noisecalc.samples[i][j];
+		}
+		average /= (8 * 4);
+		average *= 125;
+		average += 64;
+		average /= 128;
+
+		tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C);
+		tmp = (tmp / 128) & 0x1F;
+		if (tmp >= 8)
+			average += 2;
+		else
+			average -= 25;
+		if (tmp == 8)
+			average -= 72;
+		else
+			average -= 48;
+
+/* FIXME: This is wrong, but people want fancy stats. well... */
+bcm->stats.noise = average;
+		if (average > -65)
+			bcm->stats.link_quality = 0;
+		else if (average > -75)
+			bcm->stats.link_quality = 1;
+		else if (average > -85)
+			bcm->stats.link_quality = 2;
+		else
+			bcm->stats.link_quality = 3;
+//		dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
+drop_calculation:
+		bcm->noisecalc.calculation_running = 0;
+		return;
+	}
+generate_new:
+	bcm43xx_generate_noise_sample(bcm);
+}
+
+static void handle_irq_ps(struct bcm43xx_private *bcm)
+{
+	if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
+		///TODO: PS TBTT
+	} else {
+		if (1/*FIXME: the last PSpoll frame was sent successfully */)
+			bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+	}
+	if (bcm->ieee->iw_mode == IW_MODE_ADHOC)
+		bcm->reg124_set_0x4 = 1;
+	//FIXME else set to false?
+}
+
+static void handle_irq_reg124(struct bcm43xx_private *bcm)
+{
+	if (!bcm->reg124_set_0x4)
+		return;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
+			bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD)
+			| 0x4);
+	//FIXME: reset reg124_set_0x4 to false?
+}
+
+static void handle_irq_pmq(struct bcm43xx_private *bcm)
+{
+	u32 tmp;
+
+	//TODO: AP mode.
+
+	while (1) {
+		tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS);
+		if (!(tmp & 0x00000008))
+			break;
+	}
+	/* 16bit write is odd, but correct. */
+	bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002);
+}
+
+static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm,
+					     u16 ram_offset, u16 shm_size_offset)
+{
+	u32 value;
+	u16 size = 0;
+
+	/* Timestamp. */
+	//FIXME: assumption: The chip sets the timestamp
+	value = 0;
+	bcm43xx_ram_write(bcm, ram_offset++, value);
+	bcm43xx_ram_write(bcm, ram_offset++, value);
+	size += 8;
+
+	/* Beacon Interval / Capability Information */
+	value = 0x0000;//FIXME: Which interval?
+	value |= (1 << 0) << 16; /* ESS */
+	value |= (1 << 2) << 16; /* CF Pollable */	//FIXME?
+	value |= (1 << 3) << 16; /* CF Poll Request */	//FIXME?
+	if (!bcm->ieee->open_wep)
+		value |= (1 << 4) << 16; /* Privacy */
+	bcm43xx_ram_write(bcm, ram_offset++, value);
+	size += 4;
+
+	/* SSID */
+	//TODO
+
+	/* FH Parameter Set */
+	//TODO
+
+	/* DS Parameter Set */
+	//TODO
+
+	/* CF Parameter Set */
+	//TODO
+
+	/* TIM */
+	//TODO
+
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size);
+}
+
+static void handle_irq_beacon(struct bcm43xx_private *bcm)
+{
+	u32 status;
+
+	bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON;
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);
+
+	if ((status & 0x1) && (status & 0x2)) {
+		/* ACK beacon IRQ. */
+		bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
+				BCM43xx_IRQ_BEACON);
+		bcm->irq_savedstate |= BCM43xx_IRQ_BEACON;
+		return;
+	}
+	if (!(status & 0x1)) {
+		bcm43xx_generate_beacon_template(bcm, 0x68, 0x18);
+		status |= 0x1;
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
+	}
+	if (!(status & 0x2)) {
+		bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A);
+		status |= 0x2;
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
+	}
+}
+
+/* Interrupt handler bottom-half */
+static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
+{
+	u32 reason;
+	u32 dma_reason[4];
+	int activity = 0;
+	unsigned long flags;
+
+#ifdef CONFIG_BCM43XX_DEBUG
+	u32 _handled = 0x00000000;
+# define bcmirq_handled(irq)	do { _handled |= (irq); } while (0)
+#else
+# define bcmirq_handled(irq)	do { /* nothing */ } while (0)
+#endif /* CONFIG_BCM43XX_DEBUG*/
+
+	bcm43xx_lock_mmio(bcm, flags);
+	reason = bcm->irq_reason;
+	dma_reason[0] = bcm->dma_reason[0];
+	dma_reason[1] = bcm->dma_reason[1];
+	dma_reason[2] = bcm->dma_reason[2];
+	dma_reason[3] = bcm->dma_reason[3];
+
+	if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
+		/* TX error. We get this when Template Ram is written in wrong endianess
+		 * in dummy_tx(). We also get this if something is wrong with the TX header
+		 * on DMA or PIO queues.
+		 * Maybe we get this in other error conditions, too.
+		 */
+		printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n");
+		bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
+	}
+	if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) |
+		     (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) |
+		     (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) |
+		     (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) {
+		printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: "
+				     "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
+		        dma_reason[0], dma_reason[1],
+			dma_reason[2], dma_reason[3]);
+		bcm43xx_controller_restart(bcm, "DMA error");
+		bcm43xx_unlock_mmio(bcm, flags);
+		return;
+	}
+	if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
+		     (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) |
+		     (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) |
+		     (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) {
+		printkl(KERN_ERR PFX "DMA error: "
+				     "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
+		        dma_reason[0], dma_reason[1],
+			dma_reason[2], dma_reason[3]);
+	}
+
+	if (reason & BCM43xx_IRQ_PS) {
+		handle_irq_ps(bcm);
+		bcmirq_handled(BCM43xx_IRQ_PS);
+	}
+
+	if (reason & BCM43xx_IRQ_REG124) {
+		handle_irq_reg124(bcm);
+		bcmirq_handled(BCM43xx_IRQ_REG124);
+	}
+
+	if (reason & BCM43xx_IRQ_BEACON) {
+		if (bcm->ieee->iw_mode == IW_MODE_MASTER)
+			handle_irq_beacon(bcm);
+		bcmirq_handled(BCM43xx_IRQ_BEACON);
+	}
+
+	if (reason & BCM43xx_IRQ_PMQ) {
+		handle_irq_pmq(bcm);
+		bcmirq_handled(BCM43xx_IRQ_PMQ);
+	}
+
+	if (reason & BCM43xx_IRQ_SCAN) {
+		/*TODO*/
+		//bcmirq_handled(BCM43xx_IRQ_SCAN);
+	}
+
+	if (reason & BCM43xx_IRQ_NOISE) {
+		handle_irq_noise(bcm);
+		bcmirq_handled(BCM43xx_IRQ_NOISE);
+	}
+
+	/* Check the DMA reason registers for received data. */
+	assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
+	assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
+	if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
+		if (bcm43xx_using_pio(bcm))
+			bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0);
+		else
+			bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0);
+		/* We intentionally don't set "activity" to 1, here. */
+	}
+	if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
+		if (bcm43xx_using_pio(bcm))
+			bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3);
+		else
+			bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1);
+		activity = 1;
+	}
+	bcmirq_handled(BCM43xx_IRQ_RX);
+
+	if (reason & BCM43xx_IRQ_XMIT_STATUS) {
+		handle_irq_transmit_status(bcm);
+		activity = 1;
+		//TODO: In AP mode, this also causes sending of powersave responses.
+		bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS);
+	}
+
+	/* IRQ_PIO_WORKAROUND is handled in the top-half. */
+	bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND);
+#ifdef CONFIG_BCM43XX_DEBUG
+	if (unlikely(reason & ~_handled)) {
+		printkl(KERN_WARNING PFX
+			"Unhandled IRQ! Reason: 0x%08x,  Unhandled: 0x%08x,  "
+			"DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+			reason, (reason & ~_handled),
+			dma_reason[0], dma_reason[1],
+			dma_reason[2], dma_reason[3]);
+	}
+#endif
+#undef bcmirq_handled
+
+	if (!modparam_noleds)
+		bcm43xx_leds_update(bcm, activity);
+	bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+static void pio_irq_workaround(struct bcm43xx_private *bcm,
+			       u16 base, int queueidx)
+{
+	u16 rxctl;
+
+	rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL);
+	if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE)
+		bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE;
+	else
+		bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE;
+}
+
+static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason)
+{
+	if (bcm43xx_using_pio(bcm) &&
+	    (bcm->current_core->rev < 3) &&
+	    (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) {
+		/* Apply a PIO specific workaround to the dma_reasons */
+		pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0);
+		pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1);
+		pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2);
+		pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3);
+	}
+
+	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason);
+
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
+			bcm->dma_reason[0]);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
+			bcm->dma_reason[1]);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
+			bcm->dma_reason[2]);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
+			bcm->dma_reason[3]);
+}
+
+/* Interrupt handler top-half */
+static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	irqreturn_t ret = IRQ_HANDLED;
+	struct bcm43xx_private *bcm = dev_id;
+	u32 reason;
+
+	if (!bcm)
+		return IRQ_NONE;
+
+	spin_lock(&bcm->_lock);
+
+	reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+	if (reason == 0xffffffff) {
+		/* irq not for us (shared irq) */
+		ret = IRQ_NONE;
+		goto out;
+	}
+	reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
+	if (!reason)
+		goto out;
+
+	bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
+			     & 0x0001dc00;
+	bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
+			     & 0x0000dc00;
+	bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
+			     & 0x0000dc00;
+	bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
+			     & 0x0001dc00;
+
+	bcm43xx_interrupt_ack(bcm, reason);
+
+	/* Only accept IRQs, if we are initialized properly.
+	 * This avoids an RX race while initializing.
+	 * We should probably not enable IRQs before we are initialized
+	 * completely, but some careful work is needed to fix this. I think it
+	 * is best to stay with this cheap workaround for now... .
+	 */
+	if (likely(bcm->initialized)) {
+		/* disable all IRQs. They are enabled again in the bottom half. */
+		bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+		/* save the reason code and call our bottom half. */
+		bcm->irq_reason = reason;
+		tasklet_schedule(&bcm->isr_tasklet);
+	}
+
+out:
+	mmiowb();
+	spin_unlock(&bcm->_lock);
+
+	return ret;
+}
+
+static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
+{
+	if (bcm->firmware_norelease && !force)
+		return; /* Suspending or controller reset. */
+	release_firmware(bcm->ucode);
+	bcm->ucode = NULL;
+	release_firmware(bcm->pcm);
+	bcm->pcm = NULL;
+	release_firmware(bcm->initvals0);
+	bcm->initvals0 = NULL;
+	release_firmware(bcm->initvals1);
+	bcm->initvals1 = NULL;
+}
+
+static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u8 rev = bcm->current_core->rev;
+	int err = 0;
+	int nr;
+	char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
+
+	if (!bcm->ucode) {
+		snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
+			 (rev >= 5 ? 5 : rev),
+			 modparam_fwpostfix);
+		err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
+		if (err) {
+			printk(KERN_ERR PFX 
+			       "Error: Microcode \"%s\" not available or load failed.\n",
+			        buf);
+			goto error;
+		}
+	}
+
+	if (!bcm->pcm) {
+		snprintf(buf, ARRAY_SIZE(buf),
+			 "bcm43xx_pcm%d%s.fw",
+			 (rev < 5 ? 4 : 5),
+			 modparam_fwpostfix);
+		err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
+		if (err) {
+			printk(KERN_ERR PFX
+			       "Error: PCM \"%s\" not available or load failed.\n",
+			       buf);
+			goto error;
+		}
+	}
+
+	if (!bcm->initvals0) {
+		if (rev == 2 || rev == 4) {
+			switch (phy->type) {
+			case BCM43xx_PHYTYPE_A:
+				nr = 3;
+				break;
+			case BCM43xx_PHYTYPE_B:
+			case BCM43xx_PHYTYPE_G:
+				nr = 1;
+				break;
+			default:
+				goto err_noinitval;
+			}
+		
+		} else if (rev >= 5) {
+			switch (phy->type) {
+			case BCM43xx_PHYTYPE_A:
+				nr = 7;
+				break;
+			case BCM43xx_PHYTYPE_B:
+			case BCM43xx_PHYTYPE_G:
+				nr = 5;
+				break;
+			default:
+				goto err_noinitval;
+			}
+		} else
+			goto err_noinitval;
+		snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
+			 nr, modparam_fwpostfix);
+
+		err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
+		if (err) {
+			printk(KERN_ERR PFX 
+			       "Error: InitVals \"%s\" not available or load failed.\n",
+			        buf);
+			goto error;
+		}
+		if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
+			printk(KERN_ERR PFX "InitVals fileformat error.\n");
+			goto error;
+		}
+	}
+
+	if (!bcm->initvals1) {
+		if (rev >= 5) {
+			u32 sbtmstatehigh;
+
+			switch (phy->type) {
+			case BCM43xx_PHYTYPE_A:
+				sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
+				if (sbtmstatehigh & 0x00010000)
+					nr = 9;
+				else
+					nr = 10;
+				break;
+			case BCM43xx_PHYTYPE_B:
+			case BCM43xx_PHYTYPE_G:
+					nr = 6;
+				break;
+			default:
+				goto err_noinitval;
+			}
+			snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
+				 nr, modparam_fwpostfix);
+
+			err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
+			if (err) {
+				printk(KERN_ERR PFX 
+				       "Error: InitVals \"%s\" not available or load failed.\n",
+			        	buf);
+				goto error;
+			}
+			if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
+				printk(KERN_ERR PFX "InitVals fileformat error.\n");
+				goto error;
+			}
+		}
+	}
+
+out:
+	return err;
+error:
+	bcm43xx_release_firmware(bcm, 1);
+	goto out;
+err_noinitval:
+	printk(KERN_ERR PFX "Error: No InitVals available!\n");
+	err = -ENOENT;
+	goto error;
+}
+
+static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
+{
+	const u32 *data;
+	unsigned int i, len;
+
+	/* Upload Microcode. */
+	data = (u32 *)(bcm->ucode->data);
+	len = bcm->ucode->size / sizeof(u32);
+	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
+	for (i = 0; i < len; i++) {
+		bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
+				be32_to_cpu(data[i]));
+		udelay(10);
+	}
+
+	/* Upload PCM data. */
+	data = (u32 *)(bcm->pcm->data);
+	len = bcm->pcm->size / sizeof(u32);
+	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
+	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
+	for (i = 0; i < len; i++) {
+		bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
+				be32_to_cpu(data[i]));
+		udelay(10);
+	}
+}
+
+static int bcm43xx_write_initvals(struct bcm43xx_private *bcm,
+				  const struct bcm43xx_initval *data,
+				  const unsigned int len)
+{
+	u16 offset, size;
+	u32 value;
+	unsigned int i;
+
+	for (i = 0; i < len; i++) {
+		offset = be16_to_cpu(data[i].offset);
+		size = be16_to_cpu(data[i].size);
+		value = be32_to_cpu(data[i].value);
+
+		if (unlikely(offset >= 0x1000))
+			goto err_format;
+		if (size == 2) {
+			if (unlikely(value & 0xFFFF0000))
+				goto err_format;
+			bcm43xx_write16(bcm, offset, (u16)value);
+		} else if (size == 4) {
+			bcm43xx_write32(bcm, offset, value);
+		} else
+			goto err_format;
+	}
+
+	return 0;
+
+err_format:
+	printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. "
+			    "Please fix your bcm43xx firmware files.\n");
+	return -EPROTO;
+}
+
+static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
+{
+	int err;
+
+	err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
+				     bcm->initvals0->size / sizeof(struct bcm43xx_initval));
+	if (err)
+		goto out;
+	if (bcm->initvals1) {
+		err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
+					     bcm->initvals1->size / sizeof(struct bcm43xx_initval));
+		if (err)
+			goto out;
+	}
+out:
+	return err;
+}
+
+static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
+{
+	int res;
+	unsigned int i;
+	u32 data;
+
+	bcm->irq = bcm->pci_dev->irq;
+#ifdef CONFIG_BCM947XX
+	if (bcm->pci_dev->bus->number == 0) {
+		struct pci_dev *d = NULL;
+		/* FIXME: we will probably need more device IDs here... */
+		d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
+		if (d != NULL) {
+			bcm->irq = d->irq;
+		}
+	}
+#endif
+	res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
+			  SA_SHIRQ, KBUILD_MODNAME, bcm);
+	if (res) {
+		printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
+		return -ENODEV;
+	}
+	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
+	i = 0;
+	while (1) {
+		data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+		if (data == BCM43xx_IRQ_READY)
+			break;
+		i++;
+		if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
+			printk(KERN_ERR PFX "Card IRQ register not responding. "
+					    "Giving up.\n");
+			free_irq(bcm->irq, bcm);
+			return -ENODEV;
+		}
+		udelay(10);
+	}
+	// dummy read
+	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+
+	return 0;
+}
+
+/* Switch to the core used to write the GPIO register.
+ * This is either the ChipCommon, or the PCI core.
+ */
+static int switch_to_gpio_core(struct bcm43xx_private *bcm)
+{
+	int err;
+
+	/* Where to find the GPIO register depends on the chipset.
+	 * If it has a ChipCommon, its register at offset 0x6c is the GPIO
+	 * control register. Otherwise the register at offset 0x6c in the
+	 * PCI core is the GPIO control register.
+	 */
+	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+	if (err == -ENODEV) {
+		err = bcm43xx_switch_core(bcm, &bcm->core_pci);
+		if (unlikely(err == -ENODEV)) {
+			printk(KERN_ERR PFX "gpio error: "
+			       "Neither ChipCommon nor PCI core available!\n");
+		}
+	}
+
+	return err;
+}
+
+/* Initialize the GPIOs
+ * http://bcm-specs.sipsolutions.net/GPIO
+ */
+static int bcm43xx_gpio_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_coreinfo *old_core;
+	int err;
+	u32 mask, set;
+
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+			bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+			& 0xFFFF3FFF);
+
+	bcm43xx_leds_switch_all(bcm, 0);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
+			bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);
+
+	mask = 0x0000001F;
+	set = 0x0000000F;
+	if (bcm->chip_id == 0x4301) {
+		mask |= 0x0060;
+		set |= 0x0060;
+	}
+	if (0 /* FIXME: conditional unknown */) {
+		bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
+				bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
+				| 0x0100);
+		mask |= 0x0180;
+		set |= 0x0180;
+	}
+	if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
+		bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
+				bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
+				| 0x0200);
+		mask |= 0x0200;
+		set |= 0x0200;
+	}
+	if (bcm->current_core->rev >= 2)
+		mask  |= 0x0010; /* FIXME: This is redundant. */
+
+	old_core = bcm->current_core;
+	err = switch_to_gpio_core(bcm);
+	if (err)
+		goto out;
+	bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,
+	                (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | set);
+	err = bcm43xx_switch_core(bcm, old_core);
+out:
+	return err;
+}
+
+/* Turn off all GPIO stuff. Call this on module unload, for example. */
+static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_coreinfo *old_core;
+	int err;
+
+	old_core = bcm->current_core;
+	err = switch_to_gpio_core(bcm);
+	if (err)
+		return err;
+	bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000);
+	err = bcm43xx_switch_core(bcm, old_core);
+	assert(err == 0);
+
+	return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/EnableMac */
+void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
+{
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+	                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+			| BCM43xx_SBF_MAC_ENABLED);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
+	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+	bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+}
+
+/* http://bcm-specs.sipsolutions.net/SuspendMAC */
+void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
+{
+	int i;
+	u32 tmp;
+
+	bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+	                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+			& ~BCM43xx_SBF_MAC_ENABLED);
+	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+	for (i = 100000; i; i--) {
+		tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+		if (tmp & BCM43xx_IRQ_READY)
+			return;
+		udelay(10);
+	}
+	printkl(KERN_ERR PFX "MAC suspend failed\n");
+}
+
+void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
+			int iw_mode)
+{
+	unsigned long flags;
+	struct net_device *net_dev = bcm->net_dev;
+	u32 status;
+	u16 value;
+
+	spin_lock_irqsave(&bcm->ieee->lock, flags);
+	bcm->ieee->iw_mode = iw_mode;
+	spin_unlock_irqrestore(&bcm->ieee->lock, flags);
+	if (iw_mode == IW_MODE_MONITOR)
+		net_dev->type = ARPHRD_IEEE80211;
+	else
+		net_dev->type = ARPHRD_ETHER;
+
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	/* Reset status to infrastructured mode */
+	status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);
+	status &= ~BCM43xx_SBF_MODE_PROMISC;
+	status |= BCM43xx_SBF_MODE_NOTADHOC;
+
+/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */
+status |= BCM43xx_SBF_MODE_PROMISC;
+
+	switch (iw_mode) {
+	case IW_MODE_MONITOR:
+		status |= BCM43xx_SBF_MODE_MONITOR;
+		status |= BCM43xx_SBF_MODE_PROMISC;
+		break;
+	case IW_MODE_ADHOC:
+		status &= ~BCM43xx_SBF_MODE_NOTADHOC;
+		break;
+	case IW_MODE_MASTER:
+		status |= BCM43xx_SBF_MODE_AP;
+		break;
+	case IW_MODE_SECOND:
+	case IW_MODE_REPEAT:
+		TODO(); /* TODO */
+		break;
+	case IW_MODE_INFRA:
+		/* nothing to be done here... */
+		break;
+	default:
+		dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode);
+	}
+	if (net_dev->flags & IFF_PROMISC)
+		status |= BCM43xx_SBF_MODE_PROMISC;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+
+	value = 0x0002;
+	if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {
+		if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3)
+			value = 0x0064;
+		else
+			value = 0x0032;
+	}
+	bcm43xx_write16(bcm, 0x0612, value);
+}
+
+/* This is the opposite of bcm43xx_chip_init() */
+static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
+{
+	bcm43xx_radio_turn_off(bcm);
+	if (!modparam_noleds)
+		bcm43xx_leds_exit(bcm);
+	bcm43xx_gpio_cleanup(bcm);
+	free_irq(bcm->irq, bcm);
+	bcm43xx_release_firmware(bcm, 0);
+}
+
+/* Initialize the chip
+ * http://bcm-specs.sipsolutions.net/ChipInit
+ */
+static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	int err;
+	int tmp;
+	u32 value32;
+	u16 value16;
+
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+			BCM43xx_SBF_CORE_READY
+			| BCM43xx_SBF_400);
+
+	err = bcm43xx_request_firmware(bcm);
+	if (err)
+		goto out;
+	bcm43xx_upload_microcode(bcm);
+
+	err = bcm43xx_initialize_irq(bcm);
+	if (err)
+		goto err_release_fw;
+
+	err = bcm43xx_gpio_init(bcm);
+	if (err)
+		goto err_free_irq;
+
+	err = bcm43xx_upload_initvals(bcm);
+	if (err)
+		goto err_gpio_cleanup;
+	bcm43xx_radio_turn_on(bcm);
+
+	bcm43xx_write16(bcm, 0x03E6, 0x0000);
+	err = bcm43xx_phy_init(bcm);
+	if (err)
+		goto err_radio_off;
+
+	/* Select initial Interference Mitigation. */
+	tmp = radio->interfmode;
+	radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
+	bcm43xx_radio_set_interference_mitigation(bcm, tmp);
+
+	bcm43xx_phy_set_antenna_diversity(bcm);
+	bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT);
+	if (phy->type == BCM43xx_PHYTYPE_B) {
+		value16 = bcm43xx_read16(bcm, 0x005E);
+		value16 |= 0x0004;
+		bcm43xx_write16(bcm, 0x005E, value16);
+	}
+	bcm43xx_write32(bcm, 0x0100, 0x01000000);
+	if (bcm->current_core->rev < 5)
+		bcm43xx_write32(bcm, 0x010C, 0x01000000);
+
+	value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
+	value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	value32 |= BCM43xx_SBF_MODE_NOTADHOC;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
+
+	value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	value32 |= 0x100000;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
+
+	if (bcm43xx_using_pio(bcm)) {
+		bcm43xx_write32(bcm, 0x0210, 0x00000100);
+		bcm43xx_write32(bcm, 0x0230, 0x00000100);
+		bcm43xx_write32(bcm, 0x0250, 0x00000100);
+		bcm43xx_write32(bcm, 0x0270, 0x00000100);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000);
+	}
+
+	/* Probe Response Timeout value */
+	/* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000);
+
+	/* Initially set the wireless operation mode. */
+	bcm43xx_set_iwmode(bcm, bcm->ieee->iw_mode);
+
+	if (bcm->current_core->rev < 3) {
+		bcm43xx_write16(bcm, 0x060E, 0x0000);
+		bcm43xx_write16(bcm, 0x0610, 0x8000);
+		bcm43xx_write16(bcm, 0x0604, 0x0000);
+		bcm43xx_write16(bcm, 0x0606, 0x0200);
+	} else {
+		bcm43xx_write32(bcm, 0x0188, 0x80000000);
+		bcm43xx_write32(bcm, 0x018C, 0x02000000);
+	}
+	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
+
+	value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+	value32 |= 0x00100000;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32);
+
+	bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm));
+
+	assert(err == 0);
+	dprintk(KERN_INFO PFX "Chip initialized\n");
+out:
+	return err;
+
+err_radio_off:
+	bcm43xx_radio_turn_off(bcm);
+err_gpio_cleanup:
+	bcm43xx_gpio_cleanup(bcm);
+err_free_irq:
+	free_irq(bcm->irq, bcm);
+err_release_fw:
+	bcm43xx_release_firmware(bcm, 1);
+	goto out;
+}
+	
+/* Validate chip access
+ * http://bcm-specs.sipsolutions.net/ValidateChipAccess */
+static int bcm43xx_validate_chip(struct bcm43xx_private *bcm)
+{
+	u32 value;
+	u32 shm_backup;
+
+	shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000);
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA);
+	if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA)
+		goto error;
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55);
+	if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55)
+		goto error;
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup);
+
+	value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	if ((value | 0x80000000) != 0x80000400)
+		goto error;
+
+	value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+	if (value != 0x00000000)
+		goto error;
+
+	return 0;
+error:
+	printk(KERN_ERR PFX "Failed to validate the chipaccess\n");
+	return -ENODEV;
+}
+
+static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
+{
+	/* Initialize a "phyinfo" structure. The structure is already
+	 * zeroed out.
+	 */
+	phy->antenna_diversity = 0xFFFF;
+	phy->savedpctlreg = 0xFFFF;
+	phy->minlowsig[0] = 0xFFFF;
+	phy->minlowsig[1] = 0xFFFF;
+	spin_lock_init(&phy->lock);
+}
+
+static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
+{
+	/* Initialize a "radioinfo" structure. The structure is already
+	 * zeroed out.
+	 */
+	radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
+	radio->channel = 0xFF;
+	radio->initial_channel = 0xFF;
+	radio->lofcal = 0xFFFF;
+	radio->initval = 0xFFFF;
+	radio->nrssi[0] = -1000;
+	radio->nrssi[1] = -1000;
+}
+
+static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
+{
+	int err, i;
+	int current_core;
+	u32 core_vendor, core_id, core_rev;
+	u32 sb_id_hi, chip_id_32 = 0;
+	u16 pci_device, chip_id_16;
+	u8 core_count;
+
+	memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo));
+	memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo));
+	memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo)
+				    * BCM43xx_MAX_80211_CORES);
+	memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
+					* BCM43xx_MAX_80211_CORES);
+	bcm->current_80211_core_idx = -1;
+	bcm->nr_80211_available = 0;
+	bcm->current_core = NULL;
+	bcm->active_80211_core = NULL;
+
+	/* map core 0 */
+	err = _switch_core(bcm, 0);
+	if (err)
+		goto out;
+
+	/* fetch sb_id_hi from core information registers */
+	sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
+
+	core_id = (sb_id_hi & 0xFFF0) >> 4;
+	core_rev = (sb_id_hi & 0xF);
+	core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
+
+	/* if present, chipcommon is always core 0; read the chipid from it */
+	if (core_id == BCM43xx_COREID_CHIPCOMMON) {
+		chip_id_32 = bcm43xx_read32(bcm, 0);
+		chip_id_16 = chip_id_32 & 0xFFFF;
+		bcm->core_chipcommon.available = 1;
+		bcm->core_chipcommon.id = core_id;
+		bcm->core_chipcommon.rev = core_rev;
+		bcm->core_chipcommon.index = 0;
+		/* While we are at it, also read the capabilities. */
+		bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES);
+	} else {
+		/* without a chipCommon, use a hard coded table. */
+		pci_device = bcm->pci_dev->device;
+		if (pci_device == 0x4301)
+			chip_id_16 = 0x4301;
+		else if ((pci_device >= 0x4305) && (pci_device <= 0x4307))
+			chip_id_16 = 0x4307;
+		else if ((pci_device >= 0x4402) && (pci_device <= 0x4403))
+			chip_id_16 = 0x4402;
+		else if ((pci_device >= 0x4610) && (pci_device <= 0x4615))
+			chip_id_16 = 0x4610;
+		else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
+			chip_id_16 = 0x4710;
+#ifdef CONFIG_BCM947XX
+		else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
+			chip_id_16 = 0x4309;
+#endif
+		else {
+			printk(KERN_ERR PFX "Could not determine Chip ID\n");
+			return -ENODEV;
+		}
+	}
+
+	/* ChipCommon with Core Rev >=4 encodes number of cores,
+	 * otherwise consult hardcoded table */
+	if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) {
+		core_count = (chip_id_32 & 0x0F000000) >> 24;
+	} else {
+		switch (chip_id_16) {
+			case 0x4610:
+			case 0x4704:
+			case 0x4710:
+				core_count = 9;
+				break;
+			case 0x4310:
+				core_count = 8;
+				break;
+			case 0x5365:
+				core_count = 7;
+				break;
+			case 0x4306:
+				core_count = 6;
+				break;
+			case 0x4301:
+			case 0x4307:
+				core_count = 5;
+				break;
+			case 0x4402:
+				core_count = 3;
+				break;
+			default:
+				/* SOL if we get here */
+				assert(0);
+				core_count = 1;
+		}
+	}
+
+	bcm->chip_id = chip_id_16;
+	bcm->chip_rev = (chip_id_32 & 0x000F0000) >> 16;
+	bcm->chip_package = (chip_id_32 & 0x00F00000) >> 20;
+
+	dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n",
+		bcm->chip_id, bcm->chip_rev);
+	dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count);
+	if (bcm->core_chipcommon.available) {
+		dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
+			core_id, core_rev, core_vendor,
+			bcm43xx_core_enabled(bcm) ? "enabled" : "disabled");
+	}
+
+	if (bcm->core_chipcommon.available)
+		current_core = 1;
+	else
+		current_core = 0;
+	for ( ; current_core < core_count; current_core++) {
+		struct bcm43xx_coreinfo *core;
+		struct bcm43xx_coreinfo_80211 *ext_80211;
+
+		err = _switch_core(bcm, current_core);
+		if (err)
+			goto out;
+		/* Gather information */
+		/* fetch sb_id_hi from core information registers */
+		sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
+
+		/* extract core_id, core_rev, core_vendor */
+		core_id = (sb_id_hi & 0xFFF0) >> 4;
+		core_rev = (sb_id_hi & 0xF);
+		core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
+
+		dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
+			current_core, core_id, core_rev, core_vendor,
+			bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" );
+
+		core = NULL;
+		switch (core_id) {
+		case BCM43xx_COREID_PCI:
+			core = &bcm->core_pci;
+			if (core->available) {
+				printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
+				continue;
+			}
+			break;
+		case BCM43xx_COREID_80211:
+			for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
+				core = &(bcm->core_80211[i]);
+				ext_80211 = &(bcm->core_80211_ext[i]);
+				if (!core->available)
+					break;
+				core = NULL;
+			}
+			if (!core) {
+				printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n",
+				       BCM43xx_MAX_80211_CORES);
+				continue;
+			}
+			if (i != 0) {
+				/* More than one 80211 core is only supported
+				 * by special chips.
+				 * There are chips with two 80211 cores, but with
+				 * dangling pins on the second core. Be careful
+				 * and ignore these cores here.
+				 */
+				if (bcm->pci_dev->device != 0x4324) {
+					dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n");
+					continue;
+				}
+			}
+			switch (core_rev) {
+			case 2:
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+			case 9:
+				break;
+			default:
+				printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n",
+				       core_rev);
+				err = -ENODEV;
+				goto out;
+			}
+			bcm->nr_80211_available++;
+			bcm43xx_init_struct_phyinfo(&ext_80211->phy);
+			bcm43xx_init_struct_radioinfo(&ext_80211->radio);
+			break;
+		case BCM43xx_COREID_CHIPCOMMON:
+			printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n");
+			break;
+		}
+		if (core) {
+			core->available = 1;
+			core->id = core_id;
+			core->rev = core_rev;
+			core->index = current_core;
+		}
+	}
+
+	if (!bcm->core_80211[0].available) {
+		printk(KERN_ERR PFX "Error: No 80211 core found!\n");
+		err = -ENODEV;
+		goto out;
+	}
+
+	err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
+
+	assert(err == 0);
+out:
+	return err;
+}
+
+static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm)
+{
+	const u8 *mac = (const u8*)(bcm->net_dev->dev_addr);
+	u8 *bssid = bcm->ieee->bssid;
+
+	switch (bcm->ieee->iw_mode) {
+	case IW_MODE_ADHOC:
+		random_ether_addr(bssid);
+		break;
+	case IW_MODE_MASTER:
+	case IW_MODE_INFRA:
+	case IW_MODE_REPEAT:
+	case IW_MODE_SECOND:
+	case IW_MODE_MONITOR:
+		memcpy(bssid, mac, ETH_ALEN);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm,
+				      u16 rate,
+				      int is_ofdm)
+{
+	u16 offset;
+
+	if (is_ofdm) {
+		offset = 0x480;
+		offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
+	}
+	else {
+		offset = 0x4C0;
+		offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
+	}
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20,
+			    bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset));
+}
+
+static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm)
+{
+	switch (bcm43xx_current_phy(bcm)->type) {
+	case BCM43xx_PHYTYPE_A:
+	case BCM43xx_PHYTYPE_G:
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1);
+	case BCM43xx_PHYTYPE_B:
+		bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
+{
+	bcm43xx_chip_cleanup(bcm);
+	bcm43xx_pio_free(bcm);
+	bcm43xx_dma_free(bcm);
+
+	bcm->current_core->initialized = 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/80211Init */
+static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u32 ucodeflags;
+	int err;
+	u32 sbimconfiglow;
+	u8 limit;
+
+	if (bcm->chip_rev < 5) {
+		sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
+		sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
+		sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
+		if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
+			sbimconfiglow |= 0x32;
+		else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
+			sbimconfiglow |= 0x53;
+		else
+			assert(0);
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
+	}
+
+	bcm43xx_phy_calibrate(bcm);
+	err = bcm43xx_chip_init(bcm);
+	if (err)
+		goto out;
+
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev);
+	ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET);
+
+	if (0 /*FIXME: which condition has to be used here? */)
+		ucodeflags |= 0x00000010;
+
+	/* HW decryption needs to be set now */
+	ucodeflags |= 0x40000000;
+	
+	if (phy->type == BCM43xx_PHYTYPE_G) {
+		ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
+		if (phy->rev == 1)
+			ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY;
+		if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
+			ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL;
+	} else if (phy->type == BCM43xx_PHYTYPE_B) {
+		ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
+		if (phy->rev >= 2 && radio->version == 0x2050)
+			ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY;
+	}
+
+	if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+					     BCM43xx_UCODEFLAGS_OFFSET)) {
+		bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+				    BCM43xx_UCODEFLAGS_OFFSET, ucodeflags);
+	}
+
+	/* Short/Long Retry Limit.
+	 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
+	 * the chip-internal counter.
+	 */
+	limit = limit_value(modparam_short_retry, 0, 0xF);
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit);
+	limit = limit_value(modparam_long_retry, 0, 0xF);
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit);
+
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2);
+
+	bcm43xx_rate_memory_init(bcm);
+
+	/* Minimum Contention Window */
+	if (phy->type == BCM43xx_PHYTYPE_B)
+		bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f);
+	else
+		bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f);
+	/* Maximum Contention Window */
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
+
+	bcm43xx_gen_bssid(bcm);
+	bcm43xx_write_mac_bssid_templates(bcm);
+
+	if (bcm->current_core->rev >= 5)
+		bcm43xx_write16(bcm, 0x043C, 0x000C);
+
+	if (bcm43xx_using_pio(bcm))
+		err = bcm43xx_pio_init(bcm);
+	else
+		err = bcm43xx_dma_init(bcm);
+	if (err)
+		goto err_chip_cleanup;
+	bcm43xx_write16(bcm, 0x0612, 0x0050);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
+
+	bcm43xx_mac_enable(bcm);
+	bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
+
+	bcm->current_core->initialized = 1;
+out:
+	return err;
+
+err_chip_cleanup:
+	bcm43xx_chip_cleanup(bcm);
+	goto out;
+}
+
+static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
+{
+	int err;
+	u16 pci_status;
+
+	err = bcm43xx_pctl_set_crystal(bcm, 1);
+	if (err)
+		goto out;
+	bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
+	bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
+
+out:
+	return err;
+}
+
+static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm)
+{
+	bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
+	bcm43xx_pctl_set_crystal(bcm, 0);
+}
+
+static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm,
+					    u32 address,
+					    u32 data)
+{
+	bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address);
+	bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data);
+}
+
+static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
+{
+	int err;
+	struct bcm43xx_coreinfo *old_core;
+
+	old_core = bcm->current_core;
+	err = bcm43xx_switch_core(bcm, &bcm->core_pci);
+	if (err)
+		goto out;
+
+	bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
+
+	bcm43xx_switch_core(bcm, old_core);
+	assert(err == 0);
+out:
+	return err;
+}
+
+/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
+ * To enable core 0, pass a core_mask of 1<<0
+ */
+static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
+						  u32 core_mask)
+{
+	u32 backplane_flag_nr;
+	u32 value;
+	struct bcm43xx_coreinfo *old_core;
+	int err = 0;
+
+	value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG);
+	backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK;
+
+	old_core = bcm->current_core;
+	err = bcm43xx_switch_core(bcm, &bcm->core_pci);
+	if (err)
+		goto out;
+
+	if (bcm->core_pci.rev < 6) {
+		value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
+		value |= (1 << backplane_flag_nr);
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
+	} else {
+		err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value);
+		if (err) {
+			printk(KERN_ERR PFX "Error: ICR setup failure!\n");
+			goto out_switch_back;
+		}
+		value |= core_mask << 8;
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value);
+		if (err) {
+			printk(KERN_ERR PFX "Error: ICR setup failure!\n");
+			goto out_switch_back;
+		}
+	}
+
+	value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
+	value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
+	bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
+
+	if (bcm->core_pci.rev < 5) {
+		value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
+		value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
+			 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
+		value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
+			 & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
+		err = bcm43xx_pcicore_commit_settings(bcm);
+		assert(err == 0);
+	}
+
+out_switch_back:
+	err = bcm43xx_switch_core(bcm, old_core);
+out:
+	return err;
+}
+
+static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
+{
+	ieee80211softmac_start(bcm->net_dev);
+}
+
+static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2)
+		return;
+
+	bcm43xx_mac_suspend(bcm);
+	bcm43xx_phy_lo_g_measure(bcm);
+	bcm43xx_mac_enable(bcm);
+}
+
+static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm)
+{
+	bcm43xx_phy_lo_mark_all_unused(bcm);
+	if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
+		bcm43xx_mac_suspend(bcm);
+		bcm43xx_calc_nrssi_slope(bcm);
+		bcm43xx_mac_enable(bcm);
+	}
+}
+
+static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
+{
+	/* Update device statistics. */
+	bcm43xx_calculate_link_quality(bcm);
+}
+
+static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	if (phy->type == BCM43xx_PHYTYPE_G) {
+		//TODO: update_aci_moving_average
+		if (radio->aci_enable && radio->aci_wlan_automatic) {
+			bcm43xx_mac_suspend(bcm);
+			if (!radio->aci_enable && 1 /*TODO: not scanning? */) {
+				if (0 /*TODO: bunch of conditions*/) {
+					bcm43xx_radio_set_interference_mitigation(bcm,
+										  BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
+				}
+			} else if (1/*TODO*/) {
+				/*
+				if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) {
+					bcm43xx_radio_set_interference_mitigation(bcm,
+										  BCM43xx_RADIO_INTERFMODE_NONE);
+				}
+				*/
+			}
+			bcm43xx_mac_enable(bcm);
+		} else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN &&
+			   phy->rev == 1) {
+			//TODO: implement rev1 workaround
+		}
+	}
+	bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
+	//TODO for APHY (temperature?)
+}
+
+static void bcm43xx_periodic_task_handler(unsigned long d)
+{
+	struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
+	unsigned long flags;
+	unsigned int state;
+
+	bcm43xx_lock_mmio(bcm, flags);
+
+	assert(bcm->initialized);
+	state = bcm->periodic_state;
+	if (state % 8 == 0)
+		bcm43xx_periodic_every120sec(bcm);
+	if (state % 4 == 0)
+		bcm43xx_periodic_every60sec(bcm);
+	if (state % 2 == 0)
+		bcm43xx_periodic_every30sec(bcm);
+	bcm43xx_periodic_every15sec(bcm);
+	bcm->periodic_state = state + 1;
+
+	mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
+
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
+{
+	del_timer_sync(&bcm->periodic_tasks);
+}
+
+static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
+{
+	struct timer_list *timer = &(bcm->periodic_tasks);
+
+	assert(bcm->initialized);
+	setup_timer(timer,
+		    bcm43xx_periodic_task_handler,
+		    (unsigned long)bcm);
+	timer->expires = jiffies;
+	add_timer(timer);
+}
+
+static void bcm43xx_security_init(struct bcm43xx_private *bcm)
+{
+	bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+						  0x0056) * 2;
+	bcm43xx_clear_keys(bcm);
+}
+
+/* This is the opposite of bcm43xx_init_board() */
+static void bcm43xx_free_board(struct bcm43xx_private *bcm)
+{
+	int i, err;
+	unsigned long flags;
+
+	bcm43xx_sysfs_unregister(bcm);
+
+	bcm43xx_periodic_tasks_delete(bcm);
+
+	bcm43xx_lock(bcm, flags);
+	bcm->initialized = 0;
+	bcm->shutting_down = 1;
+	bcm43xx_unlock(bcm, flags);
+
+	for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
+		if (!bcm->core_80211[i].available)
+			continue;
+		if (!bcm->core_80211[i].initialized)
+			continue;
+
+		err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
+		assert(err == 0);
+		bcm43xx_wireless_core_cleanup(bcm);
+	}
+
+	bcm43xx_pctl_set_crystal(bcm, 0);
+
+	bcm43xx_lock(bcm, flags);
+	bcm->shutting_down = 0;
+	bcm43xx_unlock(bcm, flags);
+}
+
+static int bcm43xx_init_board(struct bcm43xx_private *bcm)
+{
+	int i, err;
+	int connect_phy;
+	unsigned long flags;
+
+	might_sleep();
+
+	bcm43xx_lock(bcm, flags);
+	bcm->initialized = 0;
+	bcm->shutting_down = 0;
+	bcm43xx_unlock(bcm, flags);
+
+	err = bcm43xx_pctl_set_crystal(bcm, 1);
+	if (err)
+		goto out;
+	err = bcm43xx_pctl_init(bcm);
+	if (err)
+		goto err_crystal_off;
+	err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
+	if (err)
+		goto err_crystal_off;
+
+	tasklet_enable(&bcm->isr_tasklet);
+	for (i = 0; i < bcm->nr_80211_available; i++) {
+		err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
+		assert(err != -ENODEV);
+		if (err)
+			goto err_80211_unwind;
+
+		/* Enable the selected wireless core.
+		 * Connect PHY only on the first core.
+		 */
+		if (!bcm43xx_core_enabled(bcm)) {
+			if (bcm->nr_80211_available == 1) {
+				connect_phy = bcm43xx_current_phy(bcm)->connected;
+			} else {
+				if (i == 0)
+					connect_phy = 1;
+				else
+					connect_phy = 0;
+			}
+			bcm43xx_wireless_core_reset(bcm, connect_phy);
+		}
+
+		if (i != 0)
+			bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
+
+		err = bcm43xx_wireless_core_init(bcm);
+		if (err)
+			goto err_80211_unwind;
+
+		if (i != 0) {
+			bcm43xx_mac_suspend(bcm);
+			bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+			bcm43xx_radio_turn_off(bcm);
+		}
+	}
+	bcm->active_80211_core = &bcm->core_80211[0];
+	if (bcm->nr_80211_available >= 2) {
+		bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
+		bcm43xx_mac_enable(bcm);
+	}
+	bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
+	bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
+	dprintk(KERN_INFO PFX "80211 cores initialized\n");
+	bcm43xx_security_init(bcm);
+	bcm43xx_softmac_init(bcm);
+
+	bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
+
+	if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) {
+		bcm43xx_mac_suspend(bcm);
+		bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0);
+		bcm43xx_mac_enable(bcm);
+	}
+
+	/* Initialization of the board is done. Flag it as such. */
+	bcm43xx_lock(bcm, flags);
+	bcm->initialized = 1;
+	bcm43xx_unlock(bcm, flags);
+
+	bcm43xx_periodic_tasks_setup(bcm);
+	bcm43xx_sysfs_register(bcm);
+	//FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
+
+	assert(err == 0);
+out:
+	return err;
+
+err_80211_unwind:
+	tasklet_disable(&bcm->isr_tasklet);
+	/* unwind all 80211 initialization */
+	for (i = 0; i < bcm->nr_80211_available; i++) {
+		if (!bcm->core_80211[i].initialized)
+			continue;
+		bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+		bcm43xx_wireless_core_cleanup(bcm);
+	}
+err_crystal_off:
+	bcm43xx_pctl_set_crystal(bcm, 0);
+	goto out;
+}
+
+static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
+{
+	struct pci_dev *pci_dev = bcm->pci_dev;
+	int i;
+
+	bcm43xx_chipset_detach(bcm);
+	/* Do _not_ access the chip, after it is detached. */
+	iounmap(bcm->mmio_addr);
+	
+	pci_release_regions(pci_dev);
+	pci_disable_device(pci_dev);
+
+	/* Free allocated structures/fields */
+	for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
+		kfree(bcm->core_80211_ext[i].phy._lo_pairs);
+		if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl)
+			kfree(bcm->core_80211_ext[i].phy.tssi2dbm);
+	}
+}	
+
+static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 value;
+	u8 phy_version;
+	u8 phy_type;
+	u8 phy_rev;
+	int phy_rev_ok = 1;
+	void *p;
+
+	value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER);
+
+	phy_version = (value & 0xF000) >> 12;
+	phy_type = (value & 0x0F00) >> 8;
+	phy_rev = (value & 0x000F);
+
+	dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n",
+		phy_version, phy_type, phy_rev);
+
+	switch (phy_type) {
+	case BCM43xx_PHYTYPE_A:
+		if (phy_rev >= 4)
+			phy_rev_ok = 0;
+		/*FIXME: We need to switch the ieee->modulation, etc.. flags,
+		 *       if we switch 80211 cores after init is done.
+		 *       As we do not implement on the fly switching between
+		 *       wireless cores, I will leave this as a future task.
+		 */
+		bcm->ieee->modulation = IEEE80211_OFDM_MODULATION;
+		bcm->ieee->mode = IEEE_A;
+		bcm->ieee->freq_band = IEEE80211_52GHZ_BAND |
+				       IEEE80211_24GHZ_BAND;
+		break;
+	case BCM43xx_PHYTYPE_B:
+		if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7)
+			phy_rev_ok = 0;
+		bcm->ieee->modulation = IEEE80211_CCK_MODULATION;
+		bcm->ieee->mode = IEEE_B;
+		bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
+		break;
+	case BCM43xx_PHYTYPE_G:
+		if (phy_rev > 7)
+			phy_rev_ok = 0;
+		bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
+					IEEE80211_CCK_MODULATION;
+		bcm->ieee->mode = IEEE_G;
+		bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
+		break;
+	default:
+		printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n",
+		       phy_type);
+		return -ENODEV;
+	};
+	if (!phy_rev_ok) {
+		printk(KERN_WARNING PFX "Invalid PHY Revision %x\n",
+		       phy_rev);
+	}
+
+	phy->version = phy_version;
+	phy->type = phy_type;
+	phy->rev = phy_rev;
+	if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) {
+		p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT,
+			    GFP_KERNEL);
+		if (!p)
+			return -ENOMEM;
+		phy->_lo_pairs = p;
+	}
+
+	return 0;
+}
+
+static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
+{
+	struct pci_dev *pci_dev = bcm->pci_dev;
+	struct net_device *net_dev = bcm->net_dev;
+	int err;
+	int i;
+	unsigned long mmio_start, mmio_flags, mmio_len;
+	u32 coremask;
+
+	err = pci_enable_device(pci_dev);
+	if (err) {
+		printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err);
+		goto out;
+	}
+	mmio_start = pci_resource_start(pci_dev, 0);
+	mmio_flags = pci_resource_flags(pci_dev, 0);
+	mmio_len = pci_resource_len(pci_dev, 0);
+	if (!(mmio_flags & IORESOURCE_MEM)) {
+		printk(KERN_ERR PFX
+		       "%s, region #0 not an MMIO resource, aborting\n",
+		       pci_name(pci_dev));
+		err = -ENODEV;
+		goto err_pci_disable;
+	}
+	err = pci_request_regions(pci_dev, KBUILD_MODNAME);
+	if (err) {
+		printk(KERN_ERR PFX
+		       "could not access PCI resources (%i)\n", err);
+		goto err_pci_disable;
+	}
+	/* enable PCI bus-mastering */
+	pci_set_master(pci_dev);
+	bcm->mmio_addr = ioremap(mmio_start, mmio_len);
+	if (!bcm->mmio_addr) {
+		printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n",
+		       pci_name(pci_dev));
+		err = -EIO;
+		goto err_pci_release;
+	}
+	bcm->mmio_len = mmio_len;
+	net_dev->base_addr = (unsigned long)bcm->mmio_addr;
+
+	bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
+	                          &bcm->board_vendor);
+	bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
+	                          &bcm->board_type);
+	bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
+	                          &bcm->board_revision);
+
+	err = bcm43xx_chipset_attach(bcm);
+	if (err)
+		goto err_iounmap;
+	err = bcm43xx_pctl_init(bcm);
+	if (err)
+		goto err_chipset_detach;
+	err = bcm43xx_probe_cores(bcm);
+	if (err)
+		goto err_chipset_detach;
+	
+	/* Attach all IO cores to the backplane. */
+	coremask = 0;
+	for (i = 0; i < bcm->nr_80211_available; i++)
+		coremask |= (1 << bcm->core_80211[i].index);
+	//FIXME: Also attach some non80211 cores?
+	err = bcm43xx_setup_backplane_pci_connection(bcm, coremask);
+	if (err) {
+		printk(KERN_ERR PFX "Backplane->PCI connection failed!\n");
+		goto err_chipset_detach;
+	}
+
+	err = bcm43xx_sprom_extract(bcm);
+	if (err)
+		goto err_chipset_detach;
+	err = bcm43xx_leds_init(bcm);
+	if (err)
+		goto err_chipset_detach;
+
+	for (i = 0; i < bcm->nr_80211_available; i++) {
+		err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
+		assert(err != -ENODEV);
+		if (err)
+			goto err_80211_unwind;
+
+		/* Enable the selected wireless core.
+		 * Connect PHY only on the first core.
+		 */
+		bcm43xx_wireless_core_reset(bcm, (i == 0));
+
+		err = bcm43xx_read_phyinfo(bcm);
+		if (err && (i == 0))
+			goto err_80211_unwind;
+
+		err = bcm43xx_read_radioinfo(bcm);
+		if (err && (i == 0))
+			goto err_80211_unwind;
+
+		err = bcm43xx_validate_chip(bcm);
+		if (err && (i == 0))
+			goto err_80211_unwind;
+
+		bcm43xx_radio_turn_off(bcm);
+		err = bcm43xx_phy_init_tssi2dbm_table(bcm);
+		if (err)
+			goto err_80211_unwind;
+		bcm43xx_wireless_core_disable(bcm);
+	}
+	bcm43xx_pctl_set_crystal(bcm, 0);
+
+	/* Set the MAC address in the networking subsystem */
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
+		memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
+	else
+		memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
+
+	bcm43xx_geo_init(bcm);
+
+	snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
+		 "Broadcom %04X", bcm->chip_id);
+
+	assert(err == 0);
+out:
+	return err;
+
+err_80211_unwind:
+	for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
+		kfree(bcm->core_80211_ext[i].phy._lo_pairs);
+		if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl)
+			kfree(bcm->core_80211_ext[i].phy.tssi2dbm);
+	}
+err_chipset_detach:
+	bcm43xx_chipset_detach(bcm);
+err_iounmap:
+	iounmap(bcm->mmio_addr);
+err_pci_release:
+	pci_release_regions(pci_dev);
+err_pci_disable:
+	pci_disable_device(pci_dev);
+	goto out;
+}
+
+/* Do the Hardware IO operations to send the txb */
+static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
+			     struct ieee80211_txb *txb)
+{
+	int err = -ENODEV;
+
+	if (bcm43xx_using_pio(bcm))
+		err = bcm43xx_pio_tx(bcm, txb);
+	else
+		err = bcm43xx_dma_tx(bcm, txb);
+
+	return err;
+}
+
+static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
+				       u8 channel)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	struct bcm43xx_radioinfo *radio;
+	unsigned long flags;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if (bcm->initialized) {
+		bcm43xx_mac_suspend(bcm);
+		bcm43xx_radio_selectchannel(bcm, channel, 0);
+		bcm43xx_mac_enable(bcm);
+	} else {
+		radio = bcm43xx_current_radio(bcm);
+		radio->initial_channel = channel;
+	}
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+/* set_security() callback in struct ieee80211_device */
+static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
+					   struct ieee80211_security *sec)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	struct ieee80211_security *secinfo = &bcm->ieee->sec;
+	unsigned long flags;
+	int keyidx;
+	
+	dprintk(KERN_INFO PFX "set security called\n");
+
+	bcm43xx_lock_mmio(bcm, flags);
+
+	for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
+		if (sec->flags & (1<<keyidx)) {
+			secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
+			secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
+			memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN);
+		}
+	
+	if (sec->flags & SEC_ACTIVE_KEY) {
+		secinfo->active_key = sec->active_key;
+		dprintk(KERN_INFO PFX "   .active_key = %d\n", sec->active_key);
+	}
+	if (sec->flags & SEC_UNICAST_GROUP) {
+		secinfo->unicast_uses_group = sec->unicast_uses_group;
+		dprintk(KERN_INFO PFX "   .unicast_uses_group = %d\n", sec->unicast_uses_group);
+	}
+	if (sec->flags & SEC_LEVEL) {
+		secinfo->level = sec->level;
+		dprintk(KERN_INFO PFX "   .level = %d\n", sec->level);
+	}
+	if (sec->flags & SEC_ENABLED) {
+		secinfo->enabled = sec->enabled;
+		dprintk(KERN_INFO PFX "   .enabled = %d\n", sec->enabled);
+	}
+	if (sec->flags & SEC_ENCRYPT) {
+		secinfo->encrypt = sec->encrypt;
+		dprintk(KERN_INFO PFX "   .encrypt = %d\n", sec->encrypt);
+	}
+	if (bcm->initialized && !bcm->ieee->host_encrypt) {
+		if (secinfo->enabled) {
+			/* upload WEP keys to hardware */
+			char null_address[6] = { 0 };
+			u8 algorithm = 0;
+			for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) {
+				if (!(sec->flags & (1<<keyidx)))
+					continue;
+				switch (sec->encode_alg[keyidx]) {
+					case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break;
+					case SEC_ALG_WEP:
+						algorithm = BCM43xx_SEC_ALGO_WEP;
+						if (secinfo->key_sizes[keyidx] == 13)
+							algorithm = BCM43xx_SEC_ALGO_WEP104;
+						break;
+					case SEC_ALG_TKIP:
+						FIXME();
+						algorithm = BCM43xx_SEC_ALGO_TKIP;
+						break;
+					case SEC_ALG_CCMP:
+						FIXME();
+						algorithm = BCM43xx_SEC_ALGO_AES;
+						break;
+					default:
+						assert(0);
+						break;
+				}
+				bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]);
+				bcm->key[keyidx].enabled = 1;
+				bcm->key[keyidx].algorithm = algorithm;
+			}
+		} else
+				bcm43xx_clear_keys(bcm);
+	}
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+/* hard_start_xmit() callback in struct ieee80211_device */
+static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
+					     struct net_device *net_dev,
+					     int pri)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	int err = -ENODEV;
+	unsigned long flags;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if (likely(bcm->initialized))
+		err = bcm43xx_tx(bcm, txb);
+	bcm43xx_unlock_mmio(bcm, flags);
+
+	return err;
+}
+
+static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
+{
+	return &(bcm43xx_priv(net_dev)->ieee->stats);
+}
+
+static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_controller_restart(bcm, "TX timeout");
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void bcm43xx_net_poll_controller(struct net_device *net_dev)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
+	local_irq_restore(flags);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
+static int bcm43xx_net_open(struct net_device *net_dev)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+
+	return bcm43xx_init_board(bcm);
+}
+
+static int bcm43xx_net_stop(struct net_device *net_dev)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+
+	ieee80211softmac_stop(net_dev);
+	bcm43xx_disable_interrupts_sync(bcm, NULL);
+	bcm43xx_free_board(bcm);
+
+	return 0;
+}
+
+static int bcm43xx_init_private(struct bcm43xx_private *bcm,
+				struct net_device *net_dev,
+				struct pci_dev *pci_dev)
+{
+	int err;
+
+	bcm->ieee = netdev_priv(net_dev);
+	bcm->softmac = ieee80211_priv(net_dev);
+	bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
+
+	bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+	bcm->pci_dev = pci_dev;
+	bcm->net_dev = net_dev;
+	bcm->bad_frames_preempt = modparam_bad_frames_preempt;
+	spin_lock_init(&bcm->_lock);
+	tasklet_init(&bcm->isr_tasklet,
+		     (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
+		     (unsigned long)bcm);
+	tasklet_disable_nosync(&bcm->isr_tasklet);
+	if (modparam_pio) {
+		bcm->__using_pio = 1;
+	} else {
+		err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK);
+		err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK);
+		if (err) {
+#ifdef CONFIG_BCM43XX_PIO
+			printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
+			bcm->__using_pio = 1;
+#else
+			printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
+					    "Recompile the driver with PIO support, please.\n");
+			return -ENODEV;
+#endif /* CONFIG_BCM43XX_PIO */
+		}
+	}
+	bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
+
+	/* default to sw encryption for now */
+	bcm->ieee->host_build_iv = 0;
+	bcm->ieee->host_encrypt = 1;
+	bcm->ieee->host_decrypt = 1;
+	
+	bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE;
+	bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr);
+	bcm->ieee->set_security = bcm43xx_ieee80211_set_security;
+	bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit;
+
+	return 0;
+}
+
+static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
+				      const struct pci_device_id *ent)
+{
+	struct net_device *net_dev;
+	struct bcm43xx_private *bcm;
+	int err;
+
+#ifdef CONFIG_BCM947XX
+	if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
+		return -ENODEV;
+#endif
+
+#ifdef DEBUG_SINGLE_DEVICE_ONLY
+	if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
+		return -ENODEV;
+#endif
+
+	net_dev = alloc_ieee80211softmac(sizeof(*bcm));
+	if (!net_dev) {
+		printk(KERN_ERR PFX
+		       "could not allocate ieee80211 device %s\n",
+		       pci_name(pdev));
+		err = -ENOMEM;
+		goto out;
+	}
+	/* initialize the net_device struct */
+	SET_MODULE_OWNER(net_dev);
+	SET_NETDEV_DEV(net_dev, &pdev->dev);
+
+	net_dev->open = bcm43xx_net_open;
+	net_dev->stop = bcm43xx_net_stop;
+	net_dev->get_stats = bcm43xx_net_get_stats;
+	net_dev->tx_timeout = bcm43xx_net_tx_timeout;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	net_dev->poll_controller = bcm43xx_net_poll_controller;
+#endif
+	net_dev->wireless_handlers = &bcm43xx_wx_handlers_def;
+	net_dev->irq = pdev->irq;
+	SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops);
+
+	/* initialize the bcm43xx_private struct */
+	bcm = bcm43xx_priv(net_dev);
+	memset(bcm, 0, sizeof(*bcm));
+	err = bcm43xx_init_private(bcm, net_dev, pdev);
+	if (err)
+		goto err_free_netdev;
+
+	pci_set_drvdata(pdev, net_dev);
+
+	err = bcm43xx_attach_board(bcm);
+	if (err)
+		goto err_free_netdev;
+
+	err = register_netdev(net_dev);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot register net device, "
+		       "aborting.\n");
+		err = -ENOMEM;
+		goto err_detach_board;
+	}
+
+	bcm43xx_debugfs_add_device(bcm);
+
+	assert(err == 0);
+out:
+	return err;
+
+err_detach_board:
+	bcm43xx_detach_board(bcm);
+err_free_netdev:
+	free_ieee80211softmac(net_dev);
+	goto out;
+}
+
+static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *net_dev = pci_get_drvdata(pdev);
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+
+	bcm43xx_debugfs_remove_device(bcm);
+	unregister_netdev(net_dev);
+	bcm43xx_detach_board(bcm);
+	assert(bcm->ucode == NULL);
+	free_ieee80211softmac(net_dev);
+}
+
+/* Hard-reset the chip. Do not call this directly.
+ * Use bcm43xx_controller_restart()
+ */
+static void bcm43xx_chip_reset(void *_bcm)
+{
+	struct bcm43xx_private *bcm = _bcm;
+	struct net_device *net_dev = bcm->net_dev;
+	struct pci_dev *pci_dev = bcm->pci_dev;
+	int err;
+	int was_initialized = bcm->initialized;
+
+	netif_stop_queue(bcm->net_dev);
+	tasklet_disable(&bcm->isr_tasklet);
+
+	bcm->firmware_norelease = 1;
+	if (was_initialized)
+		bcm43xx_free_board(bcm);
+	bcm->firmware_norelease = 0;
+	bcm43xx_detach_board(bcm);
+	err = bcm43xx_init_private(bcm, net_dev, pci_dev);
+	if (err)
+		goto failure;
+	err = bcm43xx_attach_board(bcm);
+	if (err)
+		goto failure;
+	if (was_initialized) {
+		err = bcm43xx_init_board(bcm);
+		if (err)
+			goto failure;
+	}
+	netif_wake_queue(bcm->net_dev);
+	printk(KERN_INFO PFX "Controller restarted\n");
+
+	return;
+failure:
+	printk(KERN_ERR PFX "Controller restart failed\n");
+}
+
+/* Hard-reset the chip.
+ * This can be called from interrupt or process context.
+ * Make sure to _not_ re-enable device interrupts after this has been called.
+*/
+void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
+{
+	bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+	printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
+	INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
+	schedule_work(&bcm->restart_work);
+}
+
+#ifdef CONFIG_PM
+
+static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *net_dev = pci_get_drvdata(pdev);
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	int try_to_shutdown = 0, err;
+
+	dprintk(KERN_INFO PFX "Suspending...\n");
+
+	bcm43xx_lock(bcm, flags);
+	bcm->was_initialized = bcm->initialized;
+	if (bcm->initialized)
+		try_to_shutdown = 1;
+	bcm43xx_unlock(bcm, flags);
+
+	netif_device_detach(net_dev);
+	if (try_to_shutdown) {
+		ieee80211softmac_stop(net_dev);
+		err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
+		if (unlikely(err)) {
+			dprintk(KERN_ERR PFX "Suspend failed.\n");
+			return -EAGAIN;
+		}
+		bcm->firmware_norelease = 1;
+		bcm43xx_free_board(bcm);
+		bcm->firmware_norelease = 0;
+	}
+	bcm43xx_chipset_detach(bcm);
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	dprintk(KERN_INFO PFX "Device suspended.\n");
+
+	return 0;
+}
+
+static int bcm43xx_resume(struct pci_dev *pdev)
+{
+	struct net_device *net_dev = pci_get_drvdata(pdev);
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	int err = 0;
+
+	dprintk(KERN_INFO PFX "Resuming...\n");
+
+	pci_set_power_state(pdev, 0);
+	pci_enable_device(pdev);
+	pci_restore_state(pdev);
+
+	bcm43xx_chipset_attach(bcm);
+	if (bcm->was_initialized) {
+		bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+		err = bcm43xx_init_board(bcm);
+	}
+	if (err) {
+		printk(KERN_ERR PFX "Resume failed!\n");
+		return err;
+	}
+
+	netif_device_attach(net_dev);
+	
+	/*FIXME: This should be handled by softmac instead. */
+	schedule_work(&bcm->softmac->associnfo.work);
+
+	dprintk(KERN_INFO PFX "Device resumed.\n");
+
+	return 0;
+}
+
+#endif				/* CONFIG_PM */
+
+static struct pci_driver bcm43xx_pci_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = bcm43xx_pci_tbl,
+	.probe = bcm43xx_init_one,
+	.remove = __devexit_p(bcm43xx_remove_one),
+#ifdef CONFIG_PM
+	.suspend = bcm43xx_suspend,
+	.resume = bcm43xx_resume,
+#endif				/* CONFIG_PM */
+};
+
+static int __init bcm43xx_init(void)
+{
+	printk(KERN_INFO KBUILD_MODNAME " driver\n");
+	bcm43xx_debugfs_init();
+	return pci_register_driver(&bcm43xx_pci_driver);
+}
+
+static void __exit bcm43xx_exit(void)
+{
+	pci_unregister_driver(&bcm43xx_pci_driver);
+	bcm43xx_debugfs_exit();
+}
+
+module_init(bcm43xx_init)
+module_exit(bcm43xx_exit)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
new file mode 100644
index 0000000..eca79a3
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -0,0 +1,168 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef BCM43xx_MAIN_H_
+#define BCM43xx_MAIN_H_
+
+#include "bcm43xx.h"
+
+#ifdef CONFIG_BCM947XX
+#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
+
+static inline void e_aton(char *str, char *dest)
+{
+	int i = 0;
+	u16 *d = (u16 *) dest;
+
+	for (;;) {
+		dest[i++] = (char) simple_strtoul(str, NULL, 16);
+		str += 2;
+		if (!*str++ || i == 6)
+			break;
+	}
+	for (i = 0; i < 3; i++)
+		d[i] = cpu_to_be16(d[i]);
+}
+#endif
+
+#define P4D_BYT3S(magic, nr_bytes)	u8 __p4dding##magic[nr_bytes]
+#define P4D_BYTES(line, nr_bytes)	P4D_BYT3S(line, nr_bytes)
+/* Magic helper macro to pad structures. Ignore those above. It's magic. */
+#define PAD_BYTES(nr_bytes)		P4D_BYTES( __LINE__ , (nr_bytes))
+
+
+/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
+static inline
+u8 bcm43xx_freq_to_channel_a(int freq)
+{
+	return ((freq - 5000) / 5);
+}
+static inline
+u8 bcm43xx_freq_to_channel_bg(int freq)
+{
+	u8 channel;
+
+	if (freq == 2484)
+		channel = 14;
+	else
+		channel = (freq - 2407) / 5;
+
+	return channel;
+}
+static inline
+u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm,
+			   int freq)
+{
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
+		return bcm43xx_freq_to_channel_a(freq);
+	return bcm43xx_freq_to_channel_bg(freq);
+}
+
+/* Lightweight function to convert a channel number to a frequency (in Mhz). */
+static inline
+int bcm43xx_channel_to_freq_a(u8 channel)
+{
+	return (5000 + (5 * channel));
+}
+static inline
+int bcm43xx_channel_to_freq_bg(u8 channel)
+{
+	int freq;
+
+	if (channel == 14)
+		freq = 2484;
+	else
+		freq = 2407 + (5 * channel);
+
+	return freq;
+}
+static inline
+int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm,
+			    u8 channel)
+{
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
+		return bcm43xx_channel_to_freq_a(channel);
+	return bcm43xx_channel_to_freq_bg(channel);
+}
+
+/* Lightweight function to check if a channel number is valid.
+ * Note that this does _NOT_ check for geographical restrictions!
+ */
+static inline
+int bcm43xx_is_valid_channel_a(u8 channel)
+{
+	return (channel <= 200);
+}
+static inline
+int bcm43xx_is_valid_channel_bg(u8 channel)
+{
+	return (channel >= 1 && channel <= 14);
+}
+static inline
+int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
+			     u8 channel)
+{
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
+		return bcm43xx_is_valid_channel_a(channel);
+	return bcm43xx_is_valid_channel_bg(channel);
+}
+
+void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
+void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
+
+void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
+			int iw_mode);
+
+u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm,
+		       u16 routing, u16 offset);
+u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm,
+		       u16 routing, u16 offset);
+void bcm43xx_shm_write32(struct bcm43xx_private *bcm,
+			 u16 routing, u16 offset,
+			 u32 value);
+void bcm43xx_shm_write16(struct bcm43xx_private *bcm,
+			 u16 routing, u16 offset,
+			 u16 value);
+
+void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm);
+
+int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core);
+
+void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
+
+void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
+void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
+
+void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
+
+int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom);
+int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom);
+
+#endif /* BCM43xx_MAIN_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
new file mode 100644
index 0000000..0a66f43
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -0,0 +1,2345 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include "bcm43xx.h"
+#include "bcm43xx_phy.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_radio.h"
+#include "bcm43xx_ilt.h"
+#include "bcm43xx_power.h"
+
+
+static const s8 bcm43xx_tssi2dbm_b_table[] = {
+	0x4D, 0x4C, 0x4B, 0x4A,
+	0x4A, 0x49, 0x48, 0x47,
+	0x47, 0x46, 0x45, 0x45,
+	0x44, 0x43, 0x42, 0x42,
+	0x41, 0x40, 0x3F, 0x3E,
+	0x3D, 0x3C, 0x3B, 0x3A,
+	0x39, 0x38, 0x37, 0x36,
+	0x35, 0x34, 0x32, 0x31,
+	0x30, 0x2F, 0x2D, 0x2C,
+	0x2B, 0x29, 0x28, 0x26,
+	0x25, 0x23, 0x21, 0x1F,
+	0x1D, 0x1A, 0x17, 0x14,
+	0x10, 0x0C, 0x06, 0x00,
+	  -7,   -7,   -7,   -7,
+	  -7,   -7,   -7,   -7,
+	  -7,   -7,   -7,   -7,
+};
+
+static const s8 bcm43xx_tssi2dbm_g_table[] = {
+	 77,  77,  77,  76,
+	 76,  76,  75,  75,
+	 74,  74,  73,  73,
+	 73,  72,  72,  71,
+	 71,  70,  70,  69,
+	 68,  68,  67,  67,
+	 66,  65,  65,  64,
+	 63,  63,  62,  61,
+	 60,  59,  58,  57,
+	 56,  55,  54,  53,
+	 52,  50,  49,  47,
+	 45,  43,  40,  37,
+	 33,  28,  22,  14,
+	  5,  -7, -20, -20,
+	-20, -20, -20, -20,
+	-20, -20, -20, -20,
+};
+
+static void bcm43xx_phy_initg(struct bcm43xx_private *bcm);
+
+
+void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	assert(irqs_disabled());
+	if (bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) == 0x00000000) {
+		phy->is_locked = 0;
+		return;
+	}
+	if (bcm->current_core->rev < 3) {
+		bcm43xx_mac_suspend(bcm);
+		spin_lock(&phy->lock);
+	} else {
+		if (bcm->ieee->iw_mode != IW_MODE_MASTER)
+			bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
+	}
+	phy->is_locked = 1;
+}
+
+void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	assert(irqs_disabled());
+	if (bcm->current_core->rev < 3) {
+		if (phy->is_locked) {
+			spin_unlock(&phy->lock);
+			bcm43xx_mac_enable(bcm);
+		}
+	} else {
+		if (bcm->ieee->iw_mode != IW_MODE_MASTER)
+			bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+	}
+	phy->is_locked = 0;
+}
+
+u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset)
+{
+	bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset);
+	return bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_DATA);
+}
+
+void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val)
+{
+	bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset);
+	mmiowb();
+	bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_DATA, val);
+}
+
+void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	unsigned long flags;
+
+	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
+	if (phy->calibrated)
+		return;
+	if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) {
+		/* We do not want to be preempted while calibrating
+		 * the hardware.
+		 */
+		local_irq_save(flags);
+
+		bcm43xx_wireless_core_reset(bcm, 0);
+		bcm43xx_phy_initg(bcm);
+		bcm43xx_wireless_core_reset(bcm, 1);
+
+		local_irq_restore(flags);
+	}
+	phy->calibrated = 1;
+}
+
+/* Connect the PHY 
+ * http://bcm-specs.sipsolutions.net/SetPHY
+ */
+int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u32 flags;
+
+	if (bcm->current_core->rev < 5)
+		goto out;
+
+	flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
+	if (connect) {
+		if (!(flags & 0x00010000))
+			return -ENODEV;
+		flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+		flags |= (0x800 << 18);
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
+	} else {
+		if (!(flags & 0x00020000))
+			return -ENODEV;
+		flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+		flags &= ~(0x800 << 18);
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
+	}
+out:
+	phy->connected = connect;
+	if (connect)
+		dprintk(KERN_INFO PFX "PHY connected\n");
+	else
+		dprintk(KERN_INFO PFX "PHY disconnected\n");
+
+	return 0;
+}
+
+/* intialize B PHY power control
+ * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
+ */
+static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 saved_batt = 0, saved_ratt = 0, saved_txctl1 = 0;
+	int must_reset_txpower = 0;
+
+	assert(phy->type != BCM43xx_PHYTYPE_A);
+	if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
+	    (bcm->board_type == 0x0416))
+		return;
+
+	bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF);
+	bcm43xx_phy_write(bcm, 0x0028, 0x8018);
+
+	if (phy->type == BCM43xx_PHYTYPE_G) {
+		if (!phy->connected)
+			return;
+		bcm43xx_phy_write(bcm, 0x047A, 0xC111);
+	}
+	if (phy->savedpctlreg != 0xFFFF)
+		return;
+
+	if (phy->type == BCM43xx_PHYTYPE_B &&
+	    phy->rev >= 2 &&
+	    radio->version == 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0076,
+				      bcm43xx_radio_read16(bcm, 0x0076) | 0x0084);
+	} else {
+		saved_batt = radio->baseband_atten;
+		saved_ratt = radio->radio_atten;
+		saved_txctl1 = radio->txctl1;
+		if ((radio->revision >= 6) && (radio->revision <= 8)
+		    && /*FIXME: incomplete specs for 5 < revision < 9 */ 0)
+			bcm43xx_radio_set_txpower_bg(bcm, 0xB, 0x1F, 0);
+		else
+			bcm43xx_radio_set_txpower_bg(bcm, 0xB, 9, 0);
+		must_reset_txpower = 1;
+	}
+	bcm43xx_dummy_transmission(bcm);
+
+	phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_PCTL);
+
+	if (must_reset_txpower)
+		bcm43xx_radio_set_txpower_bg(bcm, saved_batt, saved_ratt, saved_txctl1);
+	else
+		bcm43xx_radio_write16(bcm, 0x0076, bcm43xx_radio_read16(bcm, 0x0076) & 0xFF7B);
+	bcm43xx_radio_clear_tssi(bcm);
+}
+
+static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 offset = 0x0000;
+
+	if (phy->rev == 1)
+		offset = 0x4C00;
+
+	bcm43xx_ilt_write(bcm, offset, 0x00FE);
+	bcm43xx_ilt_write(bcm, offset + 1, 0x000D);
+	bcm43xx_ilt_write(bcm, offset + 2, 0x0013);
+	bcm43xx_ilt_write(bcm, offset + 3, 0x0019);
+
+	if (phy->rev == 1) {
+		bcm43xx_ilt_write(bcm, 0x1800, 0x2710);
+		bcm43xx_ilt_write(bcm, 0x1801, 0x9B83);
+		bcm43xx_ilt_write(bcm, 0x1802, 0x9B83);
+		bcm43xx_ilt_write(bcm, 0x1803, 0x0F8D);
+		bcm43xx_phy_write(bcm, 0x0455, 0x0004);
+	}
+
+	bcm43xx_phy_write(bcm, 0x04A5, (bcm43xx_phy_read(bcm, 0x04A5) & 0x00FF) | 0x5700);
+	bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xFF80) | 0x000F);
+	bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xC07F) | 0x2B80);
+	bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xF0FF) | 0x0300);
+
+	bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0008);
+
+	bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFF0) | 0x0008);
+	bcm43xx_phy_write(bcm, 0x04A1, (bcm43xx_phy_read(bcm, 0x04A1) & 0xF0FF) | 0x0600);
+	bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0700);
+	bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0100);
+
+	if (phy->rev == 1)
+		bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x0007);
+
+	bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xFF00) | 0x001C);
+	bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xC0FF) | 0x0200);
+	bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0xFF00) | 0x001C);
+	bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xFF00) | 0x0020);
+	bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xC0FF) | 0x0200);
+	bcm43xx_phy_write(bcm, 0x0482, (bcm43xx_phy_read(bcm, 0x0482) & 0xFF00) | 0x002E);
+	bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0x00FF) | 0x1A00);
+	bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0xFF00) | 0x0028);
+	bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0x00FF) | 0x2C00);
+
+	if (phy->rev == 1) {
+		bcm43xx_phy_write(bcm, 0x0430, 0x092B);
+		bcm43xx_phy_write(bcm, 0x041B, (bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1) | 0x0002);
+	} else {
+		bcm43xx_phy_write(bcm, 0x041B, bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1);
+		bcm43xx_phy_write(bcm, 0x041F, 0x287A);
+		bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0xFFF0) | 0x0004);
+	}
+
+	if (phy->rev > 2) {
+		bcm43xx_phy_write(bcm, 0x0422, 0x287A);
+		bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000); 
+	}
+		
+	bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874);
+	bcm43xx_phy_write(bcm, 0x048E, 0x1C00);
+
+	if (phy->rev == 1) {
+		bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600);
+		bcm43xx_phy_write(bcm, 0x048B, 0x005E);
+		bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E);
+		bcm43xx_phy_write(bcm, 0x048D, 0x0002);
+	}
+
+	bcm43xx_ilt_write(bcm, offset + 0x0800, 0);
+	bcm43xx_ilt_write(bcm, offset + 0x0801, 7);
+	bcm43xx_ilt_write(bcm, offset + 0x0802, 16);
+	bcm43xx_ilt_write(bcm, offset + 0x0803, 28);
+}
+
+static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 i;
+
+	assert(phy->type == BCM43xx_PHYTYPE_G);
+	if (phy->rev == 1) {
+		bcm43xx_phy_write(bcm, 0x0406, 0x4F19);
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+				  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340);
+		bcm43xx_phy_write(bcm, 0x042C, 0x005A);
+		bcm43xx_phy_write(bcm, 0x0427, 0x001A);
+
+		for (i = 0; i < BCM43xx_ILT_FINEFREQG_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]);
+		for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]);
+		for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]);
+	} else {
+		/* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */
+		bcm43xx_nrssi_hw_write(bcm, 0xBA98, (s16)0x7654);
+
+		if (phy->rev == 2) {
+			bcm43xx_phy_write(bcm, 0x04C0, 0x1861);
+			bcm43xx_phy_write(bcm, 0x04C1, 0x0271);
+		} else if (phy->rev > 2) {
+			bcm43xx_phy_write(bcm, 0x04C0, 0x0098);
+			bcm43xx_phy_write(bcm, 0x04C1, 0x0070);
+			bcm43xx_phy_write(bcm, 0x04C9, 0x0080);
+		}
+		bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x800);
+
+		for (i = 0; i < 64; i++)
+			bcm43xx_ilt_write(bcm, 0x4000 + i, i);
+		for (i = 0; i < BCM43xx_ILT_NOISEG2_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg2[i]);
+	}
+	
+	if (phy->rev <= 2)
+		for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]);
+	else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200))
+		for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]);
+	else
+		for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg2[i]);
+	
+	if (phy->rev == 2)
+		for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
+	else if ((phy->rev > 2) && (phy->rev <= 7))
+		for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]);
+	
+	if (phy->rev == 1) {
+		for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
+		for (i = 0; i < 4; i++) {
+			bcm43xx_ilt_write(bcm, 0x5404 + i, 0x0020);
+			bcm43xx_ilt_write(bcm, 0x5408 + i, 0x0020);
+			bcm43xx_ilt_write(bcm, 0x540C + i, 0x0020);
+			bcm43xx_ilt_write(bcm, 0x5410 + i, 0x0020);
+		}
+		bcm43xx_phy_agcsetup(bcm);
+
+		if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
+		    (bcm->board_type == 0x0416) &&
+		    (bcm->board_revision == 0x0017))
+			return;
+
+		bcm43xx_ilt_write(bcm, 0x5001, 0x0002);
+		bcm43xx_ilt_write(bcm, 0x5002, 0x0001);
+	} else {
+		for (i = 0; i <= 0x2F; i++)
+			bcm43xx_ilt_write(bcm, 0x1000 + i, 0x0820);
+		bcm43xx_phy_agcsetup(bcm);
+		bcm43xx_phy_read(bcm, 0x0400); /* dummy read */
+		bcm43xx_phy_write(bcm, 0x0403, 0x1000);
+		bcm43xx_ilt_write(bcm, 0x3C02, 0x000F);
+		bcm43xx_ilt_write(bcm, 0x3C03, 0x0014);
+
+		if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
+		    (bcm->board_type == 0x0416) &&
+		    (bcm->board_revision == 0x0017))
+			return;
+
+		bcm43xx_ilt_write(bcm, 0x0401, 0x0002);
+		bcm43xx_ilt_write(bcm, 0x0402, 0x0001);
+	}
+}
+
+/* Initialize the noisescaletable for APHY */
+static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	int i;
+
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, 0x1400);
+	for (i = 0; i < 12; i++) {
+		if (phy->rev == 2)
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767);
+		else
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323);
+	}
+	if (phy->rev == 2)
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6700);
+	else
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2300);
+	for (i = 0; i < 11; i++) {
+		if (phy->rev == 2)
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767);
+		else
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323);
+	}
+	if (phy->rev == 2)
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0067);
+	else
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0023);
+}
+
+static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 i;
+
+	assert(phy->type == BCM43xx_PHYTYPE_A);
+	switch (phy->rev) {
+	case 2:
+		bcm43xx_phy_write(bcm, 0x008E, 0x3800);
+		bcm43xx_phy_write(bcm, 0x0035, 0x03FF);
+		bcm43xx_phy_write(bcm, 0x0036, 0x0400);
+
+		bcm43xx_ilt_write(bcm, 0x3807, 0x0051);
+
+		bcm43xx_phy_write(bcm, 0x001C, 0x0FF9);
+		bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F);
+		bcm43xx_ilt_write(bcm, 0x3C0C, 0x07BF);
+		bcm43xx_radio_write16(bcm, 0x0002, 0x07BF);
+
+		bcm43xx_phy_write(bcm, 0x0024, 0x4680);
+		bcm43xx_phy_write(bcm, 0x0020, 0x0003);
+		bcm43xx_phy_write(bcm, 0x001D, 0x0F40);
+		bcm43xx_phy_write(bcm, 0x001F, 0x1C00);
+
+		bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400);
+		bcm43xx_phy_write(bcm, 0x002B, bcm43xx_phy_read(bcm, 0x002B) & 0xFBFF);
+		bcm43xx_phy_write(bcm, 0x008E, 0x58C1);
+
+		bcm43xx_ilt_write(bcm, 0x0803, 0x000F);
+		bcm43xx_ilt_write(bcm, 0x0804, 0x001F);
+		bcm43xx_ilt_write(bcm, 0x0805, 0x002A);
+		bcm43xx_ilt_write(bcm, 0x0805, 0x0030);
+		bcm43xx_ilt_write(bcm, 0x0807, 0x003A);
+
+		bcm43xx_ilt_write(bcm, 0x0000, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0001, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0002, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0003, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0004, 0x0015);
+		bcm43xx_ilt_write(bcm, 0x0005, 0x0015);
+		bcm43xx_ilt_write(bcm, 0x0006, 0x0019);
+
+		bcm43xx_ilt_write(bcm, 0x0404, 0x0003);
+		bcm43xx_ilt_write(bcm, 0x0405, 0x0003);
+		bcm43xx_ilt_write(bcm, 0x0406, 0x0007);
+
+		for (i = 0; i < 16; i++)
+			bcm43xx_ilt_write(bcm, 0x4000 + i, (0x8 + i) & 0x000F);
+
+		bcm43xx_ilt_write(bcm, 0x3003, 0x1044);
+		bcm43xx_ilt_write(bcm, 0x3004, 0x7201);
+		bcm43xx_ilt_write(bcm, 0x3006, 0x0040);
+		bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008);
+
+		for (i = 0; i < BCM43xx_ILT_FINEFREQA_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]);
+		for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]);
+		for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]);
+		bcm43xx_phy_init_noisescaletbl(bcm);
+		for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
+		break;
+	case 3:
+		for (i = 0; i < 64; i++)
+			bcm43xx_ilt_write(bcm, 0x4000 + i, i);
+
+		bcm43xx_ilt_write(bcm, 0x3807, 0x0051);
+
+		bcm43xx_phy_write(bcm, 0x001C, 0x0FF9);
+		bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F);
+		bcm43xx_radio_write16(bcm, 0x0002, 0x07BF);
+
+		bcm43xx_phy_write(bcm, 0x0024, 0x4680);
+		bcm43xx_phy_write(bcm, 0x0020, 0x0003);
+		bcm43xx_phy_write(bcm, 0x001D, 0x0F40);
+		bcm43xx_phy_write(bcm, 0x001F, 0x1C00);
+		bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400);
+
+		bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008);
+		for (i = 0; i < BCM43xx_ILT_NOISEA3_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea3[i]);
+		bcm43xx_phy_init_noisescaletbl(bcm);
+		for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
+
+		bcm43xx_phy_write(bcm, 0x0003, 0x1808);
+
+		bcm43xx_ilt_write(bcm, 0x0803, 0x000F);
+		bcm43xx_ilt_write(bcm, 0x0804, 0x001F);
+		bcm43xx_ilt_write(bcm, 0x0805, 0x002A);
+		bcm43xx_ilt_write(bcm, 0x0805, 0x0030);
+		bcm43xx_ilt_write(bcm, 0x0807, 0x003A);
+
+		bcm43xx_ilt_write(bcm, 0x0000, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0001, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0002, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0003, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0004, 0x0015);
+		bcm43xx_ilt_write(bcm, 0x0005, 0x0015);
+		bcm43xx_ilt_write(bcm, 0x0006, 0x0019);
+
+		bcm43xx_ilt_write(bcm, 0x0404, 0x0003);
+		bcm43xx_ilt_write(bcm, 0x0405, 0x0003);
+		bcm43xx_ilt_write(bcm, 0x0406, 0x0007);
+
+		bcm43xx_ilt_write(bcm, 0x3C02, 0x000F);
+		bcm43xx_ilt_write(bcm, 0x3C03, 0x0014);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+/* Initialize APHY. This is also called for the GPHY in some cases. */
+static void bcm43xx_phy_inita(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 tval;
+
+	if (phy->type == BCM43xx_PHYTYPE_A) {
+		bcm43xx_phy_setupa(bcm);
+	} else {
+		bcm43xx_phy_setupg(bcm);
+		if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
+			bcm43xx_phy_write(bcm, 0x046E, 0x03CF);
+		return;
+	}
+
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS,
+	                  (bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) & 0xF83C) | 0x0340);
+	bcm43xx_phy_write(bcm, 0x0034, 0x0001);
+
+	TODO();//TODO: RSSI AGC
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS,
+	                  bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) | (1 << 14));
+	bcm43xx_radio_init2060(bcm);
+
+	if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM)
+	    && ((bcm->board_type == 0x0416) || (bcm->board_type == 0x040A))) {
+		if (radio->lofcal == 0xFFFF) {
+			TODO();//TODO: LOF Cal
+			bcm43xx_radio_set_tx_iq(bcm);
+		} else
+			bcm43xx_radio_write16(bcm, 0x001E, radio->lofcal);
+	}
+
+	bcm43xx_phy_write(bcm, 0x007A, 0xF111);
+
+	if (phy->savedpctlreg == 0xFFFF) {
+		bcm43xx_radio_write16(bcm, 0x0019, 0x0000);
+		bcm43xx_radio_write16(bcm, 0x0017, 0x0020);
+
+		tval = bcm43xx_ilt_read(bcm, 0x3001);
+		if (phy->rev == 1) {
+			bcm43xx_ilt_write(bcm, 0x3001,
+					  (bcm43xx_ilt_read(bcm, 0x3001) & 0xFF87)
+					  | 0x0058);
+		} else {
+			bcm43xx_ilt_write(bcm, 0x3001,
+					  (bcm43xx_ilt_read(bcm, 0x3001) & 0xFFC3)
+					  | 0x002C);
+		}
+		bcm43xx_dummy_transmission(bcm);
+		phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_A_PCTL);
+		bcm43xx_ilt_write(bcm, 0x3001, tval);
+
+		bcm43xx_radio_set_txpower_a(bcm, 0x0018);
+	}
+	bcm43xx_radio_clear_tssi(bcm);
+}
+
+static void bcm43xx_phy_initb2(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 offset, val;
+
+	bcm43xx_write16(bcm, 0x03EC, 0x3F22);
+	bcm43xx_phy_write(bcm, 0x0020, 0x301C);
+	bcm43xx_phy_write(bcm, 0x0026, 0x0000);
+	bcm43xx_phy_write(bcm, 0x0030, 0x00C6);
+	bcm43xx_phy_write(bcm, 0x0088, 0x3E00);
+	val = 0x3C3D;
+	for (offset = 0x0089; offset < 0x00A7; offset++) {
+		bcm43xx_phy_write(bcm, offset, val);
+		val -= 0x0202;
+	}
+	bcm43xx_phy_write(bcm, 0x03E4, 0x3000);
+	if (radio->channel == 0xFF)
+		bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
+	else
+		bcm43xx_radio_selectchannel(bcm, radio->channel, 0);
+	if (radio->version != 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0075, 0x0080);
+		bcm43xx_radio_write16(bcm, 0x0079, 0x0081);
+	}
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
+	if (radio->version == 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
+		bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
+		bcm43xx_radio_write16(bcm, 0x007A, 0x000F);
+		bcm43xx_phy_write(bcm, 0x0038, 0x0677);
+		bcm43xx_radio_init2050(bcm);
+	}
+	bcm43xx_phy_write(bcm, 0x0014, 0x0080);
+	bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
+	bcm43xx_phy_write(bcm, 0x0032, 0x00CC);
+	bcm43xx_phy_write(bcm, 0x0035, 0x07C2);
+	bcm43xx_phy_lo_b_measure(bcm);
+	bcm43xx_phy_write(bcm, 0x0026, 0xCC00);
+	if (radio->version != 0x2050)
+		bcm43xx_phy_write(bcm, 0x0026, 0xCE00);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1000);
+	bcm43xx_phy_write(bcm, 0x002A, 0x88A3);
+	if (radio->version != 0x2050)
+		bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
+	bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
+	bcm43xx_phy_init_pctl(bcm);
+}
+
+static void bcm43xx_phy_initb4(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 offset, val;
+
+	bcm43xx_write16(bcm, 0x03EC, 0x3F22);
+	bcm43xx_phy_write(bcm, 0x0020, 0x301C);
+	bcm43xx_phy_write(bcm, 0x0026, 0x0000);
+	bcm43xx_phy_write(bcm, 0x0030, 0x00C6);
+	bcm43xx_phy_write(bcm, 0x0088, 0x3E00);
+	val = 0x3C3D;
+	for (offset = 0x0089; offset < 0x00A7; offset++) {
+		bcm43xx_phy_write(bcm, offset, val);
+		val -= 0x0202;
+	}
+	bcm43xx_phy_write(bcm, 0x03E4, 0x3000);
+	if (radio->channel == 0xFF)
+		bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
+	else
+		bcm43xx_radio_selectchannel(bcm, radio->channel, 0);
+	if (radio->version != 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0075, 0x0080);
+		bcm43xx_radio_write16(bcm, 0x0079, 0x0081);
+	}
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
+	if (radio->version == 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
+		bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
+		bcm43xx_radio_write16(bcm, 0x007A, 0x000F);
+		bcm43xx_phy_write(bcm, 0x0038, 0x0677);
+		bcm43xx_radio_init2050(bcm);
+	}
+	bcm43xx_phy_write(bcm, 0x0014, 0x0080);
+	bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
+	if (radio->version == 0x2050)
+		bcm43xx_phy_write(bcm, 0x0032, 0x00E0);
+	bcm43xx_phy_write(bcm, 0x0035, 0x07C2);
+
+	bcm43xx_phy_lo_b_measure(bcm);
+
+	bcm43xx_phy_write(bcm, 0x0026, 0xCC00);
+	if (radio->version == 0x2050)
+		bcm43xx_phy_write(bcm, 0x0026, 0xCE00);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1100);
+	bcm43xx_phy_write(bcm, 0x002A, 0x88A3);
+	if (radio->version == 0x2050)
+		bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
+	bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
+	if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
+		bcm43xx_calc_nrssi_slope(bcm);
+		bcm43xx_calc_nrssi_threshold(bcm);
+	}
+	bcm43xx_phy_init_pctl(bcm);
+}
+
+static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 offset;
+
+	if (phy->version == 1 &&
+	    radio->version == 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A)
+				      | 0x0050);
+	}
+	if ((bcm->board_vendor != PCI_VENDOR_ID_BROADCOM) &&
+	    (bcm->board_type != 0x0416)) {
+		for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
+			bcm43xx_phy_write(bcm, offset,
+					  (bcm43xx_phy_read(bcm, offset) + 0x2020)
+					  & 0x3F3F);
+		}
+	}
+	bcm43xx_phy_write(bcm, 0x0035,
+			  (bcm43xx_phy_read(bcm, 0x0035) & 0xF0FF)
+			  | 0x0700);
+	if (radio->version == 0x2050)
+		bcm43xx_phy_write(bcm, 0x0038, 0x0667);
+
+	if (phy->connected) {
+		if (radio->version == 0x2050) {
+			bcm43xx_radio_write16(bcm, 0x007A,
+					      bcm43xx_radio_read16(bcm, 0x007A)
+					      | 0x0020);
+			bcm43xx_radio_write16(bcm, 0x0051,
+					      bcm43xx_radio_read16(bcm, 0x0051)
+					      | 0x0004);
+		}
+		bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, 0x0000);
+
+		bcm43xx_phy_write(bcm, 0x0802, bcm43xx_phy_read(bcm, 0x0802) | 0x0100);
+		bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x2000);
+
+		bcm43xx_phy_write(bcm, 0x001C, 0x186A);
+
+		bcm43xx_phy_write(bcm, 0x0013, (bcm43xx_phy_read(bcm, 0x0013) & 0x00FF) | 0x1900);
+		bcm43xx_phy_write(bcm, 0x0035, (bcm43xx_phy_read(bcm, 0x0035) & 0xFFC0) | 0x0064);
+		bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D) & 0xFF80) | 0x000A);
+	}
+
+	if (bcm->bad_frames_preempt) {
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
+				  bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | (1 << 11));
+	}
+
+	if (phy->version == 1 && radio->version == 0x2050) {
+		bcm43xx_phy_write(bcm, 0x0026, 0xCE00);
+		bcm43xx_phy_write(bcm, 0x0021, 0x3763);
+		bcm43xx_phy_write(bcm, 0x0022, 0x1BC3);
+		bcm43xx_phy_write(bcm, 0x0023, 0x06F9);
+		bcm43xx_phy_write(bcm, 0x0024, 0x037E);
+	} else
+		bcm43xx_phy_write(bcm, 0x0026, 0xCC00);
+	bcm43xx_phy_write(bcm, 0x0030, 0x00C6);
+	bcm43xx_write16(bcm, 0x03EC, 0x3F22);
+
+	if (phy->version == 1 && radio->version == 0x2050)
+		bcm43xx_phy_write(bcm, 0x0020, 0x3E1C);
+	else
+		bcm43xx_phy_write(bcm, 0x0020, 0x301C);
+
+	if (phy->version == 0)
+		bcm43xx_write16(bcm, 0x03E4, 0x3000);
+
+	/* Force to channel 7, even if not supported. */
+	bcm43xx_radio_selectchannel(bcm, 7, 0);
+
+	if (radio->version != 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0075, 0x0080);
+		bcm43xx_radio_write16(bcm, 0x0079, 0x0081);
+	}
+
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
+
+	if (radio->version == 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
+	}
+
+	bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
+	bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
+
+	bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0007);
+
+	bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
+
+	bcm43xx_phy_write(bcm, 0x0014, 0x0080);
+	bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
+	bcm43xx_phy_write(bcm, 0x88A3, 0x002A);
+
+	bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
+
+	if (radio->version == 0x2050)
+		bcm43xx_radio_write16(bcm, 0x005D, 0x000D);
+
+	bcm43xx_write16(bcm, 0x03E4, (bcm43xx_read16(bcm, 0x03E4) & 0xFFC0) | 0x0004);
+}
+
+static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 offset, val;
+
+	bcm43xx_phy_write(bcm, 0x003E, 0x817A);
+	bcm43xx_radio_write16(bcm, 0x007A,
+	                      (bcm43xx_radio_read16(bcm, 0x007A) | 0x0058));
+	if ((radio->manufact == 0x17F) &&
+	    (radio->version == 0x2050) &&
+	    (radio->revision == 3 ||
+	     radio->revision == 4 ||
+	     radio->revision == 5)) {
+		bcm43xx_radio_write16(bcm, 0x0051, 0x001F);
+		bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
+		bcm43xx_radio_write16(bcm, 0x0053, 0x005B);
+		bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005D, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005E, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x007D, 0x0088);
+	}
+	if ((radio->manufact == 0x17F) &&
+	    (radio->version == 0x2050) &&
+	    (radio->revision == 6)) {
+		bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
+		bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
+		bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
+		bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x008B);
+		bcm43xx_radio_write16(bcm, 0x005C, 0x00B5);
+		bcm43xx_radio_write16(bcm, 0x005D, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005E, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x007D, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
+		bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
+	}
+	if ((radio->manufact == 0x17F) &&
+	    (radio->version == 0x2050) &&
+	    (radio->revision == 7)) {
+		bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
+		bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
+		bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
+		bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x00A8);
+		bcm43xx_radio_write16(bcm, 0x005C, 0x0075);
+		bcm43xx_radio_write16(bcm, 0x005D, 0x00F5);
+		bcm43xx_radio_write16(bcm, 0x005E, 0x00B8);
+		bcm43xx_radio_write16(bcm, 0x007D, 0x00E8);
+		bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
+		bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
+		bcm43xx_radio_write16(bcm, 0x007B, 0x0000);
+	}
+	if ((radio->manufact == 0x17F) &&
+	    (radio->version == 0x2050) &&
+	    (radio->revision == 8)) {
+		bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
+		bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
+		bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
+		bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x006B);
+		bcm43xx_radio_write16(bcm, 0x005C, 0x000F);
+		if (bcm->sprom.boardflags & 0x8000) {
+			bcm43xx_radio_write16(bcm, 0x005D, 0x00FA);
+			bcm43xx_radio_write16(bcm, 0x005E, 0x00D8);
+		} else {
+			bcm43xx_radio_write16(bcm, 0x005D, 0x00F5);
+			bcm43xx_radio_write16(bcm, 0x005E, 0x00B8);
+		}
+		bcm43xx_radio_write16(bcm, 0x0073, 0x0003);
+		bcm43xx_radio_write16(bcm, 0x007D, 0x00A8);
+		bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
+		bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
+	}
+	val = 0x1E1F;
+	for (offset = 0x0088; offset < 0x0098; offset++) {
+		bcm43xx_phy_write(bcm, offset, val);
+		val -= 0x0202;
+	}
+	val = 0x3E3F;
+	for (offset = 0x0098; offset < 0x00A8; offset++) {
+		bcm43xx_phy_write(bcm, offset, val);
+		val -= 0x0202;
+	}
+	val = 0x2120;
+	for (offset = 0x00A8; offset < 0x00C8; offset++) {
+		bcm43xx_phy_write(bcm, offset, (val & 0x3F3F));
+		val += 0x0202;
+	}
+	if (phy->type == BCM43xx_PHYTYPE_G) {
+		bcm43xx_radio_write16(bcm, 0x007A,
+		                      bcm43xx_radio_read16(bcm, 0x007A) | 0x0020);
+		bcm43xx_radio_write16(bcm, 0x0051,
+		                      bcm43xx_radio_read16(bcm, 0x0051) | 0x0004);
+		bcm43xx_phy_write(bcm, 0x0802,
+		                  bcm43xx_phy_read(bcm, 0x0802) | 0x0100);
+		bcm43xx_phy_write(bcm, 0x042B,
+		                  bcm43xx_phy_read(bcm, 0x042B) | 0x2000);
+	}
+
+	/* Force to channel 7, even if not supported. */
+	bcm43xx_radio_selectchannel(bcm, 7, 0);
+
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
+	udelay(40);
+	bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) | 0x0002));
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+	if (radio->manufact == 0x17F &&
+	    radio->version == 0x2050 &&
+	    radio->revision <= 2) {
+		bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
+		bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
+	}
+	bcm43xx_radio_write16(bcm, 0x007A,
+	                      (bcm43xx_radio_read16(bcm, 0x007A) & 0x00F8) | 0x0007);
+
+	bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
+
+	bcm43xx_phy_write(bcm, 0x0014, 0x0200);
+	if (radio->version == 0x2050){
+		if (radio->revision == 3 ||
+		    radio->revision == 4 ||
+		    radio->revision == 5)
+			bcm43xx_phy_write(bcm, 0x002A, 0x8AC0);
+		else
+			bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
+	}
+	bcm43xx_phy_write(bcm, 0x0038, 0x0668);
+	bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
+	if (radio->version == 0x2050) {
+		if (radio->revision == 3 ||
+		    radio->revision == 4 ||
+		    radio->revision == 5)
+			bcm43xx_phy_write(bcm, 0x005D, bcm43xx_phy_read(bcm, 0x005D) | 0x0003);
+		else if (radio->revision <= 2)
+			bcm43xx_radio_write16(bcm, 0x005D, 0x000D);
+	}
+	
+	if (phy->rev == 4)
+		bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004);
+	else
+		bcm43xx_write16(bcm, 0x03E4, 0x0009);
+	if (phy->type == BCM43xx_PHYTYPE_B) {
+		bcm43xx_write16(bcm, 0x03E6, 0x8140);
+		bcm43xx_phy_write(bcm, 0x0016, 0x0410);
+		bcm43xx_phy_write(bcm, 0x0017, 0x0820);
+		bcm43xx_phy_write(bcm, 0x0062, 0x0007);
+		(void) bcm43xx_radio_calibrationvalue(bcm);
+		bcm43xx_phy_lo_b_measure(bcm);
+		if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
+			bcm43xx_calc_nrssi_slope(bcm);
+			bcm43xx_calc_nrssi_threshold(bcm);
+		}
+		bcm43xx_phy_init_pctl(bcm);
+	} else
+		bcm43xx_write16(bcm, 0x03E6, 0x0);
+}
+
+static void bcm43xx_calc_loopback_gain(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 backup_phy[15];
+	u16 backup_radio[3];
+	u16 backup_bband;
+	u16 i;
+	u16 loop1_cnt, loop1_done, loop1_omitted;
+	u16 loop2_done;
+
+	backup_phy[0] = bcm43xx_phy_read(bcm, 0x0429);
+	backup_phy[1] = bcm43xx_phy_read(bcm, 0x0001);
+	backup_phy[2] = bcm43xx_phy_read(bcm, 0x0811);
+	backup_phy[3] = bcm43xx_phy_read(bcm, 0x0812);
+	backup_phy[4] = bcm43xx_phy_read(bcm, 0x0814);
+	backup_phy[5] = bcm43xx_phy_read(bcm, 0x0815);
+	backup_phy[6] = bcm43xx_phy_read(bcm, 0x005A);
+	backup_phy[7] = bcm43xx_phy_read(bcm, 0x0059);
+	backup_phy[8] = bcm43xx_phy_read(bcm, 0x0058);
+	backup_phy[9] = bcm43xx_phy_read(bcm, 0x000A);
+	backup_phy[10] = bcm43xx_phy_read(bcm, 0x0003);
+	backup_phy[11] = bcm43xx_phy_read(bcm, 0x080F);
+	backup_phy[12] = bcm43xx_phy_read(bcm, 0x0810);
+	backup_phy[13] = bcm43xx_phy_read(bcm, 0x002B);
+	backup_phy[14] = bcm43xx_phy_read(bcm, 0x0015);
+	bcm43xx_phy_read(bcm, 0x002D); /* dummy read */
+	backup_bband = radio->baseband_atten;
+	backup_radio[0] = bcm43xx_radio_read16(bcm, 0x0052);
+	backup_radio[1] = bcm43xx_radio_read16(bcm, 0x0043);
+	backup_radio[2] = bcm43xx_radio_read16(bcm, 0x007A);
+
+	bcm43xx_phy_write(bcm, 0x0429,
+			  bcm43xx_phy_read(bcm, 0x0429) & 0x3FFF);
+	bcm43xx_phy_write(bcm, 0x0001,
+			  bcm43xx_phy_read(bcm, 0x0001) & 0x8000);
+	bcm43xx_phy_write(bcm, 0x0811,
+			  bcm43xx_phy_read(bcm, 0x0811) | 0x0002);
+	bcm43xx_phy_write(bcm, 0x0812,
+			  bcm43xx_phy_read(bcm, 0x0812) & 0xFFFD);
+	bcm43xx_phy_write(bcm, 0x0811,
+			  bcm43xx_phy_read(bcm, 0x0811) | 0x0001);
+	bcm43xx_phy_write(bcm, 0x0812,
+			  bcm43xx_phy_read(bcm, 0x0812) & 0xFFFE);
+	bcm43xx_phy_write(bcm, 0x0814,
+			  bcm43xx_phy_read(bcm, 0x0814) | 0x0001);
+	bcm43xx_phy_write(bcm, 0x0815,
+			  bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE);
+	bcm43xx_phy_write(bcm, 0x0814,
+			  bcm43xx_phy_read(bcm, 0x0814) | 0x0002);
+	bcm43xx_phy_write(bcm, 0x0815,
+			  bcm43xx_phy_read(bcm, 0x0815) & 0xFFFD);
+	bcm43xx_phy_write(bcm, 0x0811,
+			  bcm43xx_phy_read(bcm, 0x0811) | 0x000C);
+	bcm43xx_phy_write(bcm, 0x0812,
+			  bcm43xx_phy_read(bcm, 0x0812) | 0x000C);
+
+	bcm43xx_phy_write(bcm, 0x0811,
+			  (bcm43xx_phy_read(bcm, 0x0811)
+			   & 0xFFCF) | 0x0030);
+	bcm43xx_phy_write(bcm, 0x0812,
+			  (bcm43xx_phy_read(bcm, 0x0812)
+			   & 0xFFCF) | 0x0010);
+
+	bcm43xx_phy_write(bcm, 0x005A, 0x0780);
+	bcm43xx_phy_write(bcm, 0x0059, 0xC810);
+	bcm43xx_phy_write(bcm, 0x0058, 0x000D);
+	if (phy->version == 0) {
+		bcm43xx_phy_write(bcm, 0x0003, 0x0122);
+	} else {
+		bcm43xx_phy_write(bcm, 0x000A,
+				  bcm43xx_phy_read(bcm, 0x000A)
+				  | 0x2000);
+	}
+	bcm43xx_phy_write(bcm, 0x0814,
+			  bcm43xx_phy_read(bcm, 0x0814) | 0x0004);
+	bcm43xx_phy_write(bcm, 0x0815,
+			  bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB);
+	bcm43xx_phy_write(bcm, 0x0003,
+			  (bcm43xx_phy_read(bcm, 0x0003)
+			   & 0xFF9F) | 0x0040);
+	if (radio->version == 0x2050 && radio->revision == 2) {
+		bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
+		bcm43xx_radio_write16(bcm, 0x0043,
+				      (bcm43xx_radio_read16(bcm, 0x0043)
+				       & 0xFFF0) | 0x0009);
+		loop1_cnt = 9;
+	} else if (radio->revision == 8) {
+		bcm43xx_radio_write16(bcm, 0x0043, 0x000F);
+		loop1_cnt = 15;
+	} else
+		loop1_cnt = 0;
+
+	bcm43xx_phy_set_baseband_attenuation(bcm, 11);
+
+	if (phy->rev >= 3)
+		bcm43xx_phy_write(bcm, 0x080F, 0xC020);
+	else
+		bcm43xx_phy_write(bcm, 0x080F, 0x8020);
+	bcm43xx_phy_write(bcm, 0x0810, 0x0000);
+
+	bcm43xx_phy_write(bcm, 0x002B,
+			  (bcm43xx_phy_read(bcm, 0x002B)
+			   & 0xFFC0) | 0x0001);
+	bcm43xx_phy_write(bcm, 0x002B,
+			  (bcm43xx_phy_read(bcm, 0x002B)
+			   & 0xC0FF) | 0x0800);
+	bcm43xx_phy_write(bcm, 0x0811,
+			  bcm43xx_phy_read(bcm, 0x0811) | 0x0100);
+	bcm43xx_phy_write(bcm, 0x0812,
+			  bcm43xx_phy_read(bcm, 0x0812) & 0xCFFF);
+	if (bcm->sprom.boardflags & BCM43xx_BFL_EXTLNA) {
+		if (phy->rev >= 7) {
+			bcm43xx_phy_write(bcm, 0x0811,
+					  bcm43xx_phy_read(bcm, 0x0811)
+					  | 0x0800);
+			bcm43xx_phy_write(bcm, 0x0812,
+					  bcm43xx_phy_read(bcm, 0x0812)
+					  | 0x8000);
+		}
+	}
+	bcm43xx_radio_write16(bcm, 0x007A,
+			      bcm43xx_radio_read16(bcm, 0x007A)
+			      & 0x00F7);
+
+	for (i = 0; i < loop1_cnt; i++) {
+		bcm43xx_radio_write16(bcm, 0x0043, loop1_cnt);
+		bcm43xx_phy_write(bcm, 0x0812,
+				  (bcm43xx_phy_read(bcm, 0x0812)
+				   & 0xF0FF) | (i << 8));
+		bcm43xx_phy_write(bcm, 0x0015,
+				  (bcm43xx_phy_read(bcm, 0x0015)
+				   & 0x0FFF) | 0xA000);
+		bcm43xx_phy_write(bcm, 0x0015,
+				  (bcm43xx_phy_read(bcm, 0x0015)
+				   & 0x0FFF) | 0xF000);
+		udelay(20);
+		if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC)
+			break;
+	}
+	loop1_done = i;
+	loop1_omitted = loop1_cnt - loop1_done;
+
+	loop2_done = 0;
+	if (loop1_done >= 8) {
+		bcm43xx_phy_write(bcm, 0x0812,
+				  bcm43xx_phy_read(bcm, 0x0812)
+				  | 0x0030);
+		for (i = loop1_done - 8; i < 16; i++) {
+			bcm43xx_phy_write(bcm, 0x0812,
+					  (bcm43xx_phy_read(bcm, 0x0812)
+					   & 0xF0FF) | (i << 8));
+			bcm43xx_phy_write(bcm, 0x0015,
+					  (bcm43xx_phy_read(bcm, 0x0015)
+					   & 0x0FFF) | 0xA000);
+			bcm43xx_phy_write(bcm, 0x0015,
+					  (bcm43xx_phy_read(bcm, 0x0015)
+					   & 0x0FFF) | 0xF000);
+			udelay(20);
+			if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC)
+				break;
+		}
+	}
+
+	bcm43xx_phy_write(bcm, 0x0814, backup_phy[4]);
+	bcm43xx_phy_write(bcm, 0x0815, backup_phy[5]);
+	bcm43xx_phy_write(bcm, 0x005A, backup_phy[6]);
+	bcm43xx_phy_write(bcm, 0x0059, backup_phy[7]);
+	bcm43xx_phy_write(bcm, 0x0058, backup_phy[8]);
+	bcm43xx_phy_write(bcm, 0x000A, backup_phy[9]);
+	bcm43xx_phy_write(bcm, 0x0003, backup_phy[10]);
+	bcm43xx_phy_write(bcm, 0x080F, backup_phy[11]);
+	bcm43xx_phy_write(bcm, 0x0810, backup_phy[12]);
+	bcm43xx_phy_write(bcm, 0x002B, backup_phy[13]);
+	bcm43xx_phy_write(bcm, 0x0015, backup_phy[14]);
+
+	bcm43xx_phy_set_baseband_attenuation(bcm, backup_bband);
+
+	bcm43xx_radio_write16(bcm, 0x0052, backup_radio[0]);
+	bcm43xx_radio_write16(bcm, 0x0043, backup_radio[1]);
+	bcm43xx_radio_write16(bcm, 0x007A, backup_radio[2]);
+
+	bcm43xx_phy_write(bcm, 0x0811, backup_phy[2] | 0x0003);
+	udelay(10);
+	bcm43xx_phy_write(bcm, 0x0811, backup_phy[2]);
+	bcm43xx_phy_write(bcm, 0x0812, backup_phy[3]);
+	bcm43xx_phy_write(bcm, 0x0429, backup_phy[0]);
+	bcm43xx_phy_write(bcm, 0x0001, backup_phy[1]);
+
+	phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11;
+	phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2;
+}
+
+static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 tmp;
+
+	if (phy->rev == 1)
+		bcm43xx_phy_initb5(bcm);
+	else if (phy->rev >= 2 && phy->rev <= 7)
+		bcm43xx_phy_initb6(bcm);
+	if (phy->rev >= 2 || phy->connected)
+		bcm43xx_phy_inita(bcm);
+
+	if (phy->rev >= 2) {
+		bcm43xx_phy_write(bcm, 0x0814, 0x0000);
+		bcm43xx_phy_write(bcm, 0x0815, 0x0000);
+		if (phy->rev == 2)
+			bcm43xx_phy_write(bcm, 0x0811, 0x0000);
+		else if (phy->rev >= 3)
+			bcm43xx_phy_write(bcm, 0x0811, 0x0400);
+		bcm43xx_phy_write(bcm, 0x0015, 0x00C0);
+		if (phy->connected) {
+			tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF;
+			if (tmp < 6) {
+				bcm43xx_phy_write(bcm, 0x04C2, 0x1816);
+				bcm43xx_phy_write(bcm, 0x04C3, 0x8006);
+				if (tmp != 3) {
+					bcm43xx_phy_write(bcm, 0x04CC,
+							  (bcm43xx_phy_read(bcm, 0x04CC)
+							   & 0x00FF) | 0x1F00);
+				}
+			}
+		}
+	}
+	if (phy->rev < 3 && phy->connected)
+		bcm43xx_phy_write(bcm, 0x047E, 0x0078);
+	if (phy->rev >= 6 && phy->rev <= 8) {
+		bcm43xx_phy_write(bcm, 0x0801, bcm43xx_phy_read(bcm, 0x0801) | 0x0080);
+		bcm43xx_phy_write(bcm, 0x043E, bcm43xx_phy_read(bcm, 0x043E) | 0x0004);
+	}
+	if (phy->rev >= 2 && phy->connected)
+		bcm43xx_calc_loopback_gain(bcm);
+	if (radio->revision != 8) {
+		if (radio->initval == 0xFFFF)
+			radio->initval = bcm43xx_radio_init2050(bcm);
+		else
+			bcm43xx_radio_write16(bcm, 0x0078, radio->initval);
+	}
+	if (radio->txctl2 == 0xFFFF) {
+		bcm43xx_phy_lo_g_measure(bcm);
+	} else {
+		if (radio->version == 0x2050 && radio->revision == 8) {
+			//FIXME
+		} else {
+			bcm43xx_radio_write16(bcm, 0x0052,
+					      (bcm43xx_radio_read16(bcm, 0x0052)
+					       & 0xFFF0) | radio->txctl1);
+		}
+		if (phy->rev >= 6) {
+			/*
+			bcm43xx_phy_write(bcm, 0x0036,
+					  (bcm43xx_phy_read(bcm, 0x0036)
+					   & 0xF000) | (FIXME << 12));
+			*/
+		}
+		if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
+			bcm43xx_phy_write(bcm, 0x002E, 0x8075);
+		else
+			bcm43xx_phy_write(bcm, 0x003E, 0x807F);
+		if (phy->rev < 2)
+			bcm43xx_phy_write(bcm, 0x002F, 0x0101);
+		else
+			bcm43xx_phy_write(bcm, 0x002F, 0x0202);
+	}
+	if (phy->connected) {
+		bcm43xx_phy_lo_adjust(bcm, 0);
+		bcm43xx_phy_write(bcm, 0x080F, 0x8078);
+	}
+
+	if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) {
+		/* The specs state to update the NRSSI LT with
+		 * the value 0x7FFFFFFF here. I think that is some weird
+		 * compiler optimization in the original driver.
+		 * Essentially, what we do here is resetting all NRSSI LT
+		 * entries to -32 (see the limit_value() in nrssi_hw_update())
+		 */
+		bcm43xx_nrssi_hw_update(bcm, 0xFFFF);
+		bcm43xx_calc_nrssi_threshold(bcm);
+	} else if (phy->connected) {
+		if (radio->nrssi[0] == -1000) {
+			assert(radio->nrssi[1] == -1000);
+			bcm43xx_calc_nrssi_slope(bcm);
+		} else {
+			assert(radio->nrssi[1] != -1000);
+			bcm43xx_calc_nrssi_threshold(bcm);
+		}
+	}
+	if (radio->revision == 8)
+		bcm43xx_phy_write(bcm, 0x0805, 0x3230);
+	bcm43xx_phy_init_pctl(bcm);
+	if (bcm->chip_id == 0x4306 && bcm->chip_package != 2) {
+		bcm43xx_phy_write(bcm, 0x0429,
+				  bcm43xx_phy_read(bcm, 0x0429) & 0xBFFF);
+		bcm43xx_phy_write(bcm, 0x04C3,
+				  bcm43xx_phy_read(bcm, 0x04C3) & 0x7FFF);
+	}
+}
+
+static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
+{
+	int i;
+	u16 ret = 0;
+
+	for (i = 0; i < 10; i++){
+		bcm43xx_phy_write(bcm, 0x0015, 0xAFA0);
+		udelay(1);
+		bcm43xx_phy_write(bcm, 0x0015, 0xEFA0);
+		udelay(10);
+		bcm43xx_phy_write(bcm, 0x0015, 0xFFA0);
+		udelay(40);
+		ret += bcm43xx_phy_read(bcm, 0x002C);
+	}
+
+	return ret;
+}
+
+void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 regstack[12] = { 0 };
+	u16 mls;
+	u16 fval;
+	int i, j;
+
+	regstack[0] = bcm43xx_phy_read(bcm, 0x0015);
+	regstack[1] = bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0;
+
+	if (radio->version == 0x2053) {
+		regstack[2] = bcm43xx_phy_read(bcm, 0x000A);
+		regstack[3] = bcm43xx_phy_read(bcm, 0x002A);
+		regstack[4] = bcm43xx_phy_read(bcm, 0x0035);
+		regstack[5] = bcm43xx_phy_read(bcm, 0x0003);
+		regstack[6] = bcm43xx_phy_read(bcm, 0x0001);
+		regstack[7] = bcm43xx_phy_read(bcm, 0x0030);
+
+		regstack[8] = bcm43xx_radio_read16(bcm, 0x0043);
+		regstack[9] = bcm43xx_radio_read16(bcm, 0x007A);
+		regstack[10] = bcm43xx_read16(bcm, 0x03EC);
+		regstack[11] = bcm43xx_radio_read16(bcm, 0x0052) & 0x00F0;
+
+		bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
+		bcm43xx_write16(bcm, 0x03EC, 0x3F3F);
+		bcm43xx_phy_write(bcm, 0x0035, regstack[4] & 0xFF7F);
+		bcm43xx_radio_write16(bcm, 0x007A, regstack[9] & 0xFFF0);
+	}
+	bcm43xx_phy_write(bcm, 0x0015, 0xB000);
+	bcm43xx_phy_write(bcm, 0x002B, 0x0004);
+
+	if (radio->version == 0x2053) {
+		bcm43xx_phy_write(bcm, 0x002B, 0x0203);
+		bcm43xx_phy_write(bcm, 0x002A, 0x08A3);
+	}
+
+	phy->minlowsig[0] = 0xFFFF;
+
+	for (i = 0; i < 4; i++) {
+		bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i);
+		bcm43xx_phy_lo_b_r15_loop(bcm);
+	}
+	for (i = 0; i < 10; i++) {
+		bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i);
+		mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10;
+		if (mls < phy->minlowsig[0]) {
+			phy->minlowsig[0] = mls;
+			phy->minlowsigpos[0] = i;
+		}
+	}
+	bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | phy->minlowsigpos[0]);
+
+	phy->minlowsig[1] = 0xFFFF;
+
+	for (i = -4; i < 5; i += 2) {
+		for (j = -4; j < 5; j += 2) {
+			if (j < 0)
+				fval = (0x0100 * i) + j + 0x0100;
+			else
+				fval = (0x0100 * i) + j;
+			bcm43xx_phy_write(bcm, 0x002F, fval);
+			mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10;
+			if (mls < phy->minlowsig[1]) {
+				phy->minlowsig[1] = mls;
+				phy->minlowsigpos[1] = fval;
+			}
+		}
+	}
+	phy->minlowsigpos[1] += 0x0101;
+
+	bcm43xx_phy_write(bcm, 0x002F, phy->minlowsigpos[1]);
+	if (radio->version == 0x2053) {
+		bcm43xx_phy_write(bcm, 0x000A, regstack[2]);
+		bcm43xx_phy_write(bcm, 0x002A, regstack[3]);
+		bcm43xx_phy_write(bcm, 0x0035, regstack[4]);
+		bcm43xx_phy_write(bcm, 0x0003, regstack[5]);
+		bcm43xx_phy_write(bcm, 0x0001, regstack[6]);
+		bcm43xx_phy_write(bcm, 0x0030, regstack[7]);
+
+		bcm43xx_radio_write16(bcm, 0x0043, regstack[8]);
+		bcm43xx_radio_write16(bcm, 0x007A, regstack[9]);
+
+		bcm43xx_radio_write16(bcm, 0x0052,
+		                      (bcm43xx_radio_read16(bcm, 0x0052) & 0x000F)
+				      | regstack[11]);
+
+		bcm43xx_write16(bcm, 0x03EC, regstack[10]);
+	}
+	bcm43xx_phy_write(bcm, 0x0015, regstack[0]);
+}
+
+static inline
+u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	if (phy->connected) {
+		bcm43xx_phy_write(bcm, 0x15, 0xE300);
+		control <<= 8;
+		bcm43xx_phy_write(bcm, 0x0812, control | 0x00B0);
+		udelay(5);
+		bcm43xx_phy_write(bcm, 0x0812, control | 0x00B2);
+		udelay(2);
+		bcm43xx_phy_write(bcm, 0x0812, control | 0x00B3);
+		udelay(4);
+		bcm43xx_phy_write(bcm, 0x0015, 0xF300);
+		udelay(8);
+	} else {
+		bcm43xx_phy_write(bcm, 0x0015, control | 0xEFA0);
+		udelay(2);
+		bcm43xx_phy_write(bcm, 0x0015, control | 0xEFE0);
+		udelay(4);
+		bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0);
+		udelay(8);
+	}
+
+	return bcm43xx_phy_read(bcm, 0x002D);
+}
+
+static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control)
+{
+	int i;
+	u32 ret = 0;
+
+	for (i = 0; i < 8; i++)
+		ret += bcm43xx_phy_lo_g_deviation_subval(bcm, control);
+
+	return ret;
+}
+
+/* Write the LocalOscillator CONTROL */
+static inline
+void bcm43xx_lo_write(struct bcm43xx_private *bcm,
+		      struct bcm43xx_lopair *pair)
+{
+	u16 value;
+
+	value = (u8)(pair->low);
+	value |= ((u8)(pair->high)) << 8;
+
+#ifdef CONFIG_BCM43XX_DEBUG
+	/* Sanity check. */
+	if (pair->low < -8 || pair->low > 8 ||
+	    pair->high < -8 || pair->high > 8) {
+		printk(KERN_WARNING PFX
+		       "WARNING: Writing invalid LOpair "
+		       "(low: %d, high: %d, index: %lu)\n",
+		       pair->low, pair->high,
+		       (unsigned long)(pair - bcm43xx_current_phy(bcm)->_lo_pairs));
+		dump_stack();
+	}
+#endif
+
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, value);
+}
+
+static inline
+struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm,
+					    u16 baseband_attenuation,
+					    u16 radio_attenuation,
+					    u16 tx)
+{
+	static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 };
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	if (baseband_attenuation > 6)
+		baseband_attenuation = 6;
+	assert(radio_attenuation < 10);
+
+	if (tx == 3) {
+		return bcm43xx_get_lopair(phy,
+					  radio_attenuation,
+					  baseband_attenuation);
+	}
+	return bcm43xx_get_lopair(phy, dict[radio_attenuation], baseband_attenuation);
+}
+
+static inline
+struct bcm43xx_lopair * bcm43xx_current_lopair(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	return bcm43xx_find_lopair(bcm,
+				   radio->baseband_atten,
+				   radio->radio_atten,
+				   radio->txctl1);
+}
+
+/* Adjust B/G LO */
+void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed)
+{
+	struct bcm43xx_lopair *pair;
+
+	if (fixed) {
+		/* Use fixed values. Only for initialization. */
+		pair = bcm43xx_find_lopair(bcm, 2, 3, 0);
+	} else
+		pair = bcm43xx_current_lopair(bcm);
+	bcm43xx_lo_write(bcm, pair);
+}
+
+static void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 txctl2 = 0, i;
+	u32 smallest, tmp;
+
+	bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
+	udelay(10);
+	smallest = bcm43xx_phy_lo_g_singledeviation(bcm, 0);
+	for (i = 0; i < 16; i++) {
+		bcm43xx_radio_write16(bcm, 0x0052, i);
+		udelay(10);
+		tmp = bcm43xx_phy_lo_g_singledeviation(bcm, 0);
+		if (tmp < smallest) {
+			smallest = tmp;
+			txctl2 = i;
+		}
+	}
+	radio->txctl2 = txctl2;
+}
+
+static
+void bcm43xx_phy_lo_g_state(struct bcm43xx_private *bcm,
+			    const struct bcm43xx_lopair *in_pair,
+			    struct bcm43xx_lopair *out_pair,
+			    u16 r27)
+{
+	static const struct bcm43xx_lopair transitions[8] = {
+		{ .high =  1,  .low =  1, },
+		{ .high =  1,  .low =  0, },
+		{ .high =  1,  .low = -1, },
+		{ .high =  0,  .low = -1, },
+		{ .high = -1,  .low = -1, },
+		{ .high = -1,  .low =  0, },
+		{ .high = -1,  .low =  1, },
+		{ .high =  0,  .low =  1, },
+	};
+	struct bcm43xx_lopair lowest_transition = {
+		.high = in_pair->high,
+		.low = in_pair->low,
+	};
+	struct bcm43xx_lopair tmp_pair;
+	struct bcm43xx_lopair transition;
+	int i = 12;
+	int state = 0;
+	int found_lower;
+	int j, begin, end;
+	u32 lowest_deviation;
+	u32 tmp;
+
+	/* Note that in_pair and out_pair can point to the same pair. Be careful. */
+
+	bcm43xx_lo_write(bcm, &lowest_transition);
+	lowest_deviation = bcm43xx_phy_lo_g_singledeviation(bcm, r27);
+	do {
+		found_lower = 0;
+		assert(state >= 0 && state <= 8);
+		if (state == 0) {
+			begin = 1;
+			end = 8;
+		} else if (state % 2 == 0) {
+			begin = state - 1;
+			end = state + 1;
+		} else {
+			begin = state - 2;
+			end = state + 2;
+		}
+		if (begin < 1)
+			begin += 8;
+		if (end > 8)
+			end -= 8;
+
+		j = begin;
+		tmp_pair.high = lowest_transition.high;
+		tmp_pair.low = lowest_transition.low;
+		while (1) {
+			assert(j >= 1 && j <= 8);
+			transition.high = tmp_pair.high + transitions[j - 1].high;
+			transition.low = tmp_pair.low + transitions[j - 1].low;
+			if ((abs(transition.low) < 9) && (abs(transition.high) < 9)) {
+				bcm43xx_lo_write(bcm, &transition);
+				tmp = bcm43xx_phy_lo_g_singledeviation(bcm, r27);
+				if (tmp < lowest_deviation) {
+					lowest_deviation = tmp;
+					state = j;
+					found_lower = 1;
+
+					lowest_transition.high = transition.high;
+					lowest_transition.low = transition.low;
+				}
+			}
+			if (j == end)
+				break;
+			if (j == 8)
+				j = 1;
+			else
+				j++;
+		}
+	} while (i-- && found_lower);
+
+	out_pair->high = lowest_transition.high;
+	out_pair->low = lowest_transition.low;
+}
+
+/* Set the baseband attenuation value on chip. */
+void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
+					  u16 baseband_attenuation)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 value;
+
+	if (phy->version == 0) {
+		value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0);
+		value |= (baseband_attenuation & 0x000F);
+		bcm43xx_write16(bcm, 0x03E6, value);
+		return;
+	}
+
+	if (phy->version > 1) {
+		value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C;
+		value |= (baseband_attenuation << 2) & 0x003C;
+	} else {
+		value = bcm43xx_phy_read(bcm, 0x0060) & ~0x0078;
+		value |= (baseband_attenuation << 3) & 0x0078;
+	}
+	bcm43xx_phy_write(bcm, 0x0060, value);
+}
+
+/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */
+void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
+{
+	static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
+	const int is_initializing = bcm43xx_is_initializing(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 h, i, oldi = 0, j;
+	struct bcm43xx_lopair control;
+	struct bcm43xx_lopair *tmp_control;
+	u16 tmp;
+	u16 regstack[16] = { 0 };
+	u8 oldchannel;
+
+	//XXX: What are these?
+	u8 r27 = 0, r31;
+
+	oldchannel = radio->channel;
+	/* Setup */
+	if (phy->connected) {
+		regstack[0] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
+		regstack[1] = bcm43xx_phy_read(bcm, 0x0802);
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF);
+		bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC);
+	}
+	regstack[3] = bcm43xx_read16(bcm, 0x03E2);
+	bcm43xx_write16(bcm, 0x03E2, regstack[3] | 0x8000);
+	regstack[4] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
+	regstack[5] = bcm43xx_phy_read(bcm, 0x15);
+	regstack[6] = bcm43xx_phy_read(bcm, 0x2A);
+	regstack[7] = bcm43xx_phy_read(bcm, 0x35);
+	regstack[8] = bcm43xx_phy_read(bcm, 0x60);
+	regstack[9] = bcm43xx_radio_read16(bcm, 0x43);
+	regstack[10] = bcm43xx_radio_read16(bcm, 0x7A);
+	regstack[11] = bcm43xx_radio_read16(bcm, 0x52);
+	if (phy->connected) {
+		regstack[12] = bcm43xx_phy_read(bcm, 0x0811);
+		regstack[13] = bcm43xx_phy_read(bcm, 0x0812);
+		regstack[14] = bcm43xx_phy_read(bcm, 0x0814);
+		regstack[15] = bcm43xx_phy_read(bcm, 0x0815);
+	}
+	bcm43xx_radio_selectchannel(bcm, 6, 0);
+	if (phy->connected) {
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF);
+		bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC);
+		bcm43xx_dummy_transmission(bcm);
+	}
+	bcm43xx_radio_write16(bcm, 0x0043, 0x0006);
+
+	bcm43xx_phy_set_baseband_attenuation(bcm, 2);
+
+	bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x0000);
+	bcm43xx_phy_write(bcm, 0x002E, 0x007F);
+	bcm43xx_phy_write(bcm, 0x080F, 0x0078);
+	bcm43xx_phy_write(bcm, 0x0035, regstack[7] & ~(1 << 7));
+	bcm43xx_radio_write16(bcm, 0x007A, regstack[10] & 0xFFF0);
+	bcm43xx_phy_write(bcm, 0x002B, 0x0203);
+	bcm43xx_phy_write(bcm, 0x002A, 0x08A3);
+	if (phy->connected) {
+		bcm43xx_phy_write(bcm, 0x0814, regstack[14] | 0x0003);
+		bcm43xx_phy_write(bcm, 0x0815, regstack[15] & 0xFFFC);
+		bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
+		bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
+	}
+	if (is_initializing)
+		bcm43xx_phy_lo_g_measure_txctl2(bcm);
+	bcm43xx_phy_write(bcm, 0x080F, 0x8078);
+
+	/* Measure */
+	control.low = 0;
+	control.high = 0;
+	for (h = 0; h < 10; h++) {
+		/* Loop over each possible RadioAttenuation (0-9) */
+		i = pairorder[h];
+		if (is_initializing) {
+			if (i == 3) {
+				control.low = 0;
+				control.high = 0;
+			} else if (((i % 2 == 1) && (oldi % 2 == 1)) ||
+				  ((i % 2 == 0) && (oldi % 2 == 0))) {
+				tmp_control = bcm43xx_get_lopair(phy, oldi, 0);
+				memcpy(&control, tmp_control, sizeof(control));
+			} else {
+				tmp_control = bcm43xx_get_lopair(phy, 3, 0);
+				memcpy(&control, tmp_control, sizeof(control));
+			}
+		}
+		/* Loop over each possible BasebandAttenuation/2 */
+		for (j = 0; j < 4; j++) {
+			if (is_initializing) {
+				tmp = i * 2 + j;
+				r27 = 0;
+				r31 = 0;
+				if (tmp > 14) {
+					r31 = 1;
+					if (tmp > 17)
+						r27 = 1;
+					if (tmp > 19)
+						r27 = 2;
+				}
+			} else {
+				tmp_control = bcm43xx_get_lopair(phy, i, j * 2);
+				if (!tmp_control->used)
+					continue;
+				memcpy(&control, tmp_control, sizeof(control));
+				r27 = 3;
+				r31 = 0;
+			}
+			bcm43xx_radio_write16(bcm, 0x43, i);
+			bcm43xx_radio_write16(bcm, 0x52, radio->txctl2);
+			udelay(10);
+
+			bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
+
+			tmp = (regstack[10] & 0xFFF0);
+			if (r31)
+				tmp |= 0x0008;
+			bcm43xx_radio_write16(bcm, 0x007A, tmp);
+
+			tmp_control = bcm43xx_get_lopair(phy, i, j * 2);
+			bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27);
+		}
+		oldi = i;
+	}
+	/* Loop over each possible RadioAttenuation (10-13) */
+	for (i = 10; i < 14; i++) {
+		/* Loop over each possible BasebandAttenuation/2 */
+		for (j = 0; j < 4; j++) {
+			if (is_initializing) {
+				tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2);
+				memcpy(&control, tmp_control, sizeof(control));
+				tmp = (i - 9) * 2 + j - 5;//FIXME: This is wrong, as the following if statement can never trigger.
+				r27 = 0;
+				r31 = 0;
+				if (tmp > 14) {
+					r31 = 1;
+					if (tmp > 17)
+						r27 = 1;
+					if (tmp > 19)
+						r27 = 2;
+				}
+			} else {
+				tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2);
+				if (!tmp_control->used)
+					continue;
+				memcpy(&control, tmp_control, sizeof(control));
+				r27 = 3;
+				r31 = 0;
+			}
+			bcm43xx_radio_write16(bcm, 0x43, i - 9);
+			bcm43xx_radio_write16(bcm, 0x52,
+					      radio->txctl2
+					      | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above?
+			udelay(10);
+
+			bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
+
+			tmp = (regstack[10] & 0xFFF0);
+			if (r31)
+				tmp |= 0x0008;
+			bcm43xx_radio_write16(bcm, 0x7A, tmp);
+
+			tmp_control = bcm43xx_get_lopair(phy, i, j * 2);
+			bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27);
+		}
+	}
+
+	/* Restoration */
+	if (phy->connected) {
+		bcm43xx_phy_write(bcm, 0x0015, 0xE300);
+		bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA0);
+		udelay(5);
+		bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2);
+		udelay(2);
+		bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3);
+	} else
+		bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0);
+	bcm43xx_phy_lo_adjust(bcm, is_initializing);
+	bcm43xx_phy_write(bcm, 0x002E, 0x807F);
+	if (phy->connected)
+		bcm43xx_phy_write(bcm, 0x002F, 0x0202);
+	else
+		bcm43xx_phy_write(bcm, 0x002F, 0x0101);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, regstack[4]);
+	bcm43xx_phy_write(bcm, 0x0015, regstack[5]);
+	bcm43xx_phy_write(bcm, 0x002A, regstack[6]);
+	bcm43xx_phy_write(bcm, 0x0035, regstack[7]);
+	bcm43xx_phy_write(bcm, 0x0060, regstack[8]);
+	bcm43xx_radio_write16(bcm, 0x0043, regstack[9]);
+	bcm43xx_radio_write16(bcm, 0x007A, regstack[10]);
+	regstack[11] &= 0x00F0;
+	regstack[11] |= (bcm43xx_radio_read16(bcm, 0x52) & 0x000F);
+	bcm43xx_radio_write16(bcm, 0x52, regstack[11]);
+	bcm43xx_write16(bcm, 0x03E2, regstack[3]);
+	if (phy->connected) {
+		bcm43xx_phy_write(bcm, 0x0811, regstack[12]);
+		bcm43xx_phy_write(bcm, 0x0812, regstack[13]);
+		bcm43xx_phy_write(bcm, 0x0814, regstack[14]);
+		bcm43xx_phy_write(bcm, 0x0815, regstack[15]);
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0]);
+		bcm43xx_phy_write(bcm, 0x0802, regstack[1]);
+	}
+	bcm43xx_radio_selectchannel(bcm, oldchannel, 1);
+
+#ifdef CONFIG_BCM43XX_DEBUG
+	{
+		/* Sanity check for all lopairs. */
+		for (i = 0; i < BCM43xx_LO_COUNT; i++) {
+			tmp_control = phy->_lo_pairs + i;
+			if (tmp_control->low < -8 || tmp_control->low > 8 ||
+			    tmp_control->high < -8 || tmp_control->high > 8) {
+				printk(KERN_WARNING PFX
+				       "WARNING: Invalid LOpair (low: %d, high: %d, index: %d)\n",
+				       tmp_control->low, tmp_control->high, i);
+			}
+		}
+	}
+#endif /* CONFIG_BCM43XX_DEBUG */
+}
+
+static
+void bcm43xx_phy_lo_mark_current_used(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_lopair *pair;
+
+	pair = bcm43xx_current_lopair(bcm);
+	pair->used = 1;
+}
+
+void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_lopair *pair;
+	int i;
+
+	for (i = 0; i < BCM43xx_LO_COUNT; i++) {
+		pair = phy->_lo_pairs + i;
+		pair->used = 0;
+	}
+}
+
+/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
+ * This function converts a TSSI value to dBm in Q5.2
+ */
+static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	s8 dbm = 0;
+	s32 tmp;
+
+	tmp = phy->idle_tssi;
+	tmp += tssi;
+	tmp -= phy->savedpctlreg;
+
+	switch (phy->type) {
+		case BCM43xx_PHYTYPE_A:
+			tmp += 0x80;
+			tmp = limit_value(tmp, 0x00, 0xFF);
+			dbm = phy->tssi2dbm[tmp];
+			TODO(); //TODO: There's a FIXME on the specs
+			break;
+		case BCM43xx_PHYTYPE_B:
+		case BCM43xx_PHYTYPE_G:
+			tmp = limit_value(tmp, 0x00, 0x3F);
+			dbm = phy->tssi2dbm[tmp];
+			break;
+		default:
+			assert(0);
+	}
+
+	return dbm;
+}
+
+/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
+void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	
+	if (phy->savedpctlreg == 0xFFFF)
+		return;
+	if ((bcm->board_type == 0x0416) &&
+	    (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM))
+		return;
+	
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A: {
+
+		TODO(); //TODO: Nothing for A PHYs yet :-/
+
+		break;
+	}
+	case BCM43xx_PHYTYPE_B:
+	case BCM43xx_PHYTYPE_G: {
+		u16 tmp;
+		u16 txpower;
+		s8 v0, v1, v2, v3;
+		s8 average;
+		u8 max_pwr;
+		s16 desired_pwr, estimated_pwr, pwr_adjust;
+		s16 radio_att_delta, baseband_att_delta;
+		s16 radio_attenuation, baseband_attenuation;
+		unsigned long phylock_flags;
+
+		tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0058);
+		v0 = (s8)(tmp & 0x00FF);
+		v1 = (s8)((tmp & 0xFF00) >> 8);
+		tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005A);
+		v2 = (s8)(tmp & 0x00FF);
+		v3 = (s8)((tmp & 0xFF00) >> 8);
+		tmp = 0;
+
+		if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) {
+			tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0070);
+			v0 = (s8)(tmp & 0x00FF);
+			v1 = (s8)((tmp & 0xFF00) >> 8);
+			tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0072);
+			v2 = (s8)(tmp & 0x00FF);
+			v3 = (s8)((tmp & 0xFF00) >> 8);
+			if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F)
+				return;
+			v0 = (v0 + 0x20) & 0x3F;
+			v1 = (v1 + 0x20) & 0x3F;
+			v2 = (v2 + 0x20) & 0x3F;
+			v3 = (v3 + 0x20) & 0x3F;
+			tmp = 1;
+		}
+		bcm43xx_radio_clear_tssi(bcm);
+
+		average = (v0 + v1 + v2 + v3 + 2) / 4;
+
+		if (tmp && (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005E) & 0x8))
+			average -= 13;
+
+		estimated_pwr = bcm43xx_phy_estimate_power_out(bcm, average);
+
+		max_pwr = bcm->sprom.maxpower_bgphy;
+
+		if ((bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) &&
+		    (phy->type == BCM43xx_PHYTYPE_G))
+			max_pwr -= 0x3;
+
+		/*TODO:
+		max_pwr = min(REG - bcm->sprom.antennagain_bgphy - 0x6, max_pwr)
+			where REG is the max power as per the regulatory domain
+		*/
+
+		desired_pwr = limit_value(radio->txpower_desired, 0, max_pwr);
+		/* Check if we need to adjust the current power. */
+		pwr_adjust = desired_pwr - estimated_pwr;
+		radio_att_delta = -(pwr_adjust + 7) >> 3;
+		baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta);
+		if ((radio_att_delta == 0) && (baseband_att_delta == 0)) {
+			bcm43xx_phy_lo_mark_current_used(bcm);
+			return;
+		}
+
+		/* Calculate the new attenuation values. */
+		baseband_attenuation = radio->baseband_atten;
+		baseband_attenuation += baseband_att_delta;
+		radio_attenuation = radio->radio_atten;
+		radio_attenuation += radio_att_delta;
+
+		/* Get baseband and radio attenuation values into their permitted ranges.
+		 * baseband 0-11, radio 0-9.
+		 * Radio attenuation affects power level 4 times as much as baseband.
+		 */
+		if (radio_attenuation < 0) {
+			baseband_attenuation -= (4 * -radio_attenuation);
+			radio_attenuation = 0;
+		} else if (radio_attenuation > 9) {
+			baseband_attenuation += (4 * (radio_attenuation - 9));
+			radio_attenuation = 9;
+		} else {
+			while (baseband_attenuation < 0 && radio_attenuation > 0) {
+				baseband_attenuation += 4;
+				radio_attenuation--;
+			}
+			while (baseband_attenuation > 11 && radio_attenuation < 9) {
+				baseband_attenuation -= 4;
+				radio_attenuation++;
+			}
+		}
+		baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
+
+		txpower = radio->txctl1;
+		if ((radio->version == 0x2050) && (radio->revision == 2)) {
+			if (radio_attenuation <= 1) {
+				if (txpower == 0) {
+					txpower = 3;
+					radio_attenuation += 2;
+					baseband_attenuation += 2;
+				} else if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
+					baseband_attenuation += 4 * (radio_attenuation - 2);
+					radio_attenuation = 2;
+				}
+			} else if (radio_attenuation > 4 && txpower != 0) {
+				txpower = 0;
+				if (baseband_attenuation < 3) {
+					radio_attenuation -= 3;
+					baseband_attenuation += 2;
+				} else {
+					radio_attenuation -= 2;
+					baseband_attenuation -= 2;
+				}
+			}
+		}
+		radio->txctl1 = txpower;
+		baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
+		radio_attenuation = limit_value(radio_attenuation, 0, 9);
+
+		bcm43xx_phy_lock(bcm, phylock_flags);
+		bcm43xx_radio_lock(bcm);
+		bcm43xx_radio_set_txpower_bg(bcm, baseband_attenuation,
+					     radio_attenuation, txpower);
+		bcm43xx_phy_lo_mark_current_used(bcm);
+		bcm43xx_radio_unlock(bcm);
+		bcm43xx_phy_unlock(bcm, phylock_flags);
+		break;
+	}
+	default:
+		assert(0);
+	}
+}
+
+static inline
+s32 bcm43xx_tssi2dbm_ad(s32 num, s32 den)
+{
+	if (num < 0)
+		return num/den;
+	else
+		return (num+den/2)/den;
+}
+
+static inline
+s8 bcm43xx_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2)
+{
+	s32 m1, m2, f = 256, q, delta;
+	s8 i = 0;
+	
+	m1 = bcm43xx_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
+	m2 = max(bcm43xx_tssi2dbm_ad(32768 + index * pab2, 256), 1);
+	do {
+		if (i > 15)
+			return -EINVAL;
+		q = bcm43xx_tssi2dbm_ad(f * 4096 -
+					bcm43xx_tssi2dbm_ad(m2 * f, 16) * f, 2048);
+		delta = abs(q - f);
+		f = q;
+		i++;
+	} while (delta >= 2);
+	entry[index] = limit_value(bcm43xx_tssi2dbm_ad(m1 * f, 8192), -127, 128);
+	return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
+int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	s16 pab0, pab1, pab2;
+	u8 idx;
+	s8 *dyn_tssi2dbm;
+	
+	if (phy->type == BCM43xx_PHYTYPE_A) {
+		pab0 = (s16)(bcm->sprom.pa1b0);
+		pab1 = (s16)(bcm->sprom.pa1b1);
+		pab2 = (s16)(bcm->sprom.pa1b2);
+	} else {
+		pab0 = (s16)(bcm->sprom.pa0b0);
+		pab1 = (s16)(bcm->sprom.pa0b1);
+		pab2 = (s16)(bcm->sprom.pa0b2);
+	}
+
+	if ((bcm->chip_id == 0x4301) && (radio->version != 0x2050)) {
+		phy->idle_tssi = 0x34;
+		phy->tssi2dbm = bcm43xx_tssi2dbm_b_table;
+		return 0;
+	}
+
+	if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
+	    pab0 != -1 && pab1 != -1 && pab2 != -1) {
+		/* The pabX values are set in SPROM. Use them. */
+		if (phy->type == BCM43xx_PHYTYPE_A) {
+			if ((s8)bcm->sprom.idle_tssi_tgt_aphy != 0 &&
+			    (s8)bcm->sprom.idle_tssi_tgt_aphy != -1)
+				phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_aphy);
+			else
+				phy->idle_tssi = 62;
+		} else {
+			if ((s8)bcm->sprom.idle_tssi_tgt_bgphy != 0 &&
+			    (s8)bcm->sprom.idle_tssi_tgt_bgphy != -1)
+				phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_bgphy);
+			else
+				phy->idle_tssi = 62;
+		}
+		dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
+		if (dyn_tssi2dbm == NULL) {
+			printk(KERN_ERR PFX "Could not allocate memory"
+					    "for tssi2dbm table\n");
+			return -ENOMEM;
+		}
+		for (idx = 0; idx < 64; idx++)
+			if (bcm43xx_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0, pab1, pab2)) {
+				phy->tssi2dbm = NULL;
+				printk(KERN_ERR PFX "Could not generate "
+						    "tssi2dBm table\n");
+				return -ENODEV;
+			}
+		phy->tssi2dbm = dyn_tssi2dbm;
+		phy->dyn_tssi_tbl = 1;
+	} else {
+		/* pabX values not set in SPROM. */
+		switch (phy->type) {
+		case BCM43xx_PHYTYPE_A:
+			/* APHY needs a generated table. */
+			phy->tssi2dbm = NULL;
+			printk(KERN_ERR PFX "Could not generate tssi2dBm "
+					    "table (wrong SPROM info)!\n");
+			return -ENODEV;
+		case BCM43xx_PHYTYPE_B:
+			phy->idle_tssi = 0x34;
+			phy->tssi2dbm = bcm43xx_tssi2dbm_b_table;
+			break;
+		case BCM43xx_PHYTYPE_G:
+			phy->idle_tssi = 0x34;
+			phy->tssi2dbm = bcm43xx_tssi2dbm_g_table;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int bcm43xx_phy_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	int err = -ENODEV;
+	unsigned long flags;
+
+	/* We do not want to be preempted while calibrating
+	 * the hardware.
+	 */
+	local_irq_save(flags);
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+		if (phy->rev == 2 || phy->rev == 3) {
+			bcm43xx_phy_inita(bcm);
+			err = 0;
+		}
+		break;
+	case BCM43xx_PHYTYPE_B:
+		switch (phy->rev) {
+		case 2:
+			bcm43xx_phy_initb2(bcm);
+			err = 0;
+			break;
+		case 4:
+			bcm43xx_phy_initb4(bcm);
+			err = 0;
+			break;
+		case 5:
+			bcm43xx_phy_initb5(bcm);
+			err = 0;
+			break;
+		case 6:
+			bcm43xx_phy_initb6(bcm);
+			err = 0;
+			break;
+		}
+		break;
+	case BCM43xx_PHYTYPE_G:
+		bcm43xx_phy_initg(bcm);
+		err = 0;
+		break;
+	}
+	local_irq_restore(flags);
+	if (err)
+		printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n");
+
+	return err;
+}
+
+void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 antennadiv;
+	u16 offset;
+	u16 value;
+	u32 ucodeflags;
+
+	antennadiv = phy->antenna_diversity;
+
+	if (antennadiv == 0xFFFF)
+		antennadiv = 3;
+	assert(antennadiv <= 3);
+
+	ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+					BCM43xx_UCODEFLAGS_OFFSET);
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+			    BCM43xx_UCODEFLAGS_OFFSET,
+			    ucodeflags & ~BCM43xx_UCODEFLAG_AUTODIV);
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+	case BCM43xx_PHYTYPE_G:
+		if (phy->type == BCM43xx_PHYTYPE_A)
+			offset = 0x0000;
+		else
+			offset = 0x0400;
+
+		if (antennadiv == 2)
+			value = (3/*automatic*/ << 7);
+		else
+			value = (antennadiv << 7);
+		bcm43xx_phy_write(bcm, offset + 1,
+				  (bcm43xx_phy_read(bcm, offset + 1)
+				   & 0x7E7F) | value);
+
+		if (antennadiv >= 2) {
+			if (antennadiv == 2)
+				value = (antennadiv << 7);
+			else
+				value = (0/*force0*/ << 7);
+			bcm43xx_phy_write(bcm, offset + 0x2B,
+					  (bcm43xx_phy_read(bcm, offset + 0x2B)
+					   & 0xFEFF) | value);
+		}
+
+		if (phy->type == BCM43xx_PHYTYPE_G) {
+			if (antennadiv >= 2)
+				bcm43xx_phy_write(bcm, 0x048C,
+						  bcm43xx_phy_read(bcm, 0x048C)
+						   | 0x2000);
+			else
+				bcm43xx_phy_write(bcm, 0x048C,
+						  bcm43xx_phy_read(bcm, 0x048C)
+						   & ~0x2000);
+			if (phy->rev >= 2) {
+				bcm43xx_phy_write(bcm, 0x0461,
+						  bcm43xx_phy_read(bcm, 0x0461)
+						   | 0x0010);
+				bcm43xx_phy_write(bcm, 0x04AD,
+						  (bcm43xx_phy_read(bcm, 0x04AD)
+						   & 0x00FF) | 0x0015);
+				if (phy->rev == 2)
+					bcm43xx_phy_write(bcm, 0x0427, 0x0008);
+				else
+					bcm43xx_phy_write(bcm, 0x0427,
+						(bcm43xx_phy_read(bcm, 0x0427)
+						 & 0x00FF) | 0x0008);
+			}
+			else if (phy->rev >= 6)
+				bcm43xx_phy_write(bcm, 0x049B, 0x00DC);
+		} else {
+			if (phy->rev < 3)
+				bcm43xx_phy_write(bcm, 0x002B,
+						  (bcm43xx_phy_read(bcm, 0x002B)
+						   & 0x00FF) | 0x0024);
+			else {
+				bcm43xx_phy_write(bcm, 0x0061,
+						  bcm43xx_phy_read(bcm, 0x0061)
+						   | 0x0010);
+				if (phy->rev == 3) {
+					bcm43xx_phy_write(bcm, 0x0093, 0x001D);
+					bcm43xx_phy_write(bcm, 0x0027, 0x0008);
+				} else {
+					bcm43xx_phy_write(bcm, 0x0093, 0x003A);
+					bcm43xx_phy_write(bcm, 0x0027,
+						(bcm43xx_phy_read(bcm, 0x0027)
+						 & 0x00FF) | 0x0008);
+				}
+			}
+		}
+		break;
+	case BCM43xx_PHYTYPE_B:
+		if (bcm->current_core->rev == 2)
+			value = (3/*automatic*/ << 7);
+		else
+			value = (antennadiv << 7);
+		bcm43xx_phy_write(bcm, 0x03E2,
+				  (bcm43xx_phy_read(bcm, 0x03E2)
+				   & 0xFE7F) | value);
+		break;
+	default:
+		assert(0);
+	}
+
+	if (antennadiv >= 2) {
+		ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+						BCM43xx_UCODEFLAGS_OFFSET);
+		bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+				    BCM43xx_UCODEFLAGS_OFFSET,
+				    ucodeflags | BCM43xx_UCODEFLAG_AUTODIV);
+	}
+
+	phy->antenna_diversity = antennadiv;
+}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h
new file mode 100644
index 0000000..1f321ef
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h
@@ -0,0 +1,74 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef BCM43xx_PHY_H_
+#define BCM43xx_PHY_H_
+
+#include <linux/types.h>
+
+struct bcm43xx_private;
+
+void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm);
+#define bcm43xx_phy_lock(bcm, flags) \
+	do {					\
+		local_irq_save(flags);		\
+		bcm43xx_raw_phy_lock(bcm);	\
+	} while (0)
+void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm);
+#define bcm43xx_phy_unlock(bcm, flags) \
+	do {					\
+		bcm43xx_raw_phy_unlock(bcm);	\
+		local_irq_restore(flags);	\
+	} while (0)
+
+u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset);
+void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
+
+int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm);
+int bcm43xx_phy_init(struct bcm43xx_private *bcm);
+
+void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm);
+void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm);
+int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect);
+
+void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm);
+void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm);
+void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm);
+
+/* Adjust the LocalOscillator to the saved values.
+ * "fixed" is only set to 1 once in initialization. Set to 0 otherwise.
+ */
+void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed);
+void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm);
+
+void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
+					  u16 baseband_attenuation);
+
+#endif /* BCM43xx_PHY_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
new file mode 100644
index 0000000..c59ddd4
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -0,0 +1,606 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  PIO Transmission
+
+  Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx.h"
+#include "bcm43xx_pio.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_xmit.h"
+
+#include <linux/delay.h>
+
+
+static void tx_start(struct bcm43xx_pioqueue *queue)
+{
+	bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+			  BCM43xx_PIO_TXCTL_INIT);
+}
+
+static void tx_octet(struct bcm43xx_pioqueue *queue,
+		     u8 octet)
+{
+	if (queue->need_workarounds) {
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
+				  octet);
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+				  BCM43xx_PIO_TXCTL_WRITEHI);
+	} else {
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+				  BCM43xx_PIO_TXCTL_WRITEHI);
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
+				  octet);
+	}
+}
+
+static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr,
+			    const u8 *packet,
+			    unsigned int *pos)
+{
+	const u8 *source;
+	unsigned int i = *pos;
+	u16 ret;
+
+	if (i < sizeof(*txhdr)) {
+		source = (const u8 *)txhdr;
+	} else {
+		source = packet;
+		i -= sizeof(*txhdr);
+	}
+	ret = le16_to_cpu( *((u16 *)(source + i)) );
+	*pos += 2;
+
+	return ret;
+}
+
+static void tx_data(struct bcm43xx_pioqueue *queue,
+		    struct bcm43xx_txhdr *txhdr,
+		    const u8 *packet,
+		    unsigned int octets)
+{
+	u16 data;
+	unsigned int i = 0;
+
+	if (queue->need_workarounds) {
+		data = tx_get_next_word(txhdr, packet, &i);
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
+	}
+	bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+			  BCM43xx_PIO_TXCTL_WRITELO |
+			  BCM43xx_PIO_TXCTL_WRITEHI);
+	while (i < octets - 1) {
+		data = tx_get_next_word(txhdr, packet, &i);
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
+	}
+	if (octets % 2)
+		tx_octet(queue, packet[octets - sizeof(*txhdr) - 1]);
+}
+
+static void tx_complete(struct bcm43xx_pioqueue *queue,
+			struct sk_buff *skb)
+{
+	if (queue->need_workarounds) {
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
+				  skb->data[skb->len - 1]);
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+				  BCM43xx_PIO_TXCTL_WRITEHI |
+				  BCM43xx_PIO_TXCTL_COMPLETE);
+	} else {
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+				  BCM43xx_PIO_TXCTL_COMPLETE);
+	}
+}
+
+static u16 generate_cookie(struct bcm43xx_pioqueue *queue,
+			   int packetindex)
+{
+	u16 cookie = 0x0000;
+
+	/* We use the upper 4 bits for the PIO
+	 * controller ID and the lower 12 bits
+	 * for the packet index (in the cache).
+	 */
+	switch (queue->mmio_base) {
+	case BCM43xx_MMIO_PIO1_BASE:
+		break;
+	case BCM43xx_MMIO_PIO2_BASE:
+		cookie = 0x1000;
+		break;
+	case BCM43xx_MMIO_PIO3_BASE:
+		cookie = 0x2000;
+		break;
+	case BCM43xx_MMIO_PIO4_BASE:
+		cookie = 0x3000;
+		break;
+	default:
+		assert(0);
+	}
+	assert(((u16)packetindex & 0xF000) == 0x0000);
+	cookie |= (u16)packetindex;
+
+	return cookie;
+}
+
+static
+struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm,
+				       u16 cookie,
+				       struct bcm43xx_pio_txpacket **packet)
+{
+	struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm);
+	struct bcm43xx_pioqueue *queue = NULL;
+	int packetindex;
+
+	switch (cookie & 0xF000) {
+	case 0x0000:
+		queue = pio->queue0;
+		break;
+	case 0x1000:
+		queue = pio->queue1;
+		break;
+	case 0x2000:
+		queue = pio->queue2;
+		break;
+	case 0x3000:
+		queue = pio->queue3;
+		break;
+	default:
+		assert(0);
+	}
+	packetindex = (cookie & 0x0FFF);
+	assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS);
+	*packet = &(queue->tx_packets_cache[packetindex]);
+
+	return queue;
+}
+
+static void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue,
+				  struct sk_buff *skb,
+				  struct bcm43xx_pio_txpacket *packet)
+{
+	struct bcm43xx_txhdr txhdr;
+	unsigned int octets;
+
+	assert(skb_shinfo(skb)->nr_frags == 0);
+	bcm43xx_generate_txhdr(queue->bcm,
+			       &txhdr, skb->data, skb->len,
+			       (packet->xmitted_frags == 0),
+			       generate_cookie(queue, pio_txpacket_getindex(packet)));
+
+	tx_start(queue);
+	octets = skb->len + sizeof(txhdr);
+	if (queue->need_workarounds)
+		octets--;
+	tx_data(queue, &txhdr, (u8 *)skb->data, octets);
+	tx_complete(queue, skb);
+}
+
+static void free_txpacket(struct bcm43xx_pio_txpacket *packet,
+			  int irq_context)
+{
+	struct bcm43xx_pioqueue *queue = packet->queue;
+
+	ieee80211_txb_free(packet->txb);
+	list_move(&packet->list, &queue->txfree);
+	queue->nr_txfree++;
+
+	assert(queue->tx_devq_used >= packet->xmitted_octets);
+	assert(queue->tx_devq_packets >= packet->xmitted_frags);
+	queue->tx_devq_used -= packet->xmitted_octets;
+	queue->tx_devq_packets -= packet->xmitted_frags;
+}
+
+static int pio_tx_packet(struct bcm43xx_pio_txpacket *packet)
+{
+	struct bcm43xx_pioqueue *queue = packet->queue;
+	struct ieee80211_txb *txb = packet->txb;
+	struct sk_buff *skb;
+	u16 octets;
+	int i;
+
+	for (i = packet->xmitted_frags; i < txb->nr_frags; i++) {
+		skb = txb->fragments[i];
+
+		octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr);
+		assert(queue->tx_devq_size >= octets);
+		assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS);
+		assert(queue->tx_devq_used <= queue->tx_devq_size);
+		/* Check if there is sufficient free space on the device
+		 * TX queue. If not, return and let the TX tasklet
+		 * retry later.
+		 */
+		if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS)
+			return -EBUSY;
+		if (queue->tx_devq_used + octets > queue->tx_devq_size)
+			return -EBUSY;
+		/* Now poke the device. */
+		pio_tx_write_fragment(queue, skb, packet);
+
+		/* Account for the packet size.
+		 * (We must not overflow the device TX queue)
+		 */
+		queue->tx_devq_packets++;
+		queue->tx_devq_used += octets;
+
+		assert(packet->xmitted_frags <= packet->txb->nr_frags);
+		packet->xmitted_frags++;
+		packet->xmitted_octets += octets;
+	}
+	list_move_tail(&packet->list, &queue->txrunning);
+
+	return 0;
+}
+
+static void tx_tasklet(unsigned long d)
+{
+	struct bcm43xx_pioqueue *queue = (struct bcm43xx_pioqueue *)d;
+	struct bcm43xx_private *bcm = queue->bcm;
+	unsigned long flags;
+	struct bcm43xx_pio_txpacket *packet, *tmp_packet;
+	int err;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
+		assert(packet->xmitted_frags < packet->txb->nr_frags);
+		if (packet->xmitted_frags == 0) {
+			int i;
+			struct sk_buff *skb;
+
+			/* Check if the device queue is big
+			 * enough for every fragment. If not, drop the
+			 * whole packet.
+			 */
+			for (i = 0; i < packet->txb->nr_frags; i++) {
+				skb = packet->txb->fragments[i];
+				if (unlikely(skb->len > queue->tx_devq_size)) {
+					dprintkl(KERN_ERR PFX "PIO TX device queue too small. "
+							      "Dropping packet.\n");
+					free_txpacket(packet, 1);
+					goto next_packet;
+				}
+			}
+		}
+		/* Try to transmit the packet.
+		 * This may not completely succeed.
+		 */
+		err = pio_tx_packet(packet);
+		if (err)
+			break;
+	next_packet:
+		continue;
+	}
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+static void setup_txqueues(struct bcm43xx_pioqueue *queue)
+{
+	struct bcm43xx_pio_txpacket *packet;
+	int i;
+
+	queue->nr_txfree = BCM43xx_PIO_MAXTXPACKETS;
+	for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) {
+		packet = &(queue->tx_packets_cache[i]);
+
+		packet->queue = queue;
+		INIT_LIST_HEAD(&packet->list);
+
+		list_add(&packet->list, &queue->txfree);
+	}
+}
+
+static
+struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm,
+						 u16 pio_mmio_base)
+{
+	struct bcm43xx_pioqueue *queue;
+	u32 value;
+	u16 qsize;
+
+	queue = kzalloc(sizeof(*queue), GFP_KERNEL);
+	if (!queue)
+		goto out;
+
+	queue->bcm = bcm;
+	queue->mmio_base = pio_mmio_base;
+	queue->need_workarounds = (bcm->current_core->rev < 3);
+
+	INIT_LIST_HEAD(&queue->txfree);
+	INIT_LIST_HEAD(&queue->txqueue);
+	INIT_LIST_HEAD(&queue->txrunning);
+	tasklet_init(&queue->txtask, tx_tasklet,
+		     (unsigned long)queue);
+
+	value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	value |= BCM43xx_SBF_XFER_REG_BYTESWAP;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value);
+
+	qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE);
+	if (qsize <= BCM43xx_PIO_TXQADJUST) {
+		printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n", qsize);
+		goto err_freequeue;
+	}
+	qsize -= BCM43xx_PIO_TXQADJUST;
+	queue->tx_devq_size = qsize;
+
+	setup_txqueues(queue);
+
+out:
+	return queue;
+
+err_freequeue:
+	kfree(queue);
+	queue = NULL;
+	goto out;
+}
+
+static void cancel_transfers(struct bcm43xx_pioqueue *queue)
+{
+	struct bcm43xx_pio_txpacket *packet, *tmp_packet;
+
+	netif_tx_disable(queue->bcm->net_dev);
+	assert(queue->bcm->shutting_down);
+	tasklet_disable(&queue->txtask);
+
+	list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
+		free_txpacket(packet, 0);
+	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
+		free_txpacket(packet, 0);
+}
+
+static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue)
+{
+	if (!queue)
+		return;
+
+	cancel_transfers(queue);
+	kfree(queue);
+}
+
+void bcm43xx_pio_free(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_pio *pio;
+
+	if (!bcm43xx_using_pio(bcm))
+		return;
+	pio = bcm43xx_current_pio(bcm);
+
+	bcm43xx_destroy_pioqueue(pio->queue3);
+	pio->queue3 = NULL;
+	bcm43xx_destroy_pioqueue(pio->queue2);
+	pio->queue2 = NULL;
+	bcm43xx_destroy_pioqueue(pio->queue1);
+	pio->queue1 = NULL;
+	bcm43xx_destroy_pioqueue(pio->queue0);
+	pio->queue0 = NULL;
+}
+
+int bcm43xx_pio_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm);
+	struct bcm43xx_pioqueue *queue;
+	int err = -ENOMEM;
+
+	queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE);
+	if (!queue)
+		goto out;
+	pio->queue0 = queue;
+
+	queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE);
+	if (!queue)
+		goto err_destroy0;
+	pio->queue1 = queue;
+
+	queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE);
+	if (!queue)
+		goto err_destroy1;
+	pio->queue2 = queue;
+
+	queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE);
+	if (!queue)
+		goto err_destroy2;
+	pio->queue3 = queue;
+
+	if (bcm->current_core->rev < 3)
+		bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND;
+
+	dprintk(KERN_INFO PFX "PIO initialized\n");
+	err = 0;
+out:
+	return err;
+
+err_destroy2:
+	bcm43xx_destroy_pioqueue(pio->queue2);
+	pio->queue2 = NULL;
+err_destroy1:
+	bcm43xx_destroy_pioqueue(pio->queue1);
+	pio->queue1 = NULL;
+err_destroy0:
+	bcm43xx_destroy_pioqueue(pio->queue0);
+	pio->queue0 = NULL;
+	goto out;
+}
+
+int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
+		   struct ieee80211_txb *txb)
+{
+	struct bcm43xx_pioqueue *queue = bcm43xx_current_pio(bcm)->queue1;
+	struct bcm43xx_pio_txpacket *packet;
+	u16 tmp;
+
+	assert(!queue->tx_suspended);
+	assert(!list_empty(&queue->txfree));
+
+	tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
+	if (tmp & BCM43xx_PIO_TXCTL_SUSPEND)
+		return -EBUSY;
+
+	packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list);
+	packet->txb = txb;
+	packet->xmitted_frags = 0;
+	packet->xmitted_octets = 0;
+	list_move_tail(&packet->list, &queue->txqueue);
+	queue->nr_txfree--;
+	assert(queue->nr_txfree < BCM43xx_PIO_MAXTXPACKETS);
+
+	/* Suspend TX, if we are out of packets in the "free" queue. */
+	if (unlikely(list_empty(&queue->txfree))) {
+		netif_stop_queue(queue->bcm->net_dev);
+		queue->tx_suspended = 1;
+	}
+
+	tasklet_schedule(&queue->txtask);
+
+	return 0;
+}
+
+void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
+				   struct bcm43xx_xmitstatus *status)
+{
+	struct bcm43xx_pioqueue *queue;
+	struct bcm43xx_pio_txpacket *packet;
+
+	queue = parse_cookie(bcm, status->cookie, &packet);
+	assert(queue);
+//TODO
+if (!queue)
+return;
+	free_txpacket(packet, 1);
+	if (unlikely(queue->tx_suspended)) {
+		queue->tx_suspended = 0;
+		netif_wake_queue(queue->bcm->net_dev);
+	}
+	/* If there are packets on the txqueue, poke the tasklet. */
+	if (!list_empty(&queue->txqueue))
+		tasklet_schedule(&queue->txtask);
+}
+
+static void pio_rx_error(struct bcm43xx_pioqueue *queue,
+			 int clear_buffers,
+			 const char *error)
+{
+	int i;
+
+	printkl("PIO RX error: %s\n", error);
+	bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL,
+			  BCM43xx_PIO_RXCTL_READY);
+	if (clear_buffers) {
+		assert(queue->mmio_base == BCM43xx_MMIO_PIO1_BASE);
+		for (i = 0; i < 15; i++) {
+			/* Dummy read. */
+			bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
+		}
+	}
+}
+
+void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
+{
+	u16 preamble[21] = { 0 };
+	struct bcm43xx_rxhdr *rxhdr;
+	u16 tmp, len, rxflags2;
+	int i, preamble_readwords;
+	struct sk_buff *skb;
+
+return;
+	tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
+	if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) {
+		dprintkl(KERN_ERR PFX "PIO RX: No data available\n");//TODO: remove this printk.
+		return;
+	}
+	bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL,
+			  BCM43xx_PIO_RXCTL_DATAAVAILABLE);
+
+	for (i = 0; i < 10; i++) {
+		tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
+		if (tmp & BCM43xx_PIO_RXCTL_READY)
+			goto data_ready;
+		udelay(10);
+	}
+	dprintkl(KERN_ERR PFX "PIO RX timed out\n");
+	return;
+data_ready:
+
+//FIXME: endianess in this function.
+	len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
+	if (unlikely(len > 0x700)) {
+		pio_rx_error(queue, 0, "len > 0x700");
+		return;
+	}
+	if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) {
+		pio_rx_error(queue, 0, "len == 0");
+		return;
+	}
+	preamble[0] = cpu_to_le16(len);
+	if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE)
+		preamble_readwords = 14 / sizeof(u16);
+	else
+		preamble_readwords = 18 / sizeof(u16);
+	for (i = 0; i < preamble_readwords; i++) {
+		tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
+		preamble[i + 1] = cpu_to_be16(tmp);//FIXME?
+	}
+	rxhdr = (struct bcm43xx_rxhdr *)preamble;
+	rxflags2 = le16_to_cpu(rxhdr->flags2);
+	if (unlikely(rxflags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) {
+		pio_rx_error(queue,
+			     (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE),
+			     "invalid frame");
+		return;
+	}
+	if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) {
+		/* We received an xmit status. */
+		struct bcm43xx_hwxmitstatus *hw;
+		struct bcm43xx_xmitstatus stat;
+
+		hw = (struct bcm43xx_hwxmitstatus *)(preamble + 1);
+		stat.cookie = le16_to_cpu(hw->cookie);
+		stat.flags = hw->flags;
+		stat.cnt1 = hw->cnt1;
+		stat.cnt2 = hw->cnt2;
+		stat.seq = le16_to_cpu(hw->seq);
+		stat.unknown = le16_to_cpu(hw->unknown);
+
+		bcm43xx_debugfs_log_txstat(queue->bcm, &stat);
+		bcm43xx_pio_handle_xmitstatus(queue->bcm, &stat);
+
+		return;
+	}
+
+	skb = dev_alloc_skb(len);
+	if (unlikely(!skb)) {
+		pio_rx_error(queue, 1, "OOM");
+		return;
+	}
+	skb_put(skb, len);
+	for (i = 0; i < len - 1; i += 2) {
+		tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
+		*((u16 *)(skb->data + i)) = tmp;
+	}
+	if (len % 2) {
+		tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
+		skb->data[len - 1] = (tmp & 0x00FF);
+		if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME)
+			skb->data[0x20] = (tmp & 0xFF00) >> 8;
+		else
+			skb->data[0x1E] = (tmp & 0xFF00) >> 8;
+	}
+	bcm43xx_rx(queue->bcm, skb, rxhdr);
+}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
new file mode 100644
index 0000000..970627b
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
@@ -0,0 +1,138 @@
+#ifndef BCM43xx_PIO_H_
+#define BCM43xx_PIO_H_
+
+#include "bcm43xx.h"
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+
+#define BCM43xx_PIO_TXCTL		0x00
+#define BCM43xx_PIO_TXDATA		0x02
+#define BCM43xx_PIO_TXQBUFSIZE		0x04
+#define BCM43xx_PIO_RXCTL		0x08
+#define BCM43xx_PIO_RXDATA		0x0A
+
+#define BCM43xx_PIO_TXCTL_WRITEHI	(1 << 0)
+#define BCM43xx_PIO_TXCTL_WRITELO	(1 << 1)
+#define BCM43xx_PIO_TXCTL_COMPLETE	(1 << 2)
+#define BCM43xx_PIO_TXCTL_INIT		(1 << 3)
+#define BCM43xx_PIO_TXCTL_SUSPEND	(1 << 7)
+
+#define BCM43xx_PIO_RXCTL_DATAAVAILABLE	(1 << 0)
+#define BCM43xx_PIO_RXCTL_READY		(1 << 1)
+
+/* PIO constants */
+#define BCM43xx_PIO_MAXTXDEVQPACKETS	31
+#define BCM43xx_PIO_TXQADJUST		80
+
+/* PIO tuning knobs */
+#define BCM43xx_PIO_MAXTXPACKETS	256
+
+
+
+#ifdef CONFIG_BCM43XX_PIO
+
+
+struct bcm43xx_pioqueue;
+struct bcm43xx_xmitstatus;
+
+struct bcm43xx_pio_txpacket {
+	struct bcm43xx_pioqueue *queue;
+	struct ieee80211_txb *txb;
+	struct list_head list;
+
+	u8 xmitted_frags;
+	u16 xmitted_octets;
+};
+
+#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache)) 
+
+struct bcm43xx_pioqueue {
+	struct bcm43xx_private *bcm;
+	u16 mmio_base;
+
+	u8 tx_suspended:1,
+	   need_workarounds:1; /* Workarounds needed for core.rev < 3 */
+
+	/* Adjusted size of the device internal TX buffer. */
+	u16 tx_devq_size;
+	/* Used octets of the device internal TX buffer. */
+	u16 tx_devq_used;
+	/* Used packet slots in the device internal TX buffer. */
+	u8 tx_devq_packets;
+	/* Packets from the txfree list can
+	 * be taken on incoming TX requests.
+	 */
+	struct list_head txfree;
+	unsigned int nr_txfree;
+	/* Packets on the txqueue are queued,
+	 * but not completely written to the chip, yet.
+	 */
+	struct list_head txqueue;
+	/* Packets on the txrunning queue are completely
+	 * posted to the device. We are waiting for the txstatus.
+	 */
+	struct list_head txrunning;
+	/* Total number or packets sent.
+	 * (This counter can obviously wrap).
+	 */
+	unsigned int nr_tx_packets;
+	struct tasklet_struct txtask;
+	struct bcm43xx_pio_txpacket tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS];
+};
+
+static inline
+u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue,
+		     u16 offset)
+{
+	return bcm43xx_read16(queue->bcm, queue->mmio_base + offset);
+}
+
+static inline
+void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue,
+		       u16 offset, u16 value)
+{
+	bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value);
+}
+
+
+int bcm43xx_pio_init(struct bcm43xx_private *bcm);
+void bcm43xx_pio_free(struct bcm43xx_private *bcm);
+
+int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
+		   struct ieee80211_txb *txb);
+void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
+				   struct bcm43xx_xmitstatus *status);
+void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue);
+
+#else /* CONFIG_BCM43XX_PIO */
+
+static inline
+int bcm43xx_pio_init(struct bcm43xx_private *bcm)
+{
+	return 0;
+}
+static inline
+void bcm43xx_pio_free(struct bcm43xx_private *bcm)
+{
+}
+static inline
+int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
+		   struct ieee80211_txb *txb)
+{
+	return 0;
+}
+static inline
+void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
+				   struct bcm43xx_xmitstatus *status)
+{
+}
+static inline
+void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
+{
+}
+
+#endif /* CONFIG_BCM43XX_PIO */
+#endif /* BCM43xx_PIO_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.c b/drivers/net/wireless/bcm43xx/bcm43xx_power.c
new file mode 100644
index 0000000..3c92b62
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.c
@@ -0,0 +1,358 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+
+#include "bcm43xx.h"
+#include "bcm43xx_power.h"
+#include "bcm43xx_main.h"
+
+
+/* Get max/min slowclock frequency
+ * as described in http://bcm-specs.sipsolutions.net/PowerControl
+ */
+static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm,
+				       int get_max)
+{
+	int limit = 0;
+	int divisor;
+	int selection;
+	int err;
+	u32 tmp;
+	struct bcm43xx_coreinfo *old_core;
+
+	if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
+		goto out;
+	old_core = bcm->current_core;
+	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+	if (err)
+		goto out;
+
+	if (bcm->current_core->rev < 6) {
+		if ((bcm->bustype == BCM43xx_BUSTYPE_PCMCIA) ||
+			(bcm->bustype == BCM43xx_BUSTYPE_SB)) {
+			selection = 1;
+			divisor = 32;
+		} else {
+			err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp);
+			if (err) {
+				printk(KERN_ERR PFX "clockfreqlimit pcicfg read failure\n");
+				goto out_switchback;
+			}
+			if (tmp & 0x10) {
+				/* PCI */
+				selection = 2;
+				divisor = 64;
+			} else {
+				/* XTAL */
+				selection = 1;
+				divisor = 32;
+			}
+		}
+	} else if (bcm->current_core->rev < 10) {
+		selection = (tmp & 0x07);
+		if (selection) {
+			tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
+			divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16));
+		} else
+			divisor = 1;
+	} else {
+		tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL);
+		divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16));
+		selection = 1;
+	}
+	
+	switch (selection) {
+	case 0:
+		/* LPO */
+		if (get_max)
+			limit = 43000;
+		else
+			limit = 25000;
+		break;
+	case 1:
+		/* XTAL */
+		if (get_max)
+			limit = 20200000;
+		else
+			limit = 19800000;
+		break;
+	case 2:
+		/* PCI */
+		if (get_max)
+			limit = 34000000;
+		else
+			limit = 25000000;
+		break;
+	default:
+		assert(0);
+	}
+	limit /= divisor;
+
+out_switchback:
+	err = bcm43xx_switch_core(bcm, old_core);
+	assert(err == 0);
+
+out:
+	return limit;
+}
+
+/* init power control
+ * as described in http://bcm-specs.sipsolutions.net/PowerControl
+ */
+int bcm43xx_pctl_init(struct bcm43xx_private *bcm)
+{
+	int err, maxfreq;
+	struct bcm43xx_coreinfo *old_core;
+
+	if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
+		return 0;
+	old_core = bcm->current_core;
+	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+	if (err == -ENODEV)
+		return 0;
+	if (err)
+		goto out;
+
+	maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1);
+	bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY,
+			(maxfreq * 150 + 999999) / 1000000);
+	bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY,
+			(maxfreq * 15 + 999999) / 1000000);
+
+	err = bcm43xx_switch_core(bcm, old_core);
+	assert(err == 0);
+
+out:
+	return err;
+}
+
+u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm)
+{
+	u16 delay = 0;
+	int err;
+	u32 pll_on_delay;
+	struct bcm43xx_coreinfo *old_core;
+	int minfreq;
+
+	if (bcm->bustype != BCM43xx_BUSTYPE_PCI)
+		goto out;
+	if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
+		goto out;
+	old_core = bcm->current_core;
+	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+	if (err == -ENODEV)
+		goto out;
+
+	minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0);
+	pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY);
+	delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
+
+	err = bcm43xx_switch_core(bcm, old_core);
+	assert(err == 0);
+
+out:
+	return delay;
+}
+
+/* set the powercontrol clock
+ * as described in http://bcm-specs.sipsolutions.net/PowerControl
+ */
+int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode)
+{
+	int err;
+	struct bcm43xx_coreinfo *old_core;
+	u32 tmp;
+
+	old_core = bcm->current_core;
+	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+	if (err == -ENODEV)
+		return 0;
+	if (err)
+		goto out;
+	
+	if (bcm->core_chipcommon.rev < 6) {
+		if (mode == BCM43xx_PCTL_CLK_FAST) {
+			err = bcm43xx_pctl_set_crystal(bcm, 1);
+			if (err)
+				goto out;
+		}
+	} else {
+		if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) &&
+			(bcm->core_chipcommon.rev < 10)) {
+			switch (mode) {
+			case BCM43xx_PCTL_CLK_FAST:
+				tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
+				tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL;
+				bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
+				break;
+			case BCM43xx_PCTL_CLK_SLOW:
+				tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
+				tmp |= BCM43xx_PCTL_FORCE_SLOW;
+				bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
+				break;
+			case BCM43xx_PCTL_CLK_DYNAMIC:
+				tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
+				tmp &= ~BCM43xx_PCTL_FORCE_SLOW;
+				tmp |= BCM43xx_PCTL_FORCE_PLL;
+				tmp &= ~BCM43xx_PCTL_DYN_XTAL;
+				bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
+			}
+		}
+	}
+	
+	err = bcm43xx_switch_core(bcm, old_core);
+	assert(err == 0);
+
+out:
+	return err;
+}
+
+int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on)
+{
+	int err;
+	u32 in, out, outenable;
+
+	err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in);
+	if (err)
+		goto err_pci;
+	err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out);
+	if (err)
+		goto err_pci;
+	err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable);
+	if (err)
+		goto err_pci;
+
+	outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
+
+	if (on) {
+		if (in & 0x40)
+			return 0;
+
+		out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
+
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
+		if (err)
+			goto err_pci;
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
+		if (err)
+			goto err_pci;
+		udelay(1000);
+
+		out &= ~BCM43xx_PCTL_PLL_POWERDOWN;
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
+		if (err)
+			goto err_pci;
+		udelay(5000);
+	} else {
+		if (bcm->current_core->rev < 5)
+			return 0;
+		if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW)
+			return 0;
+
+/*		XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time?
+ *		err = bcm43xx_switch_core(bcm, bcm->active_80211_core);
+ *		if (err)
+ *			return err;
+ *		if (((bcm->current_core->rev >= 3) &&
+ *			(bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) ||
+ *		      ((bcm->current_core->rev < 3) &&
+ *			!(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4))))
+ *			return 0;
+ *		err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+ *		if (err)
+ *			return err;
+ */
+		
+		err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
+		if (err)
+			goto out;
+		out &= ~BCM43xx_PCTL_XTAL_POWERUP;
+		out |= BCM43xx_PCTL_PLL_POWERDOWN;
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
+		if (err)
+			goto err_pci;
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
+		if (err)
+			goto err_pci;
+	}
+
+out:
+	return err;
+
+err_pci:
+	printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n");
+	err = -EBUSY;
+	goto out;
+}
+
+/* Set the PowerSavingControlBits.
+ * Bitvalues:
+ *   0  => unset the bit
+ *   1  => set the bit
+ *   -1 => calculate the bit
+ */
+void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm,
+				   int bit25, int bit26)
+{
+	int i;
+	u32 status;
+
+//FIXME: Force 25 to off and 26 to on for now:
+bit25 = 0;
+bit26 = 1;
+
+	if (bit25 == -1) {
+		//TODO: If powersave is not off and FIXME is not set and we are not in adhoc
+		//	and thus is not an AP and we are associated, set bit 25
+	}
+	if (bit26 == -1) {
+		//TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
+		//	or we are associated, or FIXME, or the latest PS-Poll packet sent was
+		//	successful, set bit26
+	}
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	if (bit25)
+		status |= BCM43xx_SBF_PS1;
+	else
+		status &= ~BCM43xx_SBF_PS1;
+	if (bit26)
+		status |= BCM43xx_SBF_PS2;
+	else
+		status &= ~BCM43xx_SBF_PS2;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+	if (bit26 && bcm->current_core->rev >= 5) {
+		for (i = 0; i < 100; i++) {
+			if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4)
+				break;
+			udelay(10);
+		}
+	}
+}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.h b/drivers/net/wireless/bcm43xx/bcm43xx_power.h
new file mode 100644
index 0000000..5f63640
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.h
@@ -0,0 +1,47 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef BCM43xx_POWER_H_
+#define BCM43xx_POWER_H_
+
+#include <linux/types.h>
+
+
+struct bcm43xx_private;
+
+int bcm43xx_pctl_init(struct bcm43xx_private *bcm);
+int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode);
+int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on);
+u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm);
+
+void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm,
+				   int bit25, int bit26);
+
+#endif /* BCM43xx_POWER_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
new file mode 100644
index 0000000..af5c0bf
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -0,0 +1,2026 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+
+#include "bcm43xx.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_phy.h"
+#include "bcm43xx_radio.h"
+#include "bcm43xx_ilt.h"
+
+
+/* Table for bcm43xx_radio_calibrationvalue() */
+static const u16 rcc_table[16] = {
+	0x0002, 0x0003, 0x0001, 0x000F,
+	0x0006, 0x0007, 0x0005, 0x000F,
+	0x000A, 0x000B, 0x0009, 0x000F,
+	0x000E, 0x000F, 0x000D, 0x000F,
+};
+
+/* Reverse the bits of a 4bit value.
+ * Example:  1101 is flipped 1011
+ */
+static u16 flip_4bit(u16 value)
+{
+	u16 flipped = 0x0000;
+
+	assert((value & ~0x000F) == 0x0000);
+
+	flipped |= (value & 0x0001) << 3;
+	flipped |= (value & 0x0002) << 1;
+	flipped |= (value & 0x0004) >> 1;
+	flipped |= (value & 0x0008) >> 3;
+
+	return flipped;
+}
+
+/* Get the freq, as it has to be written to the device. */
+static inline
+u16 channel2freq_bg(u8 channel)
+{
+	/* Frequencies are given as frequencies_bg[index] + 2.4GHz
+	 * Starting with channel 1
+	 */
+	static const u16 frequencies_bg[14] = {
+		12, 17, 22, 27,
+		32, 37, 42, 47,
+		52, 57, 62, 67,
+		72, 84,
+	};
+
+	assert(channel >= 1 && channel <= 14);
+
+	return frequencies_bg[channel - 1];
+}
+
+/* Get the freq, as it has to be written to the device. */
+static inline
+u16 channel2freq_a(u8 channel)
+{
+	assert(channel <= 200);
+
+	return (5000 + 5 * channel);
+}
+
+void bcm43xx_radio_lock(struct bcm43xx_private *bcm)
+{
+	u32 status;
+
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	status |= BCM43xx_SBF_RADIOREG_LOCK;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+	mmiowb();
+	udelay(10);
+}
+
+void bcm43xx_radio_unlock(struct bcm43xx_private *bcm)
+{
+	u32 status;
+
+	bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); /* dummy read */
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	status &= ~BCM43xx_SBF_RADIOREG_LOCK;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+	mmiowb();
+}
+
+u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+		offset |= 0x0040;
+		break;
+	case BCM43xx_PHYTYPE_B:
+		if (radio->version == 0x2053) {
+			if (offset < 0x70)
+				offset += 0x80;
+			else if (offset < 0x80)
+				offset += 0x70;
+		} else if (radio->version == 0x2050) {
+			offset |= 0x80;
+		} else
+			assert(0);
+		break;
+	case BCM43xx_PHYTYPE_G:
+		offset |= 0x80;
+		break;
+	}
+
+	bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset);
+	return bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);
+}
+
+void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val)
+{
+	bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset);
+	mmiowb();
+	bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW, val);
+}
+
+static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm,
+				  s16 first, s16 second, s16 third)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 i;
+	u16 start = 0x08, end = 0x18;
+	u16 offset = 0x0400;
+	u16 tmp;
+
+	if (phy->rev <= 1) {
+		offset = 0x5000;
+		start = 0x10;
+		end = 0x20;
+	}
+
+	for (i = 0; i < 4; i++)
+		bcm43xx_ilt_write(bcm, offset + i, first);
+
+	for (i = start; i < end; i++)
+		bcm43xx_ilt_write(bcm, offset + i, second);
+
+	if (third != -1) {
+		tmp = ((u16)third << 14) | ((u16)third << 6);
+		bcm43xx_phy_write(bcm, 0x04A0,
+		                  (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | tmp);
+		bcm43xx_phy_write(bcm, 0x04A1,
+		                  (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | tmp);
+		bcm43xx_phy_write(bcm, 0x04A2,
+		                  (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | tmp);
+	}
+	bcm43xx_dummy_transmission(bcm);
+}
+
+static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 i, tmp;
+	u16 offset = 0x0400;
+	u16 start = 0x0008, end = 0x0018;
+
+	if (phy->rev <= 1) {
+		offset = 0x5000;
+		start = 0x0010;
+		end = 0x0020;
+	}
+
+	for (i = 0; i < 4; i++) {
+		tmp = (i & 0xFFFC);
+		tmp |= (i & 0x0001) << 1;
+		tmp |= (i & 0x0002) >> 1;
+
+		bcm43xx_ilt_write(bcm, offset + i, tmp);
+	}
+
+	for (i = start; i < end; i++)
+		bcm43xx_ilt_write(bcm, offset + i, i - start);
+
+	bcm43xx_phy_write(bcm, 0x04A0,
+	                  (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | 0x4040);
+	bcm43xx_phy_write(bcm, 0x04A1,
+	                  (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | 0x4040);
+	bcm43xx_phy_write(bcm, 0x04A2,
+	                  (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | 0x4000);
+	bcm43xx_dummy_transmission(bcm);
+}
+
+/* Synthetic PU workaround */
+static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	
+	if (radio->version != 0x2050 || radio->revision >= 6) {
+		/* We do not need the workaround. */
+		return;
+	}
+
+	if (channel <= 10) {
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
+				channel2freq_bg(channel + 4));
+	} else {
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
+				channel2freq_bg(1));
+	}
+	udelay(100);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
+			channel2freq_bg(channel));
+}
+
+u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u8 ret = 0;
+	u16 saved, rssi, temp;
+	int i, j = 0;
+
+	saved = bcm43xx_phy_read(bcm, 0x0403);
+	bcm43xx_radio_selectchannel(bcm, channel, 0);
+	bcm43xx_phy_write(bcm, 0x0403, (saved & 0xFFF8) | 5);
+	if (radio->aci_hw_rssi)
+		rssi = bcm43xx_phy_read(bcm, 0x048A) & 0x3F;
+	else
+		rssi = saved & 0x3F;
+	/* clamp temp to signed 5bit */
+	if (rssi > 32)
+		rssi -= 64;
+	for (i = 0;i < 100; i++) {
+		temp = (bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x3F;
+		if (temp > 32)
+			temp -= 64;
+		if (temp < rssi)
+			j++;
+		if (j >= 20)
+			ret = 1;
+	}
+	bcm43xx_phy_write(bcm, 0x0403, saved);
+
+	return ret;
+}
+
+u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u8 ret[13];
+	unsigned int channel = radio->channel;
+	unsigned int i, j, start, end;
+	unsigned long phylock_flags;
+
+	if (!((phy->type == BCM43xx_PHYTYPE_G) && (phy->rev > 0)))
+		return 0;
+
+	bcm43xx_phy_lock(bcm, phylock_flags);
+	bcm43xx_radio_lock(bcm);
+	bcm43xx_phy_write(bcm, 0x0802,
+	                  bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC);
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+	                  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF);
+	bcm43xx_set_all_gains(bcm, 3, 8, 1);
+
+	start = (channel - 5 > 0) ? channel - 5 : 1;
+	end = (channel + 5 < 14) ? channel + 5 : 13;
+
+	for (i = start; i <= end; i++) {
+		if (abs(channel - i) > 2)
+			ret[i-1] = bcm43xx_radio_aci_detect(bcm, i);
+	}
+	bcm43xx_radio_selectchannel(bcm, channel, 0);
+	bcm43xx_phy_write(bcm, 0x0802,
+	                  (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC) | 0x0003);
+	bcm43xx_phy_write(bcm, 0x0403,
+	                  bcm43xx_phy_read(bcm, 0x0403) & 0xFFF8);
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+	                  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000);
+	bcm43xx_set_original_gains(bcm);
+	for (i = 0; i < 13; i++) {
+		if (!ret[i])
+			continue;
+		end = (i + 5 < 13) ? i + 5 : 13;
+		for (j = i; j < end; j++)
+			ret[j] = 1;
+	}
+	bcm43xx_radio_unlock(bcm);
+	bcm43xx_phy_unlock(bcm, phylock_flags);
+
+	return ret[channel - 1];
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val)
+{
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset);
+	mmiowb();
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_DATA, (u16)val);
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset)
+{
+	u16 val;
+
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset);
+	val = bcm43xx_phy_read(bcm, BCM43xx_PHY_NRSSILT_DATA);
+
+	return (s16)val;
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val)
+{
+	u16 i;
+	s16 tmp;
+
+	for (i = 0; i < 64; i++) {
+		tmp = bcm43xx_nrssi_hw_read(bcm, i);
+		tmp -= val;
+		tmp = limit_value(tmp, -32, 31);
+		bcm43xx_nrssi_hw_write(bcm, i, tmp);
+	}
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	s16 i, delta;
+	s32 tmp;
+
+	delta = 0x1F - radio->nrssi[0];
+	for (i = 0; i < 64; i++) {
+		tmp = (i - delta) * radio->nrssislope;
+		tmp /= 0x10000;
+		tmp += 0x3A;
+		tmp = limit_value(tmp, 0, 0x3F);
+		radio->nrssi_lt[i] = tmp;
+	}
+}
+
+static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 backup[20] = { 0 };
+	s16 v47F;
+	u16 i;
+	u16 saved = 0xFFFF;
+
+	backup[0] = bcm43xx_phy_read(bcm, 0x0001);
+	backup[1] = bcm43xx_phy_read(bcm, 0x0811);
+	backup[2] = bcm43xx_phy_read(bcm, 0x0812);
+	backup[3] = bcm43xx_phy_read(bcm, 0x0814);
+	backup[4] = bcm43xx_phy_read(bcm, 0x0815);
+	backup[5] = bcm43xx_phy_read(bcm, 0x005A);
+	backup[6] = bcm43xx_phy_read(bcm, 0x0059);
+	backup[7] = bcm43xx_phy_read(bcm, 0x0058);
+	backup[8] = bcm43xx_phy_read(bcm, 0x000A);
+	backup[9] = bcm43xx_phy_read(bcm, 0x0003);
+	backup[10] = bcm43xx_radio_read16(bcm, 0x007A);
+	backup[11] = bcm43xx_radio_read16(bcm, 0x0043);
+
+	bcm43xx_phy_write(bcm, 0x0429,
+			  bcm43xx_phy_read(bcm, 0x0429) & 0x7FFF);
+	bcm43xx_phy_write(bcm, 0x0001,
+			  (bcm43xx_phy_read(bcm, 0x0001) & 0x3FFF) | 0x4000);
+	bcm43xx_phy_write(bcm, 0x0811,
+			  bcm43xx_phy_read(bcm, 0x0811) | 0x000C);
+	bcm43xx_phy_write(bcm, 0x0812,
+			  (bcm43xx_phy_read(bcm, 0x0812) & 0xFFF3) | 0x0004);
+	bcm43xx_phy_write(bcm, 0x0802,
+			  bcm43xx_phy_read(bcm, 0x0802) & ~(0x1 | 0x2));
+	if (phy->rev >= 6) {
+		backup[12] = bcm43xx_phy_read(bcm, 0x002E);
+		backup[13] = bcm43xx_phy_read(bcm, 0x002F);
+		backup[14] = bcm43xx_phy_read(bcm, 0x080F);
+		backup[15] = bcm43xx_phy_read(bcm, 0x0810);
+		backup[16] = bcm43xx_phy_read(bcm, 0x0801);
+		backup[17] = bcm43xx_phy_read(bcm, 0x0060);
+		backup[18] = bcm43xx_phy_read(bcm, 0x0014);
+		backup[19] = bcm43xx_phy_read(bcm, 0x0478);
+
+		bcm43xx_phy_write(bcm, 0x002E, 0);
+		bcm43xx_phy_write(bcm, 0x002F, 0);
+		bcm43xx_phy_write(bcm, 0x080F, 0);
+		bcm43xx_phy_write(bcm, 0x0810, 0);
+		bcm43xx_phy_write(bcm, 0x0478,
+				  bcm43xx_phy_read(bcm, 0x0478) | 0x0100);
+		bcm43xx_phy_write(bcm, 0x0801,
+				  bcm43xx_phy_read(bcm, 0x0801) | 0x0040);
+		bcm43xx_phy_write(bcm, 0x0060,
+				  bcm43xx_phy_read(bcm, 0x0060) | 0x0040);
+		bcm43xx_phy_write(bcm, 0x0014,
+				  bcm43xx_phy_read(bcm, 0x0014) | 0x0200);
+	}
+	bcm43xx_radio_write16(bcm, 0x007A,
+			      bcm43xx_radio_read16(bcm, 0x007A) | 0x0070);
+	bcm43xx_radio_write16(bcm, 0x007A,
+			      bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
+	udelay(30);
+
+	v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
+	if (v47F >= 0x20)
+		v47F -= 0x40;
+	if (v47F == 31) {
+		for (i = 7; i >= 4; i--) {
+			bcm43xx_radio_write16(bcm, 0x007B, i);
+			udelay(20);
+			v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
+			if (v47F >= 0x20)
+				v47F -= 0x40;
+			if (v47F < 31 && saved == 0xFFFF)
+				saved = i;
+		}
+		if (saved == 0xFFFF)
+			saved = 4;
+	} else {
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
+		bcm43xx_phy_write(bcm, 0x0814,
+				  bcm43xx_phy_read(bcm, 0x0814) | 0x0001);
+		bcm43xx_phy_write(bcm, 0x0815,
+				  bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE);
+		bcm43xx_phy_write(bcm, 0x0811,
+				  bcm43xx_phy_read(bcm, 0x0811) | 0x000C);
+		bcm43xx_phy_write(bcm, 0x0812,
+				  bcm43xx_phy_read(bcm, 0x0812) | 0x000C);
+		bcm43xx_phy_write(bcm, 0x0811,
+				  bcm43xx_phy_read(bcm, 0x0811) | 0x0030);
+		bcm43xx_phy_write(bcm, 0x0812,
+				  bcm43xx_phy_read(bcm, 0x0812) | 0x0030);
+		bcm43xx_phy_write(bcm, 0x005A, 0x0480);
+		bcm43xx_phy_write(bcm, 0x0059, 0x0810);
+		bcm43xx_phy_write(bcm, 0x0058, 0x000D);
+		if (phy->rev == 0) {
+			bcm43xx_phy_write(bcm, 0x0003, 0x0122);
+		} else {
+			bcm43xx_phy_write(bcm, 0x000A,
+					  bcm43xx_phy_read(bcm, 0x000A)
+					  | 0x2000);
+		}
+		bcm43xx_phy_write(bcm, 0x0814,
+				  bcm43xx_phy_read(bcm, 0x0814) | 0x0004);
+		bcm43xx_phy_write(bcm, 0x0815,
+				  bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB);
+		bcm43xx_phy_write(bcm, 0x0003,
+				  (bcm43xx_phy_read(bcm, 0x0003) & 0xFF9F)
+				  | 0x0040);
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) | 0x000F);
+		bcm43xx_set_all_gains(bcm, 3, 0, 1);
+		bcm43xx_radio_write16(bcm, 0x0043,
+				      (bcm43xx_radio_read16(bcm, 0x0043)
+				       & 0x00F0) | 0x000F);
+		udelay(30);
+		v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
+		if (v47F >= 0x20)
+			v47F -= 0x40;
+		if (v47F == -32) {
+			for (i = 0; i < 4; i++) {
+				bcm43xx_radio_write16(bcm, 0x007B, i);
+				udelay(20);
+				v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
+				if (v47F >= 0x20)
+					v47F -= 0x40;
+				if (v47F > -31 && saved == 0xFFFF)
+					saved = i;
+			}
+			if (saved == 0xFFFF)
+				saved = 3;
+		} else
+			saved = 0;
+	}
+	bcm43xx_radio_write16(bcm, 0x007B, saved);
+
+	if (phy->rev >= 6) {
+		bcm43xx_phy_write(bcm, 0x002E, backup[12]);
+		bcm43xx_phy_write(bcm, 0x002F, backup[13]);
+		bcm43xx_phy_write(bcm, 0x080F, backup[14]);
+		bcm43xx_phy_write(bcm, 0x0810, backup[15]);
+	}
+	bcm43xx_phy_write(bcm, 0x0814, backup[3]);
+	bcm43xx_phy_write(bcm, 0x0815, backup[4]);
+	bcm43xx_phy_write(bcm, 0x005A, backup[5]);
+	bcm43xx_phy_write(bcm, 0x0059, backup[6]);
+	bcm43xx_phy_write(bcm, 0x0058, backup[7]);
+	bcm43xx_phy_write(bcm, 0x000A, backup[8]);
+	bcm43xx_phy_write(bcm, 0x0003, backup[9]);
+	bcm43xx_radio_write16(bcm, 0x0043, backup[11]);
+	bcm43xx_radio_write16(bcm, 0x007A, backup[10]);
+	bcm43xx_phy_write(bcm, 0x0802,
+			  bcm43xx_phy_read(bcm, 0x0802) | 0x1 | 0x2);
+	bcm43xx_phy_write(bcm, 0x0429,
+			  bcm43xx_phy_read(bcm, 0x0429) | 0x8000);
+	bcm43xx_set_original_gains(bcm);
+	if (phy->rev >= 6) {
+		bcm43xx_phy_write(bcm, 0x0801, backup[16]);
+		bcm43xx_phy_write(bcm, 0x0060, backup[17]);
+		bcm43xx_phy_write(bcm, 0x0014, backup[18]);
+		bcm43xx_phy_write(bcm, 0x0478, backup[19]);
+	}
+	bcm43xx_phy_write(bcm, 0x0001, backup[0]);
+	bcm43xx_phy_write(bcm, 0x0812, backup[2]);
+	bcm43xx_phy_write(bcm, 0x0811, backup[1]);
+}
+
+void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 backup[18] = { 0 };
+	u16 tmp;
+	s16 nrssi0, nrssi1;
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_B:
+		backup[0] = bcm43xx_radio_read16(bcm, 0x007A);
+		backup[1] = bcm43xx_radio_read16(bcm, 0x0052);
+		backup[2] = bcm43xx_radio_read16(bcm, 0x0043);
+		backup[3] = bcm43xx_phy_read(bcm, 0x0030);
+		backup[4] = bcm43xx_phy_read(bcm, 0x0026);
+		backup[5] = bcm43xx_phy_read(bcm, 0x0015);
+		backup[6] = bcm43xx_phy_read(bcm, 0x002A);
+		backup[7] = bcm43xx_phy_read(bcm, 0x0020);
+		backup[8] = bcm43xx_phy_read(bcm, 0x005A);
+		backup[9] = bcm43xx_phy_read(bcm, 0x0059);
+		backup[10] = bcm43xx_phy_read(bcm, 0x0058);
+		backup[11] = bcm43xx_read16(bcm, 0x03E2);
+		backup[12] = bcm43xx_read16(bcm, 0x03E6);
+		backup[13] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
+
+		tmp  = bcm43xx_radio_read16(bcm, 0x007A);
+		tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
+		bcm43xx_radio_write16(bcm, 0x007A, tmp);
+		bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
+		bcm43xx_write16(bcm, 0x03EC, 0x7F7F);
+		bcm43xx_phy_write(bcm, 0x0026, 0x0000);
+		bcm43xx_phy_write(bcm, 0x0015,
+				  bcm43xx_phy_read(bcm, 0x0015) | 0x0020);
+		bcm43xx_phy_write(bcm, 0x002A, 0x08A3);
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
+
+		nrssi0 = (s16)bcm43xx_phy_read(bcm, 0x0027);
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
+		if (phy->rev >= 2) {
+			bcm43xx_write16(bcm, 0x03E6, 0x0040);
+		} else if (phy->rev == 0) {
+			bcm43xx_write16(bcm, 0x03E6, 0x0122);
+		} else {
+			bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
+					bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) & 0x2000);
+		}
+		bcm43xx_phy_write(bcm, 0x0020, 0x3F3F);
+		bcm43xx_phy_write(bcm, 0x0015, 0xF330);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0060);
+		bcm43xx_radio_write16(bcm, 0x0043,
+				      bcm43xx_radio_read16(bcm, 0x0043) & 0x00F0);
+		bcm43xx_phy_write(bcm, 0x005A, 0x0480);
+		bcm43xx_phy_write(bcm, 0x0059, 0x0810);
+		bcm43xx_phy_write(bcm, 0x0058, 0x000D);
+		udelay(20);
+
+		nrssi1 = (s16)bcm43xx_phy_read(bcm, 0x0027);
+		bcm43xx_phy_write(bcm, 0x0030, backup[3]);
+		bcm43xx_radio_write16(bcm, 0x007A, backup[0]);
+		bcm43xx_write16(bcm, 0x03E2, backup[11]);
+		bcm43xx_phy_write(bcm, 0x0026, backup[4]);
+		bcm43xx_phy_write(bcm, 0x0015, backup[5]);
+		bcm43xx_phy_write(bcm, 0x002A, backup[6]);
+		bcm43xx_synth_pu_workaround(bcm, radio->channel);
+		if (phy->rev != 0)
+			bcm43xx_write16(bcm, 0x03F4, backup[13]);
+
+		bcm43xx_phy_write(bcm, 0x0020, backup[7]);
+		bcm43xx_phy_write(bcm, 0x005A, backup[8]);
+		bcm43xx_phy_write(bcm, 0x0059, backup[9]);
+		bcm43xx_phy_write(bcm, 0x0058, backup[10]);
+		bcm43xx_radio_write16(bcm, 0x0052, backup[1]);
+		bcm43xx_radio_write16(bcm, 0x0043, backup[2]);
+
+		if (nrssi0 == nrssi1)
+			radio->nrssislope = 0x00010000;
+		else 
+			radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+
+		if (nrssi0 <= -4) {
+			radio->nrssi[0] = nrssi0;
+			radio->nrssi[1] = nrssi1;
+		}
+		break;
+	case BCM43xx_PHYTYPE_G:
+		if (radio->revision >= 9)
+			return;
+		if (radio->revision == 8)
+			bcm43xx_calc_nrssi_offset(bcm);
+
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+				  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF);
+		bcm43xx_phy_write(bcm, 0x0802,
+				  bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC);
+		backup[7] = bcm43xx_read16(bcm, 0x03E2);
+		bcm43xx_write16(bcm, 0x03E2,
+				bcm43xx_read16(bcm, 0x03E2) | 0x8000);
+		backup[0] = bcm43xx_radio_read16(bcm, 0x007A);
+		backup[1] = bcm43xx_radio_read16(bcm, 0x0052);
+		backup[2] = bcm43xx_radio_read16(bcm, 0x0043);
+		backup[3] = bcm43xx_phy_read(bcm, 0x0015);
+		backup[4] = bcm43xx_phy_read(bcm, 0x005A);
+		backup[5] = bcm43xx_phy_read(bcm, 0x0059);
+		backup[6] = bcm43xx_phy_read(bcm, 0x0058);
+		backup[8] = bcm43xx_read16(bcm, 0x03E6);
+		backup[9] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
+		if (phy->rev >= 3) {
+			backup[10] = bcm43xx_phy_read(bcm, 0x002E);
+			backup[11] = bcm43xx_phy_read(bcm, 0x002F);
+			backup[12] = bcm43xx_phy_read(bcm, 0x080F);
+			backup[13] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_LO_CONTROL);
+			backup[14] = bcm43xx_phy_read(bcm, 0x0801);
+			backup[15] = bcm43xx_phy_read(bcm, 0x0060);
+			backup[16] = bcm43xx_phy_read(bcm, 0x0014);
+			backup[17] = bcm43xx_phy_read(bcm, 0x0478);
+			bcm43xx_phy_write(bcm, 0x002E, 0);
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, 0);
+			switch (phy->rev) {
+			case 4: case 6: case 7:
+				bcm43xx_phy_write(bcm, 0x0478,
+						  bcm43xx_phy_read(bcm, 0x0478)
+						  | 0x0100);
+				bcm43xx_phy_write(bcm, 0x0801,
+						  bcm43xx_phy_read(bcm, 0x0801)
+						  | 0x0040);
+				break;
+			case 3: case 5:
+				bcm43xx_phy_write(bcm, 0x0801,
+						  bcm43xx_phy_read(bcm, 0x0801)
+						  & 0xFFBF);
+				break;
+			}
+			bcm43xx_phy_write(bcm, 0x0060,
+					  bcm43xx_phy_read(bcm, 0x0060)
+					  | 0x0040);
+			bcm43xx_phy_write(bcm, 0x0014,
+					  bcm43xx_phy_read(bcm, 0x0014)
+					  | 0x0200);
+		}
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) | 0x0070);
+		bcm43xx_set_all_gains(bcm, 0, 8, 0);
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) & 0x00F7);
+		if (phy->rev >= 2) {
+			bcm43xx_phy_write(bcm, 0x0811,
+					  (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0030);
+			bcm43xx_phy_write(bcm, 0x0812,
+					  (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0010);
+		}
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
+		udelay(20);
+
+		nrssi0 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
+		if (nrssi0 >= 0x0020)
+			nrssi0 -= 0x0040;
+
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
+		if (phy->rev >= 2) {
+			bcm43xx_phy_write(bcm, 0x0003,
+					  (bcm43xx_phy_read(bcm, 0x0003)
+					   & 0xFF9F) | 0x0040);
+		}
+
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
+				bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
+				| 0x2000);
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) | 0x000F);
+		bcm43xx_phy_write(bcm, 0x0015, 0xF330);
+		if (phy->rev >= 2) {
+			bcm43xx_phy_write(bcm, 0x0812,
+					  (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0020);
+			bcm43xx_phy_write(bcm, 0x0811,
+					  (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0020);
+		}
+
+		bcm43xx_set_all_gains(bcm, 3, 0, 1);
+		if (radio->revision == 8) {
+			bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
+		} else {
+			tmp = bcm43xx_radio_read16(bcm, 0x0052) & 0xFF0F;
+			bcm43xx_radio_write16(bcm, 0x0052, tmp | 0x0060);
+			tmp = bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0;
+			bcm43xx_radio_write16(bcm, 0x0043, tmp | 0x0009);
+		}
+		bcm43xx_phy_write(bcm, 0x005A, 0x0480);
+		bcm43xx_phy_write(bcm, 0x0059, 0x0810);
+		bcm43xx_phy_write(bcm, 0x0058, 0x000D);
+		udelay(20);
+		nrssi1 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
+		if (nrssi1 >= 0x0020)
+			nrssi1 -= 0x0040;
+		if (nrssi0 == nrssi1)
+			radio->nrssislope = 0x00010000;
+		else
+			radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+		if (nrssi0 >= -4) {
+			radio->nrssi[0] = nrssi1;
+			radio->nrssi[1] = nrssi0;
+		}
+		if (phy->rev >= 3) {
+			bcm43xx_phy_write(bcm, 0x002E, backup[10]);
+			bcm43xx_phy_write(bcm, 0x002F, backup[11]);
+			bcm43xx_phy_write(bcm, 0x080F, backup[12]);
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, backup[13]);
+		}
+		if (phy->rev >= 2) {
+			bcm43xx_phy_write(bcm, 0x0812,
+					  bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF);
+			bcm43xx_phy_write(bcm, 0x0811,
+					  bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF);
+		}
+
+		bcm43xx_radio_write16(bcm, 0x007A, backup[0]);
+		bcm43xx_radio_write16(bcm, 0x0052, backup[1]);
+		bcm43xx_radio_write16(bcm, 0x0043, backup[2]);
+		bcm43xx_write16(bcm, 0x03E2, backup[7]);
+		bcm43xx_write16(bcm, 0x03E6, backup[8]);
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[9]);
+		bcm43xx_phy_write(bcm, 0x0015, backup[3]);
+		bcm43xx_phy_write(bcm, 0x005A, backup[4]);
+		bcm43xx_phy_write(bcm, 0x0059, backup[5]);
+		bcm43xx_phy_write(bcm, 0x0058, backup[6]);
+		bcm43xx_synth_pu_workaround(bcm, radio->channel);
+		bcm43xx_phy_write(bcm, 0x0802,
+				  bcm43xx_phy_read(bcm, 0x0802) | (0x0001 | 0x0002));
+		bcm43xx_set_original_gains(bcm);
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+				  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000);
+		if (phy->rev >= 3) {
+			bcm43xx_phy_write(bcm, 0x0801, backup[14]);
+			bcm43xx_phy_write(bcm, 0x0060, backup[15]);
+			bcm43xx_phy_write(bcm, 0x0014, backup[16]);
+			bcm43xx_phy_write(bcm, 0x0478, backup[17]);
+		}
+		bcm43xx_nrssi_mem_update(bcm);
+		bcm43xx_calc_nrssi_threshold(bcm);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	s32 threshold;
+	s32 a, b;
+	s16 tmp16;
+	u16 tmp_u16;
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_B: {
+		if (radio->version != 0x2050)
+			return;
+		if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI))
+			return;
+
+		if (radio->revision >= 6) {
+			threshold = (radio->nrssi[1] - radio->nrssi[0]) * 32;
+			threshold += 20 * (radio->nrssi[0] + 1);
+			threshold /= 40;
+		} else
+			threshold = radio->nrssi[1] - 5;
+
+		threshold = limit_value(threshold, 0, 0x3E);
+		bcm43xx_phy_read(bcm, 0x0020); /* dummy read */
+		bcm43xx_phy_write(bcm, 0x0020, (((u16)threshold) << 8) | 0x001C);
+
+		if (radio->revision >= 6) {
+			bcm43xx_phy_write(bcm, 0x0087, 0x0E0D);
+			bcm43xx_phy_write(bcm, 0x0086, 0x0C0B);
+			bcm43xx_phy_write(bcm, 0x0085, 0x0A09);
+			bcm43xx_phy_write(bcm, 0x0084, 0x0808);
+			bcm43xx_phy_write(bcm, 0x0083, 0x0808);
+			bcm43xx_phy_write(bcm, 0x0082, 0x0604);
+			bcm43xx_phy_write(bcm, 0x0081, 0x0302);
+			bcm43xx_phy_write(bcm, 0x0080, 0x0100);
+		}
+		break;
+	}
+	case BCM43xx_PHYTYPE_G:
+		if (!phy->connected ||
+		    !(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) {
+			tmp16 = bcm43xx_nrssi_hw_read(bcm, 0x20);
+			if (tmp16 >= 0x20)
+				tmp16 -= 0x40;
+			if (tmp16 < 3) {
+				bcm43xx_phy_write(bcm, 0x048A,
+						  (bcm43xx_phy_read(bcm, 0x048A)
+						   & 0xF000) | 0x09EB);
+			} else {
+				bcm43xx_phy_write(bcm, 0x048A,
+						  (bcm43xx_phy_read(bcm, 0x048A)
+						   & 0xF000) | 0x0AED);
+			}
+		} else {
+			if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN) {
+				a = 0xE;
+				b = 0xA;
+			} else if (!radio->aci_wlan_automatic && radio->aci_enable) {
+				a = 0x13;
+				b = 0x12;
+			} else {
+				a = 0xE;
+				b = 0x11;
+			}
+
+			a = a * (radio->nrssi[1] - radio->nrssi[0]);
+			a += (radio->nrssi[0] << 6);
+			if (a < 32)
+				a += 31;
+			else
+				a += 32;
+			a = a >> 6;
+			a = limit_value(a, -31, 31);
+
+			b = b * (radio->nrssi[1] - radio->nrssi[0]);
+			b += (radio->nrssi[0] << 6);
+			if (b < 32)
+				b += 31;
+			else
+				b += 32;
+			b = b >> 6;
+			b = limit_value(b, -31, 31);
+
+			tmp_u16 = bcm43xx_phy_read(bcm, 0x048A) & 0xF000;
+			tmp_u16 |= ((u32)b & 0x0000003F);
+			tmp_u16 |= (((u32)a & 0x0000003F) << 6);
+			bcm43xx_phy_write(bcm, 0x048A, tmp_u16);
+		}
+		break;
+	default:
+		assert(0);
+	}
+}
+
+/* Stack implementation to save/restore values from the
+ * interference mitigation code.
+ * It is save to restore values in random order.
+ */
+static void _stack_save(u32 *_stackptr, size_t *stackidx,
+			u8 id, u16 offset, u16 value)
+{
+	u32 *stackptr = &(_stackptr[*stackidx]);
+
+	assert((offset & 0xF000) == 0x0000);
+	assert((id & 0xF0) == 0x00);
+	*stackptr = offset;
+	*stackptr |= ((u32)id) << 12;
+	*stackptr |= ((u32)value) << 16;
+	(*stackidx)++;
+	assert(*stackidx < BCM43xx_INTERFSTACK_SIZE);
+}
+
+static u16 _stack_restore(u32 *stackptr,
+			  u8 id, u16 offset)
+{
+	size_t i;
+
+	assert((offset & 0xF000) == 0x0000);
+	assert((id & 0xF0) == 0x00);
+	for (i = 0; i < BCM43xx_INTERFSTACK_SIZE; i++, stackptr++) {
+		if ((*stackptr & 0x00000FFF) != offset)
+			continue;
+		if (((*stackptr & 0x0000F000) >> 12) != id)
+			continue;
+		return ((*stackptr & 0xFFFF0000) >> 16);
+	}
+	assert(0);
+
+	return 0;
+}
+
+#define phy_stacksave(offset)					\
+	do {							\
+		_stack_save(stack, &stackidx, 0x1, (offset),	\
+			    bcm43xx_phy_read(bcm, (offset)));	\
+	} while (0)
+#define phy_stackrestore(offset)				\
+	do {							\
+		bcm43xx_phy_write(bcm, (offset),		\
+				  _stack_restore(stack, 0x1,	\
+					  	 (offset)));	\
+	} while (0)
+#define radio_stacksave(offset)						\
+	do {								\
+		_stack_save(stack, &stackidx, 0x2, (offset),		\
+			    bcm43xx_radio_read16(bcm, (offset)));	\
+	} while (0)
+#define radio_stackrestore(offset)					\
+	do {								\
+		bcm43xx_radio_write16(bcm, (offset),			\
+				      _stack_restore(stack, 0x2,	\
+						     (offset)));	\
+	} while (0)
+#define ilt_stacksave(offset)					\
+	do {							\
+		_stack_save(stack, &stackidx, 0x3, (offset),	\
+			    bcm43xx_ilt_read(bcm, (offset)));	\
+	} while (0)
+#define ilt_stackrestore(offset)				\
+	do {							\
+		bcm43xx_ilt_write(bcm, (offset),		\
+				  _stack_restore(stack, 0x3,	\
+						 (offset)));	\
+	} while (0)
+
+static void
+bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm,
+					     int mode)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 tmp, flipped;
+	u32 tmp32;
+	size_t stackidx = 0;
+	u32 *stack = radio->interfstack;
+
+	switch (mode) {
+	case BCM43xx_RADIO_INTERFMODE_NONWLAN:
+		if (phy->rev != 1) {
+			bcm43xx_phy_write(bcm, 0x042B,
+			                  bcm43xx_phy_read(bcm, 0x042B) | 0x0800);
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+			                  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & ~0x4000);
+			break;
+		}
+		radio_stacksave(0x0078);
+		tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E);
+		flipped = flip_4bit(tmp);
+		if (flipped < 10 && flipped >= 8)
+			flipped = 7;
+		else if (flipped >= 10)
+			flipped -= 3;
+		flipped = flip_4bit(flipped);
+		flipped = (flipped << 1) | 0x0020;
+		bcm43xx_radio_write16(bcm, 0x0078, flipped);
+
+		bcm43xx_calc_nrssi_threshold(bcm);
+
+		phy_stacksave(0x0406);
+		bcm43xx_phy_write(bcm, 0x0406, 0x7E28);
+
+		bcm43xx_phy_write(bcm, 0x042B,
+		                  bcm43xx_phy_read(bcm, 0x042B) | 0x0800);
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
+		                  bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | 0x1000);
+
+		phy_stacksave(0x04A0);
+		bcm43xx_phy_write(bcm, 0x04A0,
+		                  (bcm43xx_phy_read(bcm, 0x04A0) & 0xC0C0) | 0x0008);
+		phy_stacksave(0x04A1);
+		bcm43xx_phy_write(bcm, 0x04A1,
+				  (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0C0) | 0x0605);
+		phy_stacksave(0x04A2);
+		bcm43xx_phy_write(bcm, 0x04A2,
+				  (bcm43xx_phy_read(bcm, 0x04A2) & 0xC0C0) | 0x0204);
+		phy_stacksave(0x04A8);
+		bcm43xx_phy_write(bcm, 0x04A8,
+				  (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0803);
+		phy_stacksave(0x04AB);
+		bcm43xx_phy_write(bcm, 0x04AB,
+				  (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0605);
+
+		phy_stacksave(0x04A7);
+		bcm43xx_phy_write(bcm, 0x04A7, 0x0002);
+		phy_stacksave(0x04A3);
+		bcm43xx_phy_write(bcm, 0x04A3, 0x287A);
+		phy_stacksave(0x04A9);
+		bcm43xx_phy_write(bcm, 0x04A9, 0x2027);
+		phy_stacksave(0x0493);
+		bcm43xx_phy_write(bcm, 0x0493, 0x32F5);
+		phy_stacksave(0x04AA);
+		bcm43xx_phy_write(bcm, 0x04AA, 0x2027);
+		phy_stacksave(0x04AC);
+		bcm43xx_phy_write(bcm, 0x04AC, 0x32F5);
+		break;
+	case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
+		if (bcm43xx_phy_read(bcm, 0x0033) & 0x0800)
+			break;
+
+		radio->aci_enable = 1;
+
+		phy_stacksave(BCM43xx_PHY_RADIO_BITFIELD);
+		phy_stacksave(BCM43xx_PHY_G_CRS);
+		if (phy->rev < 2) {
+			phy_stacksave(0x0406);
+		} else {
+			phy_stacksave(0x04C0);
+			phy_stacksave(0x04C1);
+		}
+		phy_stacksave(0x0033);
+		phy_stacksave(0x04A7);
+		phy_stacksave(0x04A3);
+		phy_stacksave(0x04A9);
+		phy_stacksave(0x04AA);
+		phy_stacksave(0x04AC);
+		phy_stacksave(0x0493);
+		phy_stacksave(0x04A1);
+		phy_stacksave(0x04A0);
+		phy_stacksave(0x04A2);
+		phy_stacksave(0x048A);
+		phy_stacksave(0x04A8);
+		phy_stacksave(0x04AB);
+		if (phy->rev == 2) {
+			phy_stacksave(0x04AD);
+			phy_stacksave(0x04AE);
+		} else if (phy->rev >= 3) {
+			phy_stacksave(0x04AD);
+			phy_stacksave(0x0415);
+			phy_stacksave(0x0416);
+			phy_stacksave(0x0417);
+			ilt_stacksave(0x1A00 + 0x2);
+			ilt_stacksave(0x1A00 + 0x3);
+		}
+		phy_stacksave(0x042B);
+		phy_stacksave(0x048C);
+
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
+				  bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD)
+				  & ~0x1000);
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+				  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+				   & 0xFFFC) | 0x0002);
+
+		bcm43xx_phy_write(bcm, 0x0033, 0x0800);
+		bcm43xx_phy_write(bcm, 0x04A3, 0x2027);
+		bcm43xx_phy_write(bcm, 0x04A9, 0x1CA8);
+		bcm43xx_phy_write(bcm, 0x0493, 0x287A);
+		bcm43xx_phy_write(bcm, 0x04AA, 0x1CA8);
+		bcm43xx_phy_write(bcm, 0x04AC, 0x287A);
+
+		bcm43xx_phy_write(bcm, 0x04A0,
+				  (bcm43xx_phy_read(bcm, 0x04A0)
+				   & 0xFFC0) | 0x001A);
+		bcm43xx_phy_write(bcm, 0x04A7, 0x000D);
+
+		if (phy->rev < 2) {
+			bcm43xx_phy_write(bcm, 0x0406, 0xFF0D);
+		} else if (phy->rev == 2) {
+			bcm43xx_phy_write(bcm, 0x04C0, 0xFFFF);
+			bcm43xx_phy_write(bcm, 0x04C1, 0x00A9);
+		} else {
+			bcm43xx_phy_write(bcm, 0x04C0, 0x00C1);
+			bcm43xx_phy_write(bcm, 0x04C1, 0x0059);
+		}
+
+		bcm43xx_phy_write(bcm, 0x04A1,
+		                  (bcm43xx_phy_read(bcm, 0x04A1)
+				   & 0xC0FF) | 0x1800);
+		bcm43xx_phy_write(bcm, 0x04A1,
+		                  (bcm43xx_phy_read(bcm, 0x04A1)
+				   & 0xFFC0) | 0x0015);
+		bcm43xx_phy_write(bcm, 0x04A8,
+		                  (bcm43xx_phy_read(bcm, 0x04A8)
+				   & 0xCFFF) | 0x1000);
+		bcm43xx_phy_write(bcm, 0x04A8,
+		                  (bcm43xx_phy_read(bcm, 0x04A8)
+				   & 0xF0FF) | 0x0A00);
+		bcm43xx_phy_write(bcm, 0x04AB,
+		                  (bcm43xx_phy_read(bcm, 0x04AB)
+				   & 0xCFFF) | 0x1000);
+		bcm43xx_phy_write(bcm, 0x04AB,
+		                  (bcm43xx_phy_read(bcm, 0x04AB)
+				   & 0xF0FF) | 0x0800);
+		bcm43xx_phy_write(bcm, 0x04AB,
+		                  (bcm43xx_phy_read(bcm, 0x04AB)
+				   & 0xFFCF) | 0x0010);
+		bcm43xx_phy_write(bcm, 0x04AB,
+		                  (bcm43xx_phy_read(bcm, 0x04AB)
+				   & 0xFFF0) | 0x0005);
+		bcm43xx_phy_write(bcm, 0x04A8,
+		                  (bcm43xx_phy_read(bcm, 0x04A8)
+				   & 0xFFCF) | 0x0010);
+		bcm43xx_phy_write(bcm, 0x04A8,
+		                  (bcm43xx_phy_read(bcm, 0x04A8)
+				   & 0xFFF0) | 0x0006);
+		bcm43xx_phy_write(bcm, 0x04A2,
+		                  (bcm43xx_phy_read(bcm, 0x04A2)
+				   & 0xF0FF) | 0x0800);
+		bcm43xx_phy_write(bcm, 0x04A0,
+				  (bcm43xx_phy_read(bcm, 0x04A0)
+				   & 0xF0FF) | 0x0500);
+		bcm43xx_phy_write(bcm, 0x04A2,
+				  (bcm43xx_phy_read(bcm, 0x04A2)
+				   & 0xFFF0) | 0x000B);
+
+		if (phy->rev >= 3) {
+			bcm43xx_phy_write(bcm, 0x048A,
+					  bcm43xx_phy_read(bcm, 0x048A)
+					  & ~0x8000);
+			bcm43xx_phy_write(bcm, 0x0415,
+					  (bcm43xx_phy_read(bcm, 0x0415)
+					   & 0x8000) | 0x36D8);
+			bcm43xx_phy_write(bcm, 0x0416,
+					  (bcm43xx_phy_read(bcm, 0x0416)
+					   & 0x8000) | 0x36D8);
+			bcm43xx_phy_write(bcm, 0x0417,
+					  (bcm43xx_phy_read(bcm, 0x0417)
+					   & 0xFE00) | 0x016D);
+		} else {
+			bcm43xx_phy_write(bcm, 0x048A,
+					  bcm43xx_phy_read(bcm, 0x048A)
+					  | 0x1000);
+			bcm43xx_phy_write(bcm, 0x048A,
+					  (bcm43xx_phy_read(bcm, 0x048A)
+					   & 0x9FFF) | 0x2000);
+			tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+						   BCM43xx_UCODEFLAGS_OFFSET);
+			if (!(tmp32 & 0x800)) {
+				tmp32 |= 0x800;
+				bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+						    BCM43xx_UCODEFLAGS_OFFSET,
+						    tmp32);
+			}
+		}
+		if (phy->rev >= 2) {
+			bcm43xx_phy_write(bcm, 0x042B,
+					  bcm43xx_phy_read(bcm, 0x042B)
+					  | 0x0800);
+		}
+		bcm43xx_phy_write(bcm, 0x048C,
+				  (bcm43xx_phy_read(bcm, 0x048C)
+				   & 0xF0FF) | 0x0200);
+		if (phy->rev == 2) {
+			bcm43xx_phy_write(bcm, 0x04AE,
+					  (bcm43xx_phy_read(bcm, 0x04AE)
+					   & 0xFF00) | 0x007F);
+			bcm43xx_phy_write(bcm, 0x04AD,
+					  (bcm43xx_phy_read(bcm, 0x04AD)
+					   & 0x00FF) | 0x1300);
+		} else if (phy->rev >= 6) {
+			bcm43xx_ilt_write(bcm, 0x1A00 + 0x3, 0x007F);
+			bcm43xx_ilt_write(bcm, 0x1A00 + 0x2, 0x007F);
+			bcm43xx_phy_write(bcm, 0x04AD,
+					  bcm43xx_phy_read(bcm, 0x04AD)
+					  & 0x00FF);
+		}
+		bcm43xx_calc_nrssi_slope(bcm);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+static void
+bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm,
+					      int mode)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u32 tmp32;
+	u32 *stack = radio->interfstack;
+
+	switch (mode) {
+	case BCM43xx_RADIO_INTERFMODE_NONWLAN:
+		if (phy->rev != 1) {
+			bcm43xx_phy_write(bcm, 0x042B,
+			                  bcm43xx_phy_read(bcm, 0x042B) & ~0x0800);
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+			                  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000);
+			break;
+		}
+		phy_stackrestore(0x0078);
+		bcm43xx_calc_nrssi_threshold(bcm);
+		phy_stackrestore(0x0406);
+		bcm43xx_phy_write(bcm, 0x042B,
+				  bcm43xx_phy_read(bcm, 0x042B) & ~0x0800);
+		if (!bcm->bad_frames_preempt) {
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
+					  bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD)
+					  & ~(1 << 11));
+		}
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+				  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000);
+		phy_stackrestore(0x04A0);
+		phy_stackrestore(0x04A1);
+		phy_stackrestore(0x04A2);
+		phy_stackrestore(0x04A8);
+		phy_stackrestore(0x04AB);
+		phy_stackrestore(0x04A7);
+		phy_stackrestore(0x04A3);
+		phy_stackrestore(0x04A9);
+		phy_stackrestore(0x0493);
+		phy_stackrestore(0x04AA);
+		phy_stackrestore(0x04AC);
+		break;
+	case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
+		if (!(bcm43xx_phy_read(bcm, 0x0033) & 0x0800))
+			break;
+
+		radio->aci_enable = 0;
+
+		phy_stackrestore(BCM43xx_PHY_RADIO_BITFIELD);
+		phy_stackrestore(BCM43xx_PHY_G_CRS);
+		phy_stackrestore(0x0033);
+		phy_stackrestore(0x04A3);
+		phy_stackrestore(0x04A9);
+		phy_stackrestore(0x0493);
+		phy_stackrestore(0x04AA);
+		phy_stackrestore(0x04AC);
+		phy_stackrestore(0x04A0);
+		phy_stackrestore(0x04A7);
+		if (phy->rev >= 2) {
+			phy_stackrestore(0x04C0);
+			phy_stackrestore(0x04C1);
+		} else
+			phy_stackrestore(0x0406);
+		phy_stackrestore(0x04A1);
+		phy_stackrestore(0x04AB);
+		phy_stackrestore(0x04A8);
+		if (phy->rev == 2) {
+			phy_stackrestore(0x04AD);
+			phy_stackrestore(0x04AE);
+		} else if (phy->rev >= 3) {
+			phy_stackrestore(0x04AD);
+			phy_stackrestore(0x0415);
+			phy_stackrestore(0x0416);
+			phy_stackrestore(0x0417);
+			ilt_stackrestore(0x1A00 + 0x2);
+			ilt_stackrestore(0x1A00 + 0x3);
+		}
+		phy_stackrestore(0x04A2);
+		phy_stackrestore(0x04A8);
+		phy_stackrestore(0x042B);
+		phy_stackrestore(0x048C);
+		tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+					   BCM43xx_UCODEFLAGS_OFFSET);
+		if (tmp32 & 0x800) {
+			tmp32 &= ~0x800;
+			bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+					    BCM43xx_UCODEFLAGS_OFFSET,
+					    tmp32);
+		}
+		bcm43xx_calc_nrssi_slope(bcm);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+#undef phy_stacksave
+#undef phy_stackrestore
+#undef radio_stacksave
+#undef radio_stackrestore
+#undef ilt_stacksave
+#undef ilt_stackrestore
+
+int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm,
+					      int mode)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	int currentmode;
+
+	if ((phy->type != BCM43xx_PHYTYPE_G) ||
+	    (phy->rev == 0) ||
+	    (!phy->connected))
+		return -ENODEV;
+
+	radio->aci_wlan_automatic = 0;
+	switch (mode) {
+	case BCM43xx_RADIO_INTERFMODE_AUTOWLAN:
+		radio->aci_wlan_automatic = 1;
+		if (radio->aci_enable)
+			mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
+		else
+			mode = BCM43xx_RADIO_INTERFMODE_NONE;
+		break;
+	case BCM43xx_RADIO_INTERFMODE_NONE:
+	case BCM43xx_RADIO_INTERFMODE_NONWLAN:
+	case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	currentmode = radio->interfmode;
+	if (currentmode == mode)
+		return 0;
+	if (currentmode != BCM43xx_RADIO_INTERFMODE_NONE)
+		bcm43xx_radio_interference_mitigation_disable(bcm, currentmode);
+
+	if (mode == BCM43xx_RADIO_INTERFMODE_NONE) {
+		radio->aci_enable = 0;
+		radio->aci_hw_rssi = 0;
+	} else
+		bcm43xx_radio_interference_mitigation_enable(bcm, mode);
+	radio->interfmode = mode;
+
+	return 0;
+}
+
+u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm)
+{
+	u16 reg, index, ret;
+
+	reg = bcm43xx_radio_read16(bcm, 0x0060);
+	index = (reg & 0x001E) >> 1;
+	ret = rcc_table[index] << 1;
+	ret |= (reg & 0x0001);
+	ret |= 0x0020;
+
+	return ret;
+}
+
+u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 backup[19] = { 0 };
+	u16 ret;
+	u16 i, j;
+	u32 tmp1 = 0, tmp2 = 0;
+
+	backup[0] = bcm43xx_radio_read16(bcm, 0x0043);
+	backup[14] = bcm43xx_radio_read16(bcm, 0x0051);
+	backup[15] = bcm43xx_radio_read16(bcm, 0x0052);
+	backup[1] = bcm43xx_phy_read(bcm, 0x0015);
+	backup[16] = bcm43xx_phy_read(bcm, 0x005A);
+	backup[17] = bcm43xx_phy_read(bcm, 0x0059);
+	backup[18] = bcm43xx_phy_read(bcm, 0x0058);
+	if (phy->type == BCM43xx_PHYTYPE_B) {
+		backup[2] = bcm43xx_phy_read(bcm, 0x0030);
+		backup[3] = bcm43xx_read16(bcm, 0x03EC);
+		bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
+		bcm43xx_write16(bcm, 0x03EC, 0x3F3F);
+	} else {
+		if (phy->connected) {
+			backup[4] = bcm43xx_phy_read(bcm, 0x0811);
+			backup[5] = bcm43xx_phy_read(bcm, 0x0812);
+			backup[6] = bcm43xx_phy_read(bcm, 0x0814);
+			backup[7] = bcm43xx_phy_read(bcm, 0x0815);
+			backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
+			backup[9] = bcm43xx_phy_read(bcm, 0x0802);
+			bcm43xx_phy_write(bcm, 0x0814,
+			                  (bcm43xx_phy_read(bcm, 0x0814) | 0x0003));
+			bcm43xx_phy_write(bcm, 0x0815,
+			                  (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC));	
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+			                  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF));
+			bcm43xx_phy_write(bcm, 0x0802,
+			                  (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
+			bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
+			bcm43xx_phy_write(bcm, 0x0812, 0x0FB2);
+		}
+		bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+		                (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
+	}
+	backup[10] = bcm43xx_phy_read(bcm, 0x0035);
+	bcm43xx_phy_write(bcm, 0x0035,
+	                  (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
+	backup[11] = bcm43xx_read16(bcm, 0x03E6);
+	backup[12] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
+
+	// Initialization
+	if (phy->version == 0) {
+		bcm43xx_write16(bcm, 0x03E6, 0x0122);
+	} else {
+		if (phy->version >= 2)
+			bcm43xx_write16(bcm, 0x03E6, 0x0040);
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
+		                (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000));
+	}
+
+	ret = bcm43xx_radio_calibrationvalue(bcm);
+
+	if (phy->type == BCM43xx_PHYTYPE_B)
+		bcm43xx_radio_write16(bcm, 0x0078, 0x0003);
+
+	bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
+	bcm43xx_phy_write(bcm, 0x002B, 0x1403);
+	if (phy->connected)
+		bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
+	bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
+	bcm43xx_radio_write16(bcm, 0x0051,
+	                      (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
+	bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
+	bcm43xx_radio_write16(bcm, 0x0043,
+			      bcm43xx_radio_read16(bcm, 0x0043) | 0x0009);
+	bcm43xx_phy_write(bcm, 0x0058, 0x0000);
+
+	for (i = 0; i < 16; i++) {
+		bcm43xx_phy_write(bcm, 0x005A, 0x0480);
+		bcm43xx_phy_write(bcm, 0x0059, 0xC810);
+		bcm43xx_phy_write(bcm, 0x0058, 0x000D);
+		if (phy->connected)
+			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+		bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
+		udelay(10);
+		if (phy->connected)
+			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+		bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
+		udelay(10);
+		if (phy->connected)
+			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+		bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
+		udelay(10);
+		tmp1 += bcm43xx_phy_read(bcm, 0x002D);
+		bcm43xx_phy_write(bcm, 0x0058, 0x0000);
+		if (phy->connected)
+			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+		bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
+	}
+
+	tmp1++;
+	tmp1 >>= 9;
+	udelay(10);
+	bcm43xx_phy_write(bcm, 0x0058, 0x0000);
+
+	for (i = 0; i < 16; i++) {
+		bcm43xx_radio_write16(bcm, 0x0078, (flip_4bit(i) << 1) | 0x0020);
+		backup[13] = bcm43xx_radio_read16(bcm, 0x0078);
+		udelay(10);
+		for (j = 0; j < 16; j++) {
+			bcm43xx_phy_write(bcm, 0x005A, 0x0D80);
+			bcm43xx_phy_write(bcm, 0x0059, 0xC810);
+			bcm43xx_phy_write(bcm, 0x0058, 0x000D);
+			if (phy->connected)
+				bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+			bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
+			udelay(10);
+			if (phy->connected)
+				bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+			bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
+			udelay(10);
+			if (phy->connected)
+				bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */
+			bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
+			udelay(10);
+			tmp2 += bcm43xx_phy_read(bcm, 0x002D);
+			bcm43xx_phy_write(bcm, 0x0058, 0x0000);
+			if (phy->connected)
+				bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+			bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
+		}
+		tmp2++;
+		tmp2 >>= 8;
+		if (tmp1 < tmp2)
+			break;
+	}
+
+	/* Restore the registers */
+	bcm43xx_phy_write(bcm, 0x0015, backup[1]);
+	bcm43xx_radio_write16(bcm, 0x0051, backup[14]);
+	bcm43xx_radio_write16(bcm, 0x0052, backup[15]);
+	bcm43xx_radio_write16(bcm, 0x0043, backup[0]);
+	bcm43xx_phy_write(bcm, 0x005A, backup[16]);
+	bcm43xx_phy_write(bcm, 0x0059, backup[17]);
+	bcm43xx_phy_write(bcm, 0x0058, backup[18]);
+	bcm43xx_write16(bcm, 0x03E6, backup[11]);
+	if (phy->version != 0)
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[12]);
+	bcm43xx_phy_write(bcm, 0x0035, backup[10]);
+	bcm43xx_radio_selectchannel(bcm, radio->channel, 1);
+	if (phy->type == BCM43xx_PHYTYPE_B) {
+		bcm43xx_phy_write(bcm, 0x0030, backup[2]);
+		bcm43xx_write16(bcm, 0x03EC, backup[3]);
+	} else {
+		bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+				(bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
+		if (phy->connected) {
+			bcm43xx_phy_write(bcm, 0x0811, backup[4]);
+			bcm43xx_phy_write(bcm, 0x0812, backup[5]);
+			bcm43xx_phy_write(bcm, 0x0814, backup[6]);
+			bcm43xx_phy_write(bcm, 0x0815, backup[7]);
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
+			bcm43xx_phy_write(bcm, 0x0802, backup[9]);
+		}
+	}
+	if (i >= 15)
+		ret = backup[13];
+
+	return ret;
+}
+
+void bcm43xx_radio_init2060(struct bcm43xx_private *bcm)
+{
+	int err;
+
+	bcm43xx_radio_write16(bcm, 0x0004, 0x00C0);
+	bcm43xx_radio_write16(bcm, 0x0005, 0x0008);
+	bcm43xx_radio_write16(bcm, 0x0009, 0x0040);
+	bcm43xx_radio_write16(bcm, 0x0005, 0x00AA);
+	bcm43xx_radio_write16(bcm, 0x0032, 0x008F);
+	bcm43xx_radio_write16(bcm, 0x0006, 0x008F);
+	bcm43xx_radio_write16(bcm, 0x0034, 0x008F);
+	bcm43xx_radio_write16(bcm, 0x002C, 0x0007);
+	bcm43xx_radio_write16(bcm, 0x0082, 0x0080);
+	bcm43xx_radio_write16(bcm, 0x0080, 0x0000);
+	bcm43xx_radio_write16(bcm, 0x003F, 0x00DA);
+	bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008);
+	bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0010);
+	bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020);
+	bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020);
+	udelay(400);
+
+	bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020) | 0x0010);
+	udelay(400);
+
+	bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008) | 0x0008);
+	bcm43xx_radio_write16(bcm, 0x0085, bcm43xx_radio_read16(bcm, 0x0085) & ~0x0010);
+	bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008);
+	bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040);
+	bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040) | 0x0040);
+	bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0008) | 0x0008);
+	bcm43xx_phy_write(bcm, 0x0063, 0xDDC6);
+	bcm43xx_phy_write(bcm, 0x0069, 0x07BE);
+	bcm43xx_phy_write(bcm, 0x006A, 0x0000);
+
+	err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_A, 0);
+	assert(err == 0);
+	udelay(1000);
+}
+
+static inline
+u16 freq_r3A_value(u16 frequency)
+{
+	u16 value;
+
+	if (frequency < 5091)
+		value = 0x0040;
+	else if (frequency < 5321)
+		value = 0x0000;
+	else if (frequency < 5806)
+		value = 0x0080;
+	else
+		value = 0x0040;
+
+	return value;
+}
+
+void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm)
+{
+	static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
+	static const u8 data_low[5]  = { 0x00, 0x01, 0x05, 0x06, 0x0A };
+	u16 tmp = bcm43xx_radio_read16(bcm, 0x001E);
+	int i, j;
+	
+	for (i = 0; i < 5; i++) {
+		for (j = 0; j < 5; j++) {
+			if (tmp == (data_high[i] << 4 | data_low[j])) {
+				bcm43xx_phy_write(bcm, 0x0069, (i - j) << 8 | 0x00C0);
+				return;
+			}
+		}
+	}
+}
+
+int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
+				u8 channel,
+				int synthetic_pu_workaround)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 r8, tmp;
+	u16 freq;
+
+	if ((radio->manufact == 0x17F) &&
+	    (radio->version == 0x2060) &&
+	    (radio->revision == 1)) {
+		if (channel > 200)
+			return -EINVAL;
+		freq = channel2freq_a(channel);
+
+		r8 = bcm43xx_radio_read16(bcm, 0x0008);
+		bcm43xx_write16(bcm, 0x03F0, freq);
+		bcm43xx_radio_write16(bcm, 0x0008, r8);
+
+		TODO();//TODO: write max channel TX power? to Radio 0x2D
+		tmp = bcm43xx_radio_read16(bcm, 0x002E);
+		tmp &= 0x0080;
+		TODO();//TODO: OR tmp with the Power out estimation for this channel?
+		bcm43xx_radio_write16(bcm, 0x002E, tmp);
+
+		if (freq >= 4920 && freq <= 5500) {
+			/* 
+			 * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F;
+			 *    = (freq * 0.025862069
+			 */
+			r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */
+		}
+		bcm43xx_radio_write16(bcm, 0x0007, (r8 << 4) | r8);
+		bcm43xx_radio_write16(bcm, 0x0020, (r8 << 4) | r8);
+		bcm43xx_radio_write16(bcm, 0x0021, (r8 << 4) | r8);
+		bcm43xx_radio_write16(bcm, 0x0022,
+				      (bcm43xx_radio_read16(bcm, 0x0022)
+				       & 0x000F) | (r8 << 4));
+		bcm43xx_radio_write16(bcm, 0x002A, (r8 << 4));
+		bcm43xx_radio_write16(bcm, 0x002B, (r8 << 4));
+		bcm43xx_radio_write16(bcm, 0x0008,
+				      (bcm43xx_radio_read16(bcm, 0x0008)
+				       & 0x00F0) | (r8 << 4));
+		bcm43xx_radio_write16(bcm, 0x0029,
+				      (bcm43xx_radio_read16(bcm, 0x0029)
+				       & 0xFF0F) | 0x00B0);
+		bcm43xx_radio_write16(bcm, 0x0035, 0x00AA);
+		bcm43xx_radio_write16(bcm, 0x0036, 0x0085);
+		bcm43xx_radio_write16(bcm, 0x003A,
+				      (bcm43xx_radio_read16(bcm, 0x003A)
+				       & 0xFF20) | freq_r3A_value(freq));
+		bcm43xx_radio_write16(bcm, 0x003D,
+				      bcm43xx_radio_read16(bcm, 0x003D) & 0x00FF);
+		bcm43xx_radio_write16(bcm, 0x0081,
+				      (bcm43xx_radio_read16(bcm, 0x0081)
+				       & 0xFF7F) | 0x0080);
+		bcm43xx_radio_write16(bcm, 0x0035,
+				      bcm43xx_radio_read16(bcm, 0x0035) & 0xFFEF);
+		bcm43xx_radio_write16(bcm, 0x0035,
+				      (bcm43xx_radio_read16(bcm, 0x0035)
+				       & 0xFFEF) | 0x0010);
+		bcm43xx_radio_set_tx_iq(bcm);
+		TODO();	//TODO:	TSSI2dbm workaround
+		bcm43xx_phy_xmitpower(bcm);//FIXME correct?
+	} else {
+		if ((channel < 1) || (channel > 14))
+			return -EINVAL;
+
+		if (synthetic_pu_workaround)
+			bcm43xx_synth_pu_workaround(bcm, channel);
+
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
+				channel2freq_bg(channel));
+
+		if (channel == 14) {
+			if (bcm->sprom.locale == BCM43xx_LOCALE_JAPAN) {
+				bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+						    BCM43xx_UCODEFLAGS_OFFSET,
+						    bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+								       BCM43xx_UCODEFLAGS_OFFSET)
+						    & ~(1 << 7));
+			} else {
+				bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+						    BCM43xx_UCODEFLAGS_OFFSET,
+						    bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+								       BCM43xx_UCODEFLAGS_OFFSET)
+						    | (1 << 7));
+			}
+			bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
+					bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
+					| (1 << 11));
+		} else {
+			bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
+					bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
+					& 0xF7BF);
+		}
+	}
+
+	radio->channel = channel;
+	//XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
+	//     that 2000 usecs might suffice.
+	udelay(8000);
+
+	return 0;
+}
+
+void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val)
+{
+	u16 tmp;
+
+	val <<= 8;
+	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0022) & 0xFCFF;
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0022, tmp | val);
+	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x03A8) & 0xFCFF;
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x03A8, tmp | val);
+	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0054) & 0xFCFF;
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0054, tmp | val);
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
+static u16 bcm43xx_get_txgain_base_band(u16 txpower)
+{
+	u16 ret;
+
+	assert(txpower <= 63);
+
+	if (txpower >= 54)
+		ret = 2;
+	else if (txpower >= 49)
+		ret = 4;
+	else if (txpower >= 44)
+		ret = 5;
+	else
+		ret = 6;
+
+	return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
+static u16 bcm43xx_get_txgain_freq_power_amp(u16 txpower)
+{
+	u16 ret;
+
+	assert(txpower <= 63);
+
+	if (txpower >= 32)
+		ret = 0;
+	else if (txpower >= 25)
+		ret = 1;
+	else if (txpower >= 20)
+		ret = 2;
+	else if (txpower >= 12)
+		ret = 3;
+	else
+		ret = 4;
+
+	return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
+static u16 bcm43xx_get_txgain_dac(u16 txpower)
+{
+	u16 ret;
+
+	assert(txpower <= 63);
+
+	if (txpower >= 54)
+		ret = txpower - 53;
+	else if (txpower >= 49)
+		ret = txpower - 42;
+	else if (txpower >= 44)
+		ret = txpower - 37;
+	else if (txpower >= 32)
+		ret = txpower - 32;
+	else if (txpower >= 25)
+		ret = txpower - 20;
+	else if (txpower >= 20)
+		ret = txpower - 13;
+	else if (txpower >= 12)
+		ret = txpower - 8;
+	else
+		ret = txpower;
+
+	return ret;
+}
+
+void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 pamp, base, dac, ilt;
+
+	txpower = limit_value(txpower, 0, 63);
+
+	pamp = bcm43xx_get_txgain_freq_power_amp(txpower);
+	pamp <<= 5;
+	pamp &= 0x00E0;
+	bcm43xx_phy_write(bcm, 0x0019, pamp);
+
+	base = bcm43xx_get_txgain_base_band(txpower);
+	base &= 0x000F;
+	bcm43xx_phy_write(bcm, 0x0017, base | 0x0020);
+
+	ilt = bcm43xx_ilt_read(bcm, 0x3001);
+	ilt &= 0x0007;
+
+	dac = bcm43xx_get_txgain_dac(txpower);
+	dac <<= 3;
+	dac |= ilt;
+
+	bcm43xx_ilt_write(bcm, 0x3001, dac);
+
+	radio->txpwr_offset = txpower;
+
+	TODO();
+	//TODO: FuncPlaceholder (Adjust BB loft cancel)
+}
+
+void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm,
+                                 u16 baseband_attenuation, u16 radio_attenuation,
+                                 u16 txpower)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	if (baseband_attenuation == 0xFFFF)
+		baseband_attenuation = radio->baseband_atten;
+	if (radio_attenuation == 0xFFFF)
+		radio_attenuation = radio->radio_atten;
+	if (txpower == 0xFFFF)
+		txpower = radio->txctl1;
+	radio->baseband_atten = baseband_attenuation;
+	radio->radio_atten = radio_attenuation;
+	radio->txctl1 = txpower;
+
+	assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11);
+	if (radio->revision < 6)
+		assert(/*radio_attenuation >= 0 &&*/ radio_attenuation <= 9);
+	else
+		assert(/* radio_attenuation >= 0 &&*/ radio_attenuation <= 31);
+	assert(/*txpower >= 0 &&*/ txpower <= 7);
+
+	bcm43xx_phy_set_baseband_attenuation(bcm, baseband_attenuation);
+	bcm43xx_radio_write16(bcm, 0x0043, radio_attenuation);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0064, radio_attenuation);
+	if (radio->version == 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0052,
+		                      (bcm43xx_radio_read16(bcm, 0x0052) & ~0x0070)
+				       | ((txpower << 4) & 0x0070));
+	}
+	//FIXME: The spec is very weird and unclear here.
+	if (phy->type == BCM43xx_PHYTYPE_G)
+		bcm43xx_phy_lo_adjust(bcm, 0);
+}
+
+u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	if (radio->version == 0x2050 && radio->revision < 6)
+		return 0;
+	return 2;
+}
+
+u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 att = 0xFFFF;
+
+	if (phy->type == BCM43xx_PHYTYPE_A)
+		return 0x60;
+
+	switch (radio->version) {
+	case 0x2053:
+		switch (radio->revision) {
+		case 1:
+			att = 6;
+			break;
+		}
+		break;
+	case 0x2050:
+		switch (radio->revision) {
+		case 0:
+			att = 5;
+			break;
+		case 1:
+			if (phy->type == BCM43xx_PHYTYPE_G) {
+				if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+				    bcm->board_type == 0x421 &&
+				    bcm->board_revision >= 30)
+					att = 3;
+				else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+					 bcm->board_type == 0x416)
+					att = 3;
+				else
+					att = 1;
+			} else {
+				if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+				    bcm->board_type == 0x421 &&
+				    bcm->board_revision >= 30)
+					att = 7;
+				else
+					att = 6;
+			}
+			break;
+		case 2:
+			if (phy->type == BCM43xx_PHYTYPE_G) {
+				if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+				    bcm->board_type == 0x421 &&
+				    bcm->board_revision >= 30)
+					att = 3;
+				else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+					 bcm->board_type == 0x416)
+					att = 5;
+				else if (bcm->chip_id == 0x4320)
+					att = 4;
+				else
+					att = 3;
+			} else
+				att = 6;
+			break;
+		case 3:
+			att = 5;
+			break;
+		case 4:
+		case 5:
+			att = 1;
+			break;
+		case 6:
+		case 7:
+			att = 5;
+			break;
+		case 8:
+			att = 0x1A;
+			break;
+		case 9:
+		default:
+			att = 5;
+		}
+	}
+	if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+	    bcm->board_type == 0x421) {
+		if (bcm->board_revision < 0x43)
+			att = 2;
+		else if (bcm->board_revision < 0x51)
+			att = 3;
+	}
+	if (att == 0xFFFF)
+		att = 5;
+
+	return att;
+}
+
+u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	if (radio->version != 0x2050)
+		return 0;
+	if (radio->revision == 1)
+		return 3;
+	if (radio->revision < 6)
+		return 2;
+	if (radio->revision == 8)
+		return 1;
+	return 0;
+}
+
+void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	int err;
+
+	if (radio->enabled)
+		return;
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+		bcm43xx_radio_write16(bcm, 0x0004, 0x00C0);
+		bcm43xx_radio_write16(bcm, 0x0005, 0x0008);
+		bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) & 0xFFF7);
+		bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) & 0xFFF7);
+		bcm43xx_radio_init2060(bcm);	
+		break;
+	case BCM43xx_PHYTYPE_B:
+	case BCM43xx_PHYTYPE_G:
+		bcm43xx_phy_write(bcm, 0x0015, 0x8000);
+		bcm43xx_phy_write(bcm, 0x0015, 0xCC00);
+		bcm43xx_phy_write(bcm, 0x0015, (phy->connected ? 0x00C0 : 0x0000));
+		err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 1);
+		assert(err == 0);
+		break;
+	default:
+		assert(0);
+	}
+	radio->enabled = 1;
+	dprintk(KERN_INFO PFX "Radio turned on\n");
+}
+	
+void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	if (phy->type == BCM43xx_PHYTYPE_A) {
+		bcm43xx_radio_write16(bcm, 0x0004, 0x00FF);
+		bcm43xx_radio_write16(bcm, 0x0005, 0x00FB);
+		bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) | 0x0008);
+		bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) | 0x0008);
+	}
+	if (phy->type == BCM43xx_PHYTYPE_G && bcm->current_core->rev >= 5) {
+		bcm43xx_phy_write(bcm, 0x0811, bcm43xx_phy_read(bcm, 0x0811) | 0x008C);
+		bcm43xx_phy_write(bcm, 0x0812, bcm43xx_phy_read(bcm, 0x0812) & 0xFF73);
+	} else
+		bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
+	radio->enabled = 0;
+	dprintk(KERN_INFO PFX "Radio turned off\n");
+}
+
+void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0068, 0x7F7F);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x006a, 0x7F7F);
+		break;
+	case BCM43xx_PHYTYPE_B:
+	case BCM43xx_PHYTYPE_G:
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0058, 0x7F7F);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x005a, 0x7F7F);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0070, 0x7F7F);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0072, 0x7F7F);
+		break;
+	}
+}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
new file mode 100644
index 0000000..9ed1803
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
@@ -0,0 +1,99 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef BCM43xx_RADIO_H_
+#define BCM43xx_RADIO_H_
+
+#include "bcm43xx.h"
+
+
+#define BCM43xx_RADIO_DEFAULT_CHANNEL_A		36
+#define BCM43xx_RADIO_DEFAULT_CHANNEL_BG	6
+
+/* Force antenna 0. */
+#define BCM43xx_RADIO_TXANTENNA_0		0
+/* Force antenna 1. */
+#define BCM43xx_RADIO_TXANTENNA_1		1
+/* Use the RX antenna, that was selected for the most recently
+ * received good PLCP header.
+ */
+#define BCM43xx_RADIO_TXANTENNA_LASTPLCP	3
+#define BCM43xx_RADIO_TXANTENNA_DEFAULT		BCM43xx_RADIO_TXANTENNA_LASTPLCP
+
+#define BCM43xx_RADIO_INTERFMODE_NONE		0
+#define BCM43xx_RADIO_INTERFMODE_NONWLAN	1
+#define BCM43xx_RADIO_INTERFMODE_MANUALWLAN	2
+#define BCM43xx_RADIO_INTERFMODE_AUTOWLAN	3
+
+
+void bcm43xx_radio_lock(struct bcm43xx_private *bcm);
+void bcm43xx_radio_unlock(struct bcm43xx_private *bcm);
+
+u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset);
+void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val);
+
+u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm);
+void bcm43xx_radio_init2060(struct bcm43xx_private *bcm);
+
+void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm);
+void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm);
+
+int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel,
+				int synthetic_pu_workaround);
+
+void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower);
+void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm,
+                               u16 baseband_attenuation, u16 attenuation,
+			       u16 txpower);
+
+u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm);
+u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm);
+u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm);
+
+void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val);
+
+void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm);
+
+u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel);
+u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm);
+
+int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, int mode);
+
+void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm);
+void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm);
+s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset);
+void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val);
+void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val);
+void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm);
+
+void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm);
+u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm);
+
+#endif /* BCM43xx_RADIO_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
new file mode 100644
index 0000000..c44d890
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -0,0 +1,322 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  SYSFS support routines
+
+  Copyright (c) 2006 Michael Buesch <mbuesch@freenet.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx_sysfs.h"
+#include "bcm43xx.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_radio.h"
+
+#include <linux/capability.h>
+
+
+#define GENERIC_FILESIZE	64
+
+
+static int get_integer(const char *buf, size_t count)
+{
+	char tmp[10 + 1] = { 0 };
+	int ret = -EINVAL;
+
+	if (count == 0)
+		goto out;
+	count = min(count, (size_t)10);
+	memcpy(tmp, buf, count);
+	ret = simple_strtol(tmp, NULL, 10);
+out:
+	return ret;
+}
+
+static int get_boolean(const char *buf, size_t count)
+{
+	if (count != 0) {
+		if (buf[0] == '1')
+			return 1;
+		if (buf[0] == '0')
+			return 0;
+		if (count >= 4 && memcmp(buf, "true", 4) == 0)
+			return 1;
+		if (count >= 5 && memcmp(buf, "false", 5) == 0)
+			return 0;
+		if (count >= 3 && memcmp(buf, "yes", 3) == 0)
+			return 1;
+		if (count >= 2 && memcmp(buf, "no", 2) == 0)
+			return 0;
+		if (count >= 2 && memcmp(buf, "on", 2) == 0)
+			return 1;
+		if (count >= 3 && memcmp(buf, "off", 3) == 0)
+			return 0;
+	}
+	return -EINVAL;
+}
+
+static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom);
+	u16 *sprom;
+	unsigned long flags;
+	int i, err;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	assert(BCM43xx_SPROM_SIZE * sizeof(u16) <= PAGE_SIZE);
+	sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
+			GFP_KERNEL);
+	if (!sprom)
+		return -ENOMEM;
+	bcm43xx_lock_mmio(bcm, flags);
+	assert(bcm->initialized);
+	err = bcm43xx_sprom_read(bcm, sprom);
+	if (!err) {
+		for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
+			buf[i * 2] = sprom[i] & 0x00FF;
+			buf[i * 2 + 1] = (sprom[i] & 0xFF00) >> 8;
+		}
+	}
+	bcm43xx_unlock_mmio(bcm, flags);
+	kfree(sprom);
+
+	return err ? err : BCM43xx_SPROM_SIZE * sizeof(u16);
+}
+
+static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom);
+	u16 *sprom;
+	unsigned long flags;
+	int i, err;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (count != BCM43xx_SPROM_SIZE * sizeof(u16))
+		return -EINVAL;
+	sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
+			GFP_KERNEL);
+	if (!sprom)
+		return -ENOMEM;
+	for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
+		sprom[i] = buf[i * 2] & 0xFF;
+		sprom[i] |= ((u16)(buf[i * 2 + 1] & 0xFF)) << 8;
+	}
+	bcm43xx_lock_mmio(bcm, flags);
+	assert(bcm->initialized);
+	err = bcm43xx_sprom_write(bcm, sprom);
+	bcm43xx_unlock_mmio(bcm, flags);
+	kfree(sprom);
+
+	return err ? err : count;
+
+}
+
+static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode);
+	unsigned long flags;
+	int err;
+	ssize_t count = 0;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	bcm43xx_lock(bcm, flags);
+	assert(bcm->initialized);
+
+	switch (bcm43xx_current_radio(bcm)->interfmode) {
+	case BCM43xx_RADIO_INTERFMODE_NONE:
+		count = snprintf(buf, PAGE_SIZE, "0 (No Interference Mitigation)\n");
+		break;
+	case BCM43xx_RADIO_INTERFMODE_NONWLAN:
+		count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference Mitigation)\n");
+		break;
+	case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
+		count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference Mitigation)\n");
+		break;
+	default:
+		assert(0);
+	}
+	err = 0;
+
+	bcm43xx_unlock(bcm, flags);
+
+	return err ? err : count;
+
+}
+
+static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
+					     struct device_attribute *attr,
+					     const char *buf, size_t count)
+{
+	struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode);
+	unsigned long flags;
+	int err;
+	int mode;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	mode = get_integer(buf, count);
+	switch (mode) {
+	case 0:
+		mode = BCM43xx_RADIO_INTERFMODE_NONE;
+		break;
+	case 1:
+		mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
+		break;
+	case 2:
+		mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
+		break;
+	case 3:
+		mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	bcm43xx_lock_mmio(bcm, flags);
+	assert(bcm->initialized);
+
+	err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
+	if (err) {
+		printk(KERN_ERR PFX "Interference Mitigation not "
+				    "supported by device\n");
+	}
+
+	bcm43xx_unlock_mmio(bcm, flags);
+
+	return err ? err : count;
+}
+
+static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble);
+	unsigned long flags;
+	int err;
+	ssize_t count;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	bcm43xx_lock(bcm, flags);
+	assert(bcm->initialized);
+
+	if (bcm->short_preamble)
+		count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
+	else
+		count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
+
+	err = 0;
+	bcm43xx_unlock(bcm, flags);
+
+	return err ? err : count;
+}
+
+static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
+					   struct device_attribute *attr,
+					   const char *buf, size_t count)
+{
+	struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble);
+	unsigned long flags;
+	int err;
+	int value;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	value = get_boolean(buf, count);
+	if (value < 0)
+		return value;
+	bcm43xx_lock(bcm, flags);
+	assert(bcm->initialized);
+
+	bcm->short_preamble = !!value;
+
+	err = 0;
+	bcm43xx_unlock(bcm, flags);
+
+	return err ? err : count;
+}
+
+int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
+{
+	struct device *dev = &bcm->pci_dev->dev;
+	struct bcm43xx_sysfs *sysfs = &bcm->sysfs;
+	int err;
+
+	assert(bcm->initialized);
+
+	sysfs->attr_sprom.attr.name = "sprom";
+	sysfs->attr_sprom.attr.owner = THIS_MODULE;
+	sysfs->attr_sprom.attr.mode = 0600;
+	sysfs->attr_sprom.show = bcm43xx_attr_sprom_show;
+	sysfs->attr_sprom.store = bcm43xx_attr_sprom_store;
+	err = device_create_file(dev, &sysfs->attr_sprom);
+	if (err)
+		goto out;
+
+	sysfs->attr_interfmode.attr.name = "interference";
+	sysfs->attr_interfmode.attr.owner = THIS_MODULE;
+	sysfs->attr_interfmode.attr.mode = 0600;
+	sysfs->attr_interfmode.show = bcm43xx_attr_interfmode_show;
+	sysfs->attr_interfmode.store = bcm43xx_attr_interfmode_store;
+	err = device_create_file(dev, &sysfs->attr_interfmode);
+	if (err)
+		goto err_remove_sprom;
+
+	sysfs->attr_preamble.attr.name = "shortpreamble";
+	sysfs->attr_preamble.attr.owner = THIS_MODULE;
+	sysfs->attr_preamble.attr.mode = 0600;
+	sysfs->attr_preamble.show = bcm43xx_attr_preamble_show;
+	sysfs->attr_preamble.store = bcm43xx_attr_preamble_store;
+	err = device_create_file(dev, &sysfs->attr_preamble);
+	if (err)
+		goto err_remove_interfmode;
+
+out:
+	return err;
+err_remove_interfmode:
+	device_remove_file(dev, &sysfs->attr_interfmode);
+err_remove_sprom:
+	device_remove_file(dev, &sysfs->attr_sprom);
+	goto out;
+}
+
+void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
+{
+	struct device *dev = &bcm->pci_dev->dev;
+	struct bcm43xx_sysfs *sysfs = &bcm->sysfs;
+
+	device_remove_file(dev, &sysfs->attr_preamble);
+	device_remove_file(dev, &sysfs->attr_interfmode);
+	device_remove_file(dev, &sysfs->attr_sprom);
+}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h
new file mode 100644
index 0000000..57f1451
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h
@@ -0,0 +1,25 @@
+#ifndef BCM43xx_SYSFS_H_
+#define BCM43xx_SYSFS_H_
+
+#include <linux/device.h>
+
+
+struct bcm43xx_sysfs {
+	struct device_attribute attr_sprom;
+	struct device_attribute attr_interfmode;
+	struct device_attribute attr_preamble;
+};
+
+#define devattr_to_bcm(attr, attr_name)	({				\
+	struct bcm43xx_sysfs *__s; struct bcm43xx_private *__p;		\
+	__s = container_of((attr), struct bcm43xx_sysfs, attr_name);	\
+	__p = container_of(__s, struct bcm43xx_private, sysfs);		\
+	__p;								\
+					})
+
+struct bcm43xx_private;
+
+int bcm43xx_sysfs_register(struct bcm43xx_private *bcm);
+void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm);
+
+#endif /* BCM43xx_SYSFS_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
new file mode 100644
index 0000000..3daee82
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -0,0 +1,1002 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <net/ieee80211softmac.h>
+#include <net/ieee80211softmac_wx.h>
+#include <linux/capability.h>
+#include <linux/sched.h> /* for capable() */
+#include <linux/delay.h>
+
+#include "bcm43xx.h"
+#include "bcm43xx_wx.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_radio.h"
+#include "bcm43xx_phy.h"
+
+
+/* The WIRELESS_EXT version, which is implemented by this driver. */
+#define BCM43xx_WX_VERSION	18
+
+#define MAX_WX_STRING		80
+
+
+static int bcm43xx_wx_get_name(struct net_device *net_dev,
+                               struct iw_request_info *info,
+			       union iwreq_data *data,
+			       char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	int i;
+	struct bcm43xx_phyinfo *phy;
+	char suffix[7] = { 0 };
+	int have_a = 0, have_b = 0, have_g = 0;
+
+	bcm43xx_lock(bcm, flags);
+	for (i = 0; i < bcm->nr_80211_available; i++) {
+		phy = &(bcm->core_80211_ext[i].phy);
+		switch (phy->type) {
+		case BCM43xx_PHYTYPE_A:
+			have_a = 1;
+			break;
+		case BCM43xx_PHYTYPE_G:
+			have_g = 1;
+		case BCM43xx_PHYTYPE_B:
+			have_b = 1;
+			break;
+		default:
+			assert(0);
+		}
+	}
+	bcm43xx_unlock(bcm, flags);
+
+	i = 0;
+	if (have_a) {
+		suffix[i++] = 'a';
+		suffix[i++] = '/';
+	}
+	if (have_b) {
+		suffix[i++] = 'b';
+		suffix[i++] = '/';
+	}
+	if (have_g) {
+		suffix[i++] = 'g';
+		suffix[i++] = '/';
+	}
+	if (i != 0) 
+		suffix[i - 1] = '\0';
+
+	snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix);
+
+	return 0;
+}
+
+static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
+				      struct iw_request_info *info,
+				      union iwreq_data *data,
+				      char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	u8 channel;
+	int freq;
+	int err = -EINVAL;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
+		channel = data->freq.m;
+		freq = bcm43xx_channel_to_freq(bcm, channel);
+	} else {
+		channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
+		freq = data->freq.m;
+	}
+	if (!bcm43xx_is_valid_channel(bcm, channel))
+		goto out_unlock;
+	if (bcm->initialized) {
+		//ieee80211softmac_disassoc(softmac, $REASON);
+		bcm43xx_mac_suspend(bcm);
+		err = bcm43xx_radio_selectchannel(bcm, channel, 0);
+		bcm43xx_mac_enable(bcm);
+	} else {
+		bcm43xx_current_radio(bcm)->initial_channel = channel;
+		err = 0;
+	}
+out_unlock:
+	bcm43xx_unlock_mmio(bcm, flags);
+
+	return err;
+}
+
+static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
+				      struct iw_request_info *info,
+				      union iwreq_data *data,
+				      char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	struct bcm43xx_radioinfo *radio;
+	unsigned long flags;
+	int err = -ENODEV;
+	u16 channel;
+
+	bcm43xx_lock(bcm, flags);
+	radio = bcm43xx_current_radio(bcm);
+	channel = radio->channel;
+	if (channel == 0xFF) {
+		assert(!bcm->initialized);
+		channel = radio->initial_channel;
+		if (channel == 0xFF)
+			goto out_unlock;
+	}
+	assert(channel > 0 && channel <= 1000);
+	data->freq.e = 1;
+	data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000;
+	data->freq.flags = 1;
+
+	err = 0;
+out_unlock:
+	bcm43xx_unlock(bcm, flags);
+
+	return err;
+}
+
+static int bcm43xx_wx_set_mode(struct net_device *net_dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *data,
+			       char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	int mode;
+
+	mode = data->mode;
+	if (mode == IW_MODE_AUTO)
+		mode = BCM43xx_INITIAL_IWMODE;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if (bcm->ieee->iw_mode != mode)
+		bcm43xx_set_iwmode(bcm, mode);
+	bcm43xx_unlock_mmio(bcm, flags);
+
+	return 0;
+}
+
+static int bcm43xx_wx_get_mode(struct net_device *net_dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *data,
+			       char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+
+	bcm43xx_lock(bcm, flags);
+	data->mode = bcm->ieee->iw_mode;
+	bcm43xx_unlock(bcm, flags);
+
+	return 0;
+}
+
+static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
+				      struct iw_request_info *info,
+				      union iwreq_data *data,
+				      char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	struct iw_range *range = (struct iw_range *)extra;
+	const struct ieee80211_geo *geo;
+	unsigned long flags;
+	int i, j;
+	struct bcm43xx_phyinfo *phy;
+
+	data->data.length = sizeof(*range);
+	memset(range, 0, sizeof(*range));
+
+	//TODO: What about 802.11b?
+	/* 54Mb/s == ~27Mb/s payload throughput (802.11g) */
+	range->throughput = 27 * 1000 * 1000;
+
+	range->max_qual.qual = 100;
+	/* TODO: Real max RSSI */
+	range->max_qual.level = 3;
+	range->max_qual.noise = 100;
+	range->max_qual.updated = 7;
+
+	range->avg_qual.qual = 70;
+	range->avg_qual.level = 2;
+	range->avg_qual.noise = 40;
+	range->avg_qual.updated = 7;
+
+	range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
+	range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
+	range->min_frag = MIN_FRAG_THRESHOLD;
+	range->max_frag = MAX_FRAG_THRESHOLD;
+
+	range->encoding_size[0] = 5;
+	range->encoding_size[1] = 13;
+	range->num_encoding_sizes = 2;
+	range->max_encoding_tokens = WEP_KEYS;
+
+	range->we_version_compiled = WIRELESS_EXT;
+	range->we_version_source = BCM43xx_WX_VERSION;
+
+	range->enc_capa = IW_ENC_CAPA_WPA |
+			  IW_ENC_CAPA_WPA2 |
+			  IW_ENC_CAPA_CIPHER_TKIP |
+			  IW_ENC_CAPA_CIPHER_CCMP;
+
+	bcm43xx_lock(bcm, flags);
+	phy = bcm43xx_current_phy(bcm);
+
+	range->num_bitrates = 0;
+	i = 0;
+	if (phy->type == BCM43xx_PHYTYPE_A ||
+	    phy->type == BCM43xx_PHYTYPE_G) {
+		range->num_bitrates = 8;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
+	}
+	if (phy->type == BCM43xx_PHYTYPE_B ||
+	    phy->type == BCM43xx_PHYTYPE_G) {
+		range->num_bitrates += 4;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
+	}
+
+	geo = ieee80211_get_geo(bcm->ieee);
+	range->num_channels = geo->a_channels + geo->bg_channels;
+	j = 0;
+	for (i = 0; i < geo->a_channels; i++) {
+		if (j == IW_MAX_FREQUENCIES)
+			break;
+		range->freq[j].i = j + 1;
+		range->freq[j].m = geo->a[i].freq;//FIXME?
+		range->freq[j].e = 1;
+		j++;
+	}
+	for (i = 0; i < geo->bg_channels; i++) {
+		if (j == IW_MAX_FREQUENCIES)
+			break;
+		range->freq[j].i = j + 1;
+		range->freq[j].m = geo->bg[i].freq;//FIXME?
+		range->freq[j].e = 1;
+		j++;
+	}
+	range->num_frequency = j;
+
+	bcm43xx_unlock(bcm, flags);
+
+	return 0;
+}
+
+static int bcm43xx_wx_set_nick(struct net_device *net_dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *data,
+			       char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	size_t len;
+
+	bcm43xx_lock(bcm, flags);
+	len =  min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
+	memcpy(bcm->nick, extra, len);
+	bcm->nick[len] = '\0';
+	bcm43xx_unlock(bcm, flags);
+
+	return 0;
+}
+
+static int bcm43xx_wx_get_nick(struct net_device *net_dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *data,
+			       char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	size_t len;
+
+	bcm43xx_lock(bcm, flags);
+	len = strlen(bcm->nick) + 1;
+	memcpy(extra, bcm->nick, len);
+	data->data.length = (__u16)len;
+	data->data.flags = 1;
+	bcm43xx_unlock(bcm, flags);
+
+	return 0;
+}
+
+static int bcm43xx_wx_set_rts(struct net_device *net_dev,
+			      struct iw_request_info *info,
+			      union iwreq_data *data,
+			      char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	int err = -EINVAL;
+
+	bcm43xx_lock(bcm, flags);
+	if (data->rts.disabled) {
+		bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
+		err = 0;
+	} else {
+		if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD &&
+		    data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) {
+			bcm->rts_threshold = data->rts.value;
+			err = 0;
+		}
+	}
+	bcm43xx_unlock(bcm, flags);
+
+	return err;
+}
+
+static int bcm43xx_wx_get_rts(struct net_device *net_dev,
+			      struct iw_request_info *info,
+			      union iwreq_data *data,
+			      char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+
+	bcm43xx_lock(bcm, flags);
+	data->rts.value = bcm->rts_threshold;
+	data->rts.fixed = 0;
+	data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
+	bcm43xx_unlock(bcm, flags);
+
+	return 0;
+}
+
+static int bcm43xx_wx_set_frag(struct net_device *net_dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *data,
+			       char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	int err = -EINVAL;
+
+	bcm43xx_lock(bcm, flags);
+	if (data->frag.disabled) {
+		bcm->ieee->fts = MAX_FRAG_THRESHOLD;
+		err = 0;
+	} else {
+		if (data->frag.value >= MIN_FRAG_THRESHOLD &&
+		    data->frag.value <= MAX_FRAG_THRESHOLD) {
+			bcm->ieee->fts = data->frag.value & ~0x1;
+			err = 0;
+		}
+	}
+	bcm43xx_unlock(bcm, flags);
+
+	return err;
+}
+
+static int bcm43xx_wx_get_frag(struct net_device *net_dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *data,
+			       char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+
+	bcm43xx_lock(bcm, flags);
+	data->frag.value = bcm->ieee->fts;
+	data->frag.fixed = 0;
+	data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
+	bcm43xx_unlock(bcm, flags);
+
+	return 0;
+}
+
+static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
+				    struct iw_request_info *info,
+				    union iwreq_data *data,
+				    char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	struct bcm43xx_radioinfo *radio;
+	struct bcm43xx_phyinfo *phy;
+	unsigned long flags;
+	int err = -ENODEV;
+	u16 maxpower;
+
+	if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
+		printk(PFX KERN_ERR "TX power not in dBm.\n");
+		return -EOPNOTSUPP;
+	}
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if (!bcm->initialized)
+		goto out_unlock;
+	radio = bcm43xx_current_radio(bcm);
+	phy = bcm43xx_current_phy(bcm);
+	if (data->txpower.disabled != (!(radio->enabled))) {
+		if (data->txpower.disabled)
+			bcm43xx_radio_turn_off(bcm);
+		else
+			bcm43xx_radio_turn_on(bcm);
+	}
+	if (data->txpower.value > 0) {
+		/* desired and maxpower dBm values are in Q5.2 */
+		if (phy->type == BCM43xx_PHYTYPE_A)
+			maxpower = bcm->sprom.maxpower_aphy;
+		else
+			maxpower = bcm->sprom.maxpower_bgphy;
+		radio->txpower_desired = limit_value(data->txpower.value << 2,
+						     0, maxpower);
+		bcm43xx_phy_xmitpower(bcm);
+	}
+	err = 0;
+
+out_unlock:
+	bcm43xx_unlock_mmio(bcm, flags);
+
+	return err;
+}
+
+static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
+				    struct iw_request_info *info,
+				    union iwreq_data *data,
+				    char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	struct bcm43xx_radioinfo *radio;
+	unsigned long flags;
+	int err = -ENODEV;
+
+	bcm43xx_lock(bcm, flags);
+	if (!bcm->initialized)
+		goto out_unlock;
+	radio = bcm43xx_current_radio(bcm);
+	/* desired dBm value is in Q5.2 */
+	data->txpower.value = radio->txpower_desired >> 2;
+	data->txpower.fixed = 1;
+	data->txpower.flags = IW_TXPOW_DBM;
+	data->txpower.disabled = !(radio->enabled);
+
+	err = 0;
+out_unlock:
+	bcm43xx_unlock(bcm, flags);
+
+	return err;
+}
+
+static int bcm43xx_wx_set_encoding(struct net_device *net_dev,
+				   struct iw_request_info *info,
+				   union iwreq_data *data,
+				   char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	int err;
+
+	err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra);
+
+	return err;
+}
+
+static int bcm43xx_wx_set_encodingext(struct net_device *net_dev,
+                                   struct iw_request_info *info,
+                                   union iwreq_data *data,
+                                   char *extra)
+{
+        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+        int err;
+
+        err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra);
+
+        return err;
+}
+
+static int bcm43xx_wx_get_encoding(struct net_device *net_dev,
+				   struct iw_request_info *info,
+				   union iwreq_data *data,
+				   char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	int err;
+
+	err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra);
+
+	return err;
+}
+
+static int bcm43xx_wx_get_encodingext(struct net_device *net_dev,
+                                   struct iw_request_info *info,
+                                   union iwreq_data *data,
+                                   char *extra)
+{
+        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+        int err;
+
+        err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra);
+
+        return err;
+}
+
+static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
+				     struct iw_request_info *info,
+				     union iwreq_data *data,
+				     char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	int mode, err = 0;
+
+	mode = *((int *)extra);
+	switch (mode) {
+	case 0:
+		mode = BCM43xx_RADIO_INTERFMODE_NONE;
+		break;
+	case 1:
+		mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
+		break;
+	case 2:
+		mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
+		break;
+	case 3:
+		mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
+		break;
+	default:
+		printk(KERN_ERR PFX "set_interfmode allowed parameters are: "
+				    "0 => None,  1 => Non-WLAN,  2 => WLAN,  "
+				    "3 => Auto-WLAN\n");
+		return -EINVAL;
+	}
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if (bcm->initialized) {
+		err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
+		if (err) {
+			printk(KERN_ERR PFX "Interference Mitigation not "
+					    "supported by device\n");
+		}
+	} else {
+		if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) {
+			printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN "
+					    "not supported while the interface is down.\n");
+			err = -ENODEV;
+		} else
+			bcm43xx_current_radio(bcm)->interfmode = mode;
+	}
+	bcm43xx_unlock_mmio(bcm, flags);
+
+	return err;
+}
+
+static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
+				     struct iw_request_info *info,
+				     union iwreq_data *data,
+				     char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	int mode;
+
+	bcm43xx_lock(bcm, flags);
+	mode = bcm43xx_current_radio(bcm)->interfmode;
+	bcm43xx_unlock(bcm, flags);
+
+	switch (mode) {
+	case BCM43xx_RADIO_INTERFMODE_NONE:
+		strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING);
+		break;
+	case BCM43xx_RADIO_INTERFMODE_NONWLAN:
+		strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING);
+		break;
+	case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
+		strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING);
+		break;
+	default:
+		assert(0);
+	}
+	data->data.length = strlen(extra) + 1;
+
+	return 0;
+}
+
+static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
+					struct iw_request_info *info,
+					union iwreq_data *data,
+					char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	int on;
+
+	on = *((int *)extra);
+	bcm43xx_lock(bcm, flags);
+	bcm->short_preamble = !!on;
+	bcm43xx_unlock(bcm, flags);
+
+	return 0;
+}
+
+static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
+					struct iw_request_info *info,
+					union iwreq_data *data,
+					char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	int on;
+
+	bcm43xx_lock(bcm, flags);
+	on = bcm->short_preamble;
+	bcm43xx_unlock(bcm, flags);
+
+	if (on)
+		strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
+	else
+		strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING);
+	data->data.length = strlen(extra) + 1;
+
+	return 0;
+}
+
+static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
+				       struct iw_request_info *info,
+				       union iwreq_data *data,
+				       char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	int on;
+	
+	on = *((int *)extra);
+
+	bcm43xx_lock(bcm, flags);
+	bcm->ieee->host_encrypt = !!on;
+	bcm->ieee->host_decrypt = !!on;
+	bcm->ieee->host_build_iv = !on;
+	bcm43xx_unlock(bcm, flags);
+
+	return 0;
+}
+
+static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
+				       struct iw_request_info *info,
+				       union iwreq_data *data,
+				       char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	int on;
+
+	bcm43xx_lock(bcm, flags);
+	on = bcm->ieee->host_encrypt;
+	bcm43xx_unlock(bcm, flags);
+
+	if (on)
+		strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
+	else
+		strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING);
+	data->data.length = strlen(extra + 1);
+
+	return 0;
+}
+
+/* Enough buffer to hold a hexdump of the sprom data. */
+#define SPROM_BUFFERSIZE	512
+
+static int sprom2hex(const u16 *sprom, char *dump)
+{
+	int i, pos = 0;
+
+	for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
+		pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1,
+				"%04X", swab16(sprom[i]) & 0xFFFF);
+	}
+
+	return pos + 1;
+}
+
+static int hex2sprom(u16 *sprom, const char *dump, unsigned int len)
+{
+	char tmp[5] = { 0 };
+	int cnt = 0;
+	unsigned long parsed;
+
+	if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
+		return -EINVAL;
+	while (cnt < BCM43xx_SPROM_SIZE) {
+		memcpy(tmp, dump, 4);
+		dump += 4;
+		parsed = simple_strtoul(tmp, NULL, 16);
+		sprom[cnt++] = swab16((u16)parsed);
+	}
+
+	return 0;
+}
+
+static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *data,
+				 char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	int err = -EPERM;
+	u16 *sprom;
+	unsigned long flags;
+
+	if (!capable(CAP_SYS_RAWIO))
+		goto out;
+
+	err = -ENOMEM;
+	sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
+			GFP_KERNEL);
+	if (!sprom)
+		goto out;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	err = -ENODEV;
+	if (bcm->initialized)
+		err = bcm43xx_sprom_read(bcm, sprom);
+	bcm43xx_unlock_mmio(bcm, flags);
+	if (!err)
+		data->data.length = sprom2hex(sprom, extra);
+	kfree(sprom);
+out:
+	return err;
+}
+
+static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *data,
+				  char *extra)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	int err = -EPERM;
+	u16 *sprom;
+	unsigned long flags;
+	char *input;
+	unsigned int len;
+
+	if (!capable(CAP_SYS_RAWIO))
+		goto out;
+
+	err = -ENOMEM;
+	sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
+			GFP_KERNEL);
+	if (!sprom)
+		goto out;
+
+	len = data->data.length;
+	extra[len - 1] = '\0';
+	input = strchr(extra, ':');
+	if (input) {
+		input++;
+		len -= input - extra;
+	} else
+		input = extra;
+	err = hex2sprom(sprom, input, len);
+	if (err)
+		goto out_kfree;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	err = -ENODEV;
+	if (bcm->initialized)
+		err = bcm43xx_sprom_write(bcm, sprom);
+	bcm43xx_unlock_mmio(bcm, flags);
+out_kfree:
+	kfree(sprom);
+out:
+	return err;
+}
+
+/* Get wireless statistics.  Called by /proc/net/wireless and by SIOCGIWSTATS */
+
+static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
+	struct iw_statistics *wstats;
+
+	wstats = &bcm->stats.wstats;
+	if (!mac->associated) {
+		wstats->miss.beacon = 0;
+//		bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
+		wstats->discard.retries = 0;
+//		bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question
+		wstats->discard.nwid = 0;
+//		bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto
+		wstats->discard.code = 0;
+//		bcm->ieee->ieee_stats.rx_fragments = 0;  // FIXME: same here
+		wstats->discard.fragment = 0;
+		wstats->discard.misc = 0;
+		wstats->qual.qual = 0;
+		wstats->qual.level = 0;
+		wstats->qual.noise = 0;
+		wstats->qual.updated = 7;
+		wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
+			IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+		return wstats;
+	}
+	/* fill in the real statistics when iface associated */
+	wstats->qual.qual = 100;     // TODO: get the real signal quality
+	wstats->qual.level = 3 - bcm->stats.link_quality;
+	wstats->qual.noise = bcm->stats.noise;
+	wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
+			IW_QUAL_NOISE_UPDATED;
+	wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
+	wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
+	wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
+	wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments;
+	wstats->discard.misc = 0;	// FIXME
+	wstats->miss.beacon = 0;	// FIXME
+	return wstats;
+}
+
+
+#ifdef WX
+# undef WX
+#endif
+#define WX(ioctl)  [(ioctl) - SIOCSIWCOMMIT]
+static const iw_handler bcm43xx_wx_handlers[] = {
+	/* Wireless Identification */
+	WX(SIOCGIWNAME)		= bcm43xx_wx_get_name,
+	/* Basic operations */
+	WX(SIOCSIWFREQ)		= bcm43xx_wx_set_channelfreq,
+	WX(SIOCGIWFREQ)		= bcm43xx_wx_get_channelfreq,
+	WX(SIOCSIWMODE)		= bcm43xx_wx_set_mode,
+	WX(SIOCGIWMODE)		= bcm43xx_wx_get_mode,
+	/* Informative stuff */
+	WX(SIOCGIWRANGE)	= bcm43xx_wx_get_rangeparams,
+	/* Access Point manipulation */
+	WX(SIOCSIWAP)           = ieee80211softmac_wx_set_wap,
+	WX(SIOCGIWAP)           = ieee80211softmac_wx_get_wap,
+	WX(SIOCSIWSCAN)		= ieee80211softmac_wx_trigger_scan,
+	WX(SIOCGIWSCAN)		= ieee80211softmac_wx_get_scan_results,
+	/* 802.11 specific support */
+	WX(SIOCSIWESSID)	= ieee80211softmac_wx_set_essid,
+	WX(SIOCGIWESSID)	= ieee80211softmac_wx_get_essid,
+	WX(SIOCSIWNICKN)	= bcm43xx_wx_set_nick,
+	WX(SIOCGIWNICKN)	= bcm43xx_wx_get_nick,
+	/* Other parameters */
+	WX(SIOCSIWRATE)		= ieee80211softmac_wx_set_rate,
+	WX(SIOCGIWRATE)		= ieee80211softmac_wx_get_rate,
+	WX(SIOCSIWRTS)		= bcm43xx_wx_set_rts,
+	WX(SIOCGIWRTS)		= bcm43xx_wx_get_rts,
+	WX(SIOCSIWFRAG)		= bcm43xx_wx_set_frag,
+	WX(SIOCGIWFRAG)		= bcm43xx_wx_get_frag,
+	WX(SIOCSIWTXPOW)	= bcm43xx_wx_set_xmitpower,
+	WX(SIOCGIWTXPOW)	= bcm43xx_wx_get_xmitpower,
+//TODO	WX(SIOCSIWRETRY)	= bcm43xx_wx_set_retry,
+//TODO	WX(SIOCGIWRETRY)	= bcm43xx_wx_get_retry,
+	/* Encoding */
+	WX(SIOCSIWENCODE)	= bcm43xx_wx_set_encoding,
+	WX(SIOCGIWENCODE)	= bcm43xx_wx_get_encoding,
+	WX(SIOCSIWENCODEEXT)	= bcm43xx_wx_set_encodingext,
+	WX(SIOCGIWENCODEEXT)	= bcm43xx_wx_get_encodingext,
+	/* Power saving */
+//TODO	WX(SIOCSIWPOWER)	= bcm43xx_wx_set_power,
+//TODO	WX(SIOCGIWPOWER)	= bcm43xx_wx_get_power,
+	WX(SIOCSIWGENIE)	= ieee80211softmac_wx_set_genie,
+	WX(SIOCGIWGENIE)	= ieee80211softmac_wx_get_genie,
+	WX(SIOCSIWAUTH)		= ieee80211_wx_set_auth,
+	WX(SIOCGIWAUTH)		= ieee80211_wx_get_auth,
+};
+#undef WX
+
+static const iw_handler bcm43xx_priv_wx_handlers[] = {
+	/* Set Interference Mitigation Mode. */
+	bcm43xx_wx_set_interfmode,
+	/* Get Interference Mitigation Mode. */
+	bcm43xx_wx_get_interfmode,
+	/* Enable/Disable Short Preamble mode. */
+	bcm43xx_wx_set_shortpreamble,
+	/* Get Short Preamble mode. */
+	bcm43xx_wx_get_shortpreamble,
+	/* Enable/Disable Software Encryption mode */
+	bcm43xx_wx_set_swencryption,
+	/* Get Software Encryption mode */
+	bcm43xx_wx_get_swencryption,
+	/* Write SRPROM data. */
+	bcm43xx_wx_sprom_write,
+	/* Read SPROM data. */
+	bcm43xx_wx_sprom_read,
+};
+
+#define PRIV_WX_SET_INTERFMODE		(SIOCIWFIRSTPRIV + 0)
+#define PRIV_WX_GET_INTERFMODE		(SIOCIWFIRSTPRIV + 1)
+#define PRIV_WX_SET_SHORTPREAMBLE	(SIOCIWFIRSTPRIV + 2)
+#define PRIV_WX_GET_SHORTPREAMBLE	(SIOCIWFIRSTPRIV + 3)
+#define PRIV_WX_SET_SWENCRYPTION	(SIOCIWFIRSTPRIV + 4)
+#define PRIV_WX_GET_SWENCRYPTION	(SIOCIWFIRSTPRIV + 5)
+#define PRIV_WX_SPROM_WRITE		(SIOCIWFIRSTPRIV + 6)
+#define PRIV_WX_SPROM_READ		(SIOCIWFIRSTPRIV + 7)
+
+#define PRIV_WX_DUMMY(ioctl)	\
+	{					\
+		.cmd		= (ioctl),	\
+		.name		= "__unused"	\
+	}
+
+static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
+	{
+		.cmd		= PRIV_WX_SET_INTERFMODE,
+		.set_args	= IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+		.name		= "set_interfmode",
+	},
+	{
+		.cmd		= PRIV_WX_GET_INTERFMODE,
+		.get_args	= IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
+		.name		= "get_interfmode",
+	},
+	{
+		.cmd		= PRIV_WX_SET_SHORTPREAMBLE,
+		.set_args	= IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+		.name		= "set_shortpreambl",
+	},
+	{
+		.cmd		= PRIV_WX_GET_SHORTPREAMBLE,
+		.get_args	= IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
+		.name		= "get_shortpreambl",
+	},
+	{
+		.cmd		= PRIV_WX_SET_SWENCRYPTION,
+		.set_args	= IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+		.name		= "set_swencryption",
+	},
+	{
+		.cmd		= PRIV_WX_GET_SWENCRYPTION,
+		.get_args	= IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
+		.name		= "get_swencryption",
+	},
+	{
+		.cmd		= PRIV_WX_SPROM_WRITE,
+		.set_args	= IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE,
+		.name		= "write_sprom",
+	},
+	{
+		.cmd		= PRIV_WX_SPROM_READ,
+		.get_args	= IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE,
+		.name		= "read_sprom",
+	},
+};
+
+const struct iw_handler_def bcm43xx_wx_handlers_def = {
+	.standard		= bcm43xx_wx_handlers,
+	.num_standard		= ARRAY_SIZE(bcm43xx_wx_handlers),
+	.num_private		= ARRAY_SIZE(bcm43xx_priv_wx_handlers),
+	.num_private_args	= ARRAY_SIZE(bcm43xx_priv_wx_args),
+	.private		= bcm43xx_priv_wx_handlers,
+	.private_args		= bcm43xx_priv_wx_args,
+	.get_wireless_stats	= bcm43xx_get_wireless_stats,
+};
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.h b/drivers/net/wireless/bcm43xx/bcm43xx_wx.h
new file mode 100644
index 0000000..1f29ff3
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.h
@@ -0,0 +1,36 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef BCM43xx_WX_H_
+#define BCM43xx_WX_H_
+
+extern const struct iw_handler_def bcm43xx_wx_handlers_def;
+
+#endif /* BCM43xx_WX_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
new file mode 100644
index 0000000..d8ece28
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -0,0 +1,582 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Transmission (TX/RX) related functions.
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx_xmit.h"
+
+#include <linux/etherdevice.h>
+
+
+/* Extract the bitrate out of a CCK PLCP header. */
+static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4 *plcp)
+{
+	switch (plcp->raw[0]) {
+	case 0x0A:
+		return IEEE80211_CCK_RATE_1MB;
+	case 0x14:
+		return IEEE80211_CCK_RATE_2MB;
+	case 0x37:
+		return IEEE80211_CCK_RATE_5MB;
+	case 0x6E:
+		return IEEE80211_CCK_RATE_11MB;
+	}
+	assert(0);
+	return 0;
+}
+
+/* Extract the bitrate out of an OFDM PLCP header. */
+static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4 *plcp)
+{
+	switch (plcp->raw[0] & 0xF) {
+	case 0xB:
+		return IEEE80211_OFDM_RATE_6MB;
+	case 0xF:
+		return IEEE80211_OFDM_RATE_9MB;
+	case 0xA:
+		return IEEE80211_OFDM_RATE_12MB;
+	case 0xE:
+		return IEEE80211_OFDM_RATE_18MB;
+	case 0x9:
+		return IEEE80211_OFDM_RATE_24MB;
+	case 0xD:
+		return IEEE80211_OFDM_RATE_36MB;
+	case 0x8:
+		return IEEE80211_OFDM_RATE_48MB;
+	case 0xC:
+		return IEEE80211_OFDM_RATE_54MB;
+	}
+	assert(0);
+	return 0;
+}
+
+u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate)
+{
+	switch (bitrate) {
+	case IEEE80211_CCK_RATE_1MB:
+		return 0x0A;
+	case IEEE80211_CCK_RATE_2MB:
+		return 0x14;
+	case IEEE80211_CCK_RATE_5MB:
+		return 0x37;
+	case IEEE80211_CCK_RATE_11MB:
+		return 0x6E;
+	}
+	assert(0);
+	return 0;
+}
+
+u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate)
+{
+	switch (bitrate) {
+	case IEEE80211_OFDM_RATE_6MB:
+		return 0xB;
+	case IEEE80211_OFDM_RATE_9MB:
+		return 0xF;
+	case IEEE80211_OFDM_RATE_12MB:
+		return 0xA;
+	case IEEE80211_OFDM_RATE_18MB:
+		return 0xE;
+	case IEEE80211_OFDM_RATE_24MB:
+		return 0x9;
+	case IEEE80211_OFDM_RATE_36MB:
+		return 0xD;
+	case IEEE80211_OFDM_RATE_48MB:
+		return 0x8;
+	case IEEE80211_OFDM_RATE_54MB:
+		return 0xC;
+	}
+	assert(0);
+	return 0;
+}
+
+static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
+				      const u16 octets, const u8 bitrate,
+				      const int ofdm_modulation)
+{
+	__le32 *data = &(plcp->data);
+	__u8 *raw = plcp->raw;
+
+	if (ofdm_modulation) {
+		*data = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
+		assert(!(octets & 0xF000));
+		*data |= (octets << 5);
+		*data = cpu_to_le32(*data);
+	} else {
+		u32 plen;
+
+		plen = octets * 16 / bitrate;
+		if ((octets * 16 % bitrate) > 0) {
+			plen++;
+			if ((bitrate == IEEE80211_CCK_RATE_11MB)
+			    && ((octets * 8 % 11) < 4)) {
+				raw[1] = 0x84;
+			} else
+				raw[1] = 0x04;
+		} else
+			raw[1] = 0x04;
+		*data |= cpu_to_le32(plen << 16);
+		raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate);
+	}
+}
+
+static u8 bcm43xx_calc_fallback_rate(u8 bitrate)
+{
+	switch (bitrate) {
+	case IEEE80211_CCK_RATE_1MB:
+		return IEEE80211_CCK_RATE_1MB;
+	case IEEE80211_CCK_RATE_2MB:
+		return IEEE80211_CCK_RATE_1MB;
+	case IEEE80211_CCK_RATE_5MB:
+		return IEEE80211_CCK_RATE_2MB;
+	case IEEE80211_CCK_RATE_11MB:
+		return IEEE80211_CCK_RATE_5MB;
+	case IEEE80211_OFDM_RATE_6MB:
+		return IEEE80211_CCK_RATE_5MB;
+	case IEEE80211_OFDM_RATE_9MB:
+		return IEEE80211_OFDM_RATE_6MB;
+	case IEEE80211_OFDM_RATE_12MB:
+		return IEEE80211_OFDM_RATE_9MB;
+	case IEEE80211_OFDM_RATE_18MB:
+		return IEEE80211_OFDM_RATE_12MB;
+	case IEEE80211_OFDM_RATE_24MB:
+		return IEEE80211_OFDM_RATE_18MB;
+	case IEEE80211_OFDM_RATE_36MB:
+		return IEEE80211_OFDM_RATE_24MB;
+	case IEEE80211_OFDM_RATE_48MB:
+		return IEEE80211_OFDM_RATE_36MB;
+	case IEEE80211_OFDM_RATE_54MB:
+		return IEEE80211_OFDM_RATE_48MB;
+	}
+	assert(0);
+	return 0;
+}
+
+static
+__le16 bcm43xx_calc_duration_id(const struct ieee80211_hdr *wireless_header,
+				u8 bitrate)
+{
+	const u16 frame_ctl = le16_to_cpu(wireless_header->frame_ctl);
+	__le16 duration_id = wireless_header->duration_id;
+
+	switch (WLAN_FC_GET_TYPE(frame_ctl)) {
+	case IEEE80211_FTYPE_DATA:
+	case IEEE80211_FTYPE_MGMT:
+		//TODO: Steal the code from ieee80211, once it is completed there.
+		break;
+	case IEEE80211_FTYPE_CTL:
+		/* Use the original duration/id. */
+		break;
+	default:
+		assert(0);
+	}
+
+	return duration_id;
+}
+
+static inline
+u16 ceiling_div(u16 dividend, u16 divisor)
+{
+	return ((dividend + divisor - 1) / divisor);
+}
+
+static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy,
+				 struct bcm43xx_txhdr *txhdr,
+				 u16 *flags,
+				 u8 bitrate,
+				 const struct ieee80211_hdr_4addr *wlhdr)
+{
+	u16 fctl;
+	u16 dur;
+	u8 fallback_bitrate;
+	int ofdm_modulation;
+	int fallback_ofdm_modulation;
+//	u8 *sa, *da;
+	u16 flen;
+
+//FIXME	sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr);
+//FIXME	da = ieee80211_get_DA((struct ieee80211_hdr *)wlhdr);
+	fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
+	ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
+	fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
+
+	flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + IEEE80211_FCS_LEN,
+	bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp),
+				  flen, bitrate,
+				  !ieee80211_is_cck_rate(bitrate));
+	bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp),
+				  flen, fallback_bitrate,
+				  !ieee80211_is_cck_rate(fallback_bitrate));
+	fctl = IEEE80211_FTYPE_CTL;
+	fctl |= IEEE80211_STYPE_RTS;
+	dur = le16_to_cpu(wlhdr->duration_id);
+/*FIXME: should we test for dur==0 here and let it unmodified in this case?
+ *       The following assert checks for this case...
+ */
+assert(dur);
+/*FIXME: The duration calculation is not really correct.
+ *       I am not 100% sure which bitrate to use. We use the RTS rate here,
+ *       but this is likely to be wrong.
+ */
+	if (phy->type == BCM43xx_PHYTYPE_A) {
+		/* Three times SIFS */
+		dur += 16 * 3;
+		/* Add ACK duration. */
+		dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
+				   bitrate * 4);
+		/* Add CTS duration. */
+		dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
+				   bitrate * 4);
+	} else {
+		/* Three times SIFS */
+		dur += 10 * 3;
+		/* Add ACK duration. */
+		dur += ceiling_div(8 * (14 /*bytes*/) * 10,
+				   bitrate);
+		/* Add CTS duration. */
+		dur += ceiling_div(8 * (14 /*bytes*/) * 10,
+				   bitrate);
+	}
+
+	txhdr->rts_cts_frame_control = cpu_to_le16(fctl);
+	txhdr->rts_cts_dur = cpu_to_le16(dur);
+//printk(BCM43xx_MACFMT "  " BCM43xx_MACFMT "  " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3));
+//printk(BCM43xx_MACFMT "  " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da));
+	memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME!
+//	memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN);
+
+	*flags |= BCM43xx_TXHDRFLAG_RTSCTS;
+	*flags |= BCM43xx_TXHDRFLAG_RTS;
+	if (ofdm_modulation)
+		*flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM;
+	if (fallback_ofdm_modulation)
+		*flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM;
+}
+				 
+void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
+			    struct bcm43xx_txhdr *txhdr,
+			    const unsigned char *fragment_data,
+			    const unsigned int fragment_len,
+			    const int is_first_fragment,
+			    const u16 cookie)
+{
+	const struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data;
+	const struct ieee80211_security *secinfo = &bcm->ieee->sec;
+	u8 bitrate;
+	u8 fallback_bitrate;
+	int ofdm_modulation;
+	int fallback_ofdm_modulation;
+	u16 plcp_fragment_len = fragment_len;
+	u16 flags = 0;
+	u16 control = 0;
+	u16 wsec_rate = 0;
+	u16 encrypt_frame;
+
+	/* Now construct the TX header. */
+	memset(txhdr, 0, sizeof(*txhdr));
+
+	bitrate = bcm->softmac->txrates.default_rate;
+	ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
+	fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
+	fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
+
+	/* Set Frame Control from 80211 header. */
+	txhdr->frame_control = wireless_header->frame_ctl;
+	/* Copy address1 from 80211 header. */
+	memcpy(txhdr->mac1, wireless_header->addr1, 6);
+	/* Set the fallback duration ID. */
+	txhdr->fallback_dur_id = bcm43xx_calc_duration_id((const struct ieee80211_hdr *)wireless_header,
+							  fallback_bitrate);
+	/* Set the cookie (used as driver internal ID for the frame) */
+	txhdr->cookie = cpu_to_le16(cookie);
+
+	/* Hardware appends FCS. */
+	plcp_fragment_len += IEEE80211_FCS_LEN;
+
+	/* Hardware encryption. */
+	encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED;
+	if (encrypt_frame && !bcm->ieee->host_encrypt) {
+		const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header;
+		memcpy(txhdr->wep_iv, hdr->payload, 4);
+		/* Hardware appends ICV. */
+		plcp_fragment_len += 4;
+
+		wsec_rate |= (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT)
+			     & BCM43xx_TXHDR_WSEC_ALGO_MASK;
+		wsec_rate |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT)
+			     & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK;
+	}
+
+	/* Generate the PLCP header and the fallback PLCP header. */
+	bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp),
+				  plcp_fragment_len,
+				  bitrate, ofdm_modulation);
+	bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len,
+				  fallback_bitrate, fallback_ofdm_modulation);
+
+	/* Set the CONTROL field */
+	if (ofdm_modulation)
+		control |= BCM43xx_TXHDRCTL_OFDM;
+	if (bcm->short_preamble) //FIXME: could be the other way around, please test
+		control |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE;
+	control |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT)
+		   & BCM43xx_TXHDRCTL_ANTENNADIV_MASK;
+
+	/* Set the FLAGS field */
+	if (!is_multicast_ether_addr(wireless_header->addr1) &&
+	    !is_broadcast_ether_addr(wireless_header->addr1))
+		flags |= BCM43xx_TXHDRFLAG_EXPECTACK;
+	if (1 /* FIXME: PS poll?? */)
+		flags |= 0x10; // FIXME: unknown meaning.
+	if (fallback_ofdm_modulation)
+		flags |= BCM43xx_TXHDRFLAG_FALLBACKOFDM;
+	if (is_first_fragment)
+		flags |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT;
+
+	/* Set WSEC/RATE field */
+	wsec_rate |= (txhdr->plcp.raw[0] << BCM43xx_TXHDR_RATE_SHIFT)
+		     & BCM43xx_TXHDR_RATE_MASK;
+
+	/* Generate the RTS/CTS packet, if required. */
+	/* FIXME: We should first try with CTS-to-self,
+	 *        if we are on 80211g. If we get too many
+	 *        failures (hidden nodes), we should switch back to RTS/CTS.
+	 */
+	if (0/*FIXME txctl->use_rts_cts*/) {
+		bcm43xx_generate_rts(phy, txhdr, &flags,
+				     0/*FIXME txctl->rts_cts_rate*/,
+				     wireless_header);
+	}
+
+	txhdr->flags = cpu_to_le16(flags);
+	txhdr->control = cpu_to_le16(control);
+	txhdr->wsec_rate = cpu_to_le16(wsec_rate);
+}
+
+static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm,
+				   u8 in_rssi, int ofdm,
+				   int adjust_2053, int adjust_2050)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	s32 tmp;
+
+	switch (radio->version) {
+	case 0x2050:
+		if (ofdm) {
+			tmp = in_rssi;
+			if (tmp > 127)
+				tmp -= 256;
+			tmp *= 73;
+			tmp /= 64;
+			if (adjust_2050)
+				tmp += 25;
+			else
+				tmp -= 3;
+		} else {
+			if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
+				if (in_rssi > 63)
+					in_rssi = 63;
+				tmp = radio->nrssi_lt[in_rssi];
+				tmp = 31 - tmp;
+				tmp *= -131;
+				tmp /= 128;
+				tmp -= 57;
+			} else {
+				tmp = in_rssi;
+				tmp = 31 - tmp;
+				tmp *= -149;
+				tmp /= 128;
+				tmp -= 68;
+			}
+			if (phy->type == BCM43xx_PHYTYPE_G &&
+			    adjust_2050)
+				tmp += 25;
+		}
+		break;
+	case 0x2060:
+		if (in_rssi > 127)
+			tmp = in_rssi - 256;
+		else
+			tmp = in_rssi;
+		break;
+	default:
+		tmp = in_rssi;
+		tmp -= 11;
+		tmp *= 103;
+		tmp /= 64;
+		if (adjust_2053)
+			tmp -= 109;
+		else
+			tmp -= 83;
+	}
+
+	return (s8)tmp;
+}
+
+//TODO
+#if 0
+static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm,
+					u8 in_rssi)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	s8 ret;
+
+	if (phy->type == BCM43xx_PHYTYPE_A) {
+		//TODO: Incomplete specs.
+		ret = 0;
+	} else
+		ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1);
+
+	return ret;
+}
+#endif
+
+int bcm43xx_rx(struct bcm43xx_private *bcm,
+	       struct sk_buff *skb,
+	       struct bcm43xx_rxhdr *rxhdr)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_plcp_hdr4 *plcp;
+	struct ieee80211_rx_stats stats;
+	struct ieee80211_hdr_4addr *wlhdr;
+	u16 frame_ctl;
+	int is_packet_for_us = 0;
+	int err = -EINVAL;
+	const u16 rxflags1 = le16_to_cpu(rxhdr->flags1);
+	const u16 rxflags2 = le16_to_cpu(rxhdr->flags2);
+	const u16 rxflags3 = le16_to_cpu(rxhdr->flags3);
+	const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM);
+
+	if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) {
+		plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2);
+		/* Skip two unknown bytes and the PLCP header. */
+		skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6));
+	} else {
+		plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data);
+		/* Skip the PLCP header. */
+		skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6));
+	}
+	/* The SKB contains the PAYLOAD (wireless header + data)
+	 * at this point. The FCS at the end is stripped.
+	 */
+
+	memset(&stats, 0, sizeof(stats));
+	stats.mac_time = le16_to_cpu(rxhdr->mactime);
+	stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
+					      !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
+					      !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
+	stats.signal = rxhdr->signal_quality;	//FIXME
+//TODO	stats.noise = 
+	if (is_ofdm)
+		stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
+	else
+		stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
+//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
+	stats.received_channel = radio->channel;
+//TODO	stats.control = 
+	stats.mask = IEEE80211_STATMASK_SIGNAL |
+//TODO		     IEEE80211_STATMASK_NOISE |
+		     IEEE80211_STATMASK_RATE |
+		     IEEE80211_STATMASK_RSSI;
+	if (phy->type == BCM43xx_PHYTYPE_A)
+		stats.freq = IEEE80211_52GHZ_BAND;
+	else
+		stats.freq = IEEE80211_24GHZ_BAND;
+	stats.len = skb->len;
+
+	bcm->stats.last_rx = jiffies;
+	if (bcm->ieee->iw_mode == IW_MODE_MONITOR) {
+		err = ieee80211_rx(bcm->ieee, skb, &stats);
+		return (err == 0) ? -EINVAL : 0;
+	}
+
+	wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
+
+	switch (bcm->ieee->iw_mode) {
+	case IW_MODE_ADHOC:
+		if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
+		    memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
+		    is_broadcast_ether_addr(wlhdr->addr1) ||
+		    is_multicast_ether_addr(wlhdr->addr1) ||
+		    bcm->net_dev->flags & IFF_PROMISC)
+			is_packet_for_us = 1;
+		break;
+	case IW_MODE_INFRA:
+	default:
+		/* When receiving multicast or broadcast packets, filter out
+		   the packets we send ourself; we shouldn't see those */
+		if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
+		    memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
+		    (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) &&
+		     (is_broadcast_ether_addr(wlhdr->addr1) ||
+		      is_multicast_ether_addr(wlhdr->addr1) ||
+		      bcm->net_dev->flags & IFF_PROMISC)))
+			is_packet_for_us = 1;
+		break;
+	}
+
+	frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
+	if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) {
+		frame_ctl &= ~IEEE80211_FCTL_PROTECTED;
+		wlhdr->frame_ctl = cpu_to_le16(frame_ctl);		
+		/* trim IV and ICV */
+		/* FIXME: this must be done only for WEP encrypted packets */
+		if (skb->len < 32) {
+			dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag "
+					      "set and length < 32)\n");
+			return -EINVAL;
+		} else {		
+			memmove(skb->data + 4, skb->data, 24);
+			skb_pull(skb, 4);
+			skb_trim(skb, skb->len - 4);
+			stats.len -= 8;
+		}
+		wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
+	}
+	
+	switch (WLAN_FC_GET_TYPE(frame_ctl)) {
+	case IEEE80211_FTYPE_MGMT:
+		ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats);
+		break;
+	case IEEE80211_FTYPE_DATA:
+		if (is_packet_for_us) {
+			err = ieee80211_rx(bcm->ieee, skb, &stats);
+			err = (err == 0) ? -EINVAL : 0;
+		}
+		break;
+	case IEEE80211_FTYPE_CTL:
+		break;
+	default:
+		assert(0);
+		return -EINVAL;
+	}
+
+	return err;
+}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
new file mode 100644
index 0000000..2aed19e
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
@@ -0,0 +1,156 @@
+#ifndef BCM43xx_XMIT_H_
+#define BCM43xx_XMIT_H_
+
+#include "bcm43xx_main.h"
+
+
+#define _bcm43xx_declare_plcp_hdr(size) \
+	struct bcm43xx_plcp_hdr##size {		\
+		union {				\
+			__le32 data;		\
+			__u8 raw[size];		\
+		} __attribute__((__packed__));	\
+	} __attribute__((__packed__))
+
+/* struct bcm43xx_plcp_hdr4 */
+_bcm43xx_declare_plcp_hdr(4);
+/* struct bcm43xx_plcp_hdr6 */
+_bcm43xx_declare_plcp_hdr(6);
+
+#undef _bcm43xx_declare_plcp_hdr
+
+/* Device specific TX header. To be prepended to TX frames. */
+struct bcm43xx_txhdr {
+	union {
+		struct {
+			__le16 flags;
+			__le16 wsec_rate;
+			__le16 frame_control;
+			u16 unknown_zeroed_0;
+			__le16 control;
+			u8 wep_iv[10];
+			u8 unknown_wsec_tkip_data[3]; //FIXME
+			PAD_BYTES(3);
+			u8 mac1[6];
+			u16 unknown_zeroed_1;
+			struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp;
+			__le16 rts_cts_dur_fallback;
+			struct bcm43xx_plcp_hdr4 fallback_plcp;
+			__le16 fallback_dur_id;
+			PAD_BYTES(2);
+			__le16 cookie;
+			__le16 unknown_scb_stuff; //FIXME
+			struct bcm43xx_plcp_hdr6 rts_cts_plcp;
+			__le16 rts_cts_frame_control;
+			__le16 rts_cts_dur;
+			u8 rts_cts_mac1[6];
+			u8 rts_cts_mac2[6];
+			PAD_BYTES(2);
+			struct bcm43xx_plcp_hdr6 plcp;
+		} __attribute__((__packed__));
+		u8 raw[82];
+	} __attribute__((__packed__));
+} __attribute__((__packed__));
+
+/* Values/Masks for the device TX header */
+#define BCM43xx_TXHDRFLAG_EXPECTACK		0x0001
+#define BCM43xx_TXHDRFLAG_RTSCTS		0x0002
+#define BCM43xx_TXHDRFLAG_RTS			0x0004
+#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT		0x0008
+#define BCM43xx_TXHDRFLAG_DESTPSMODE		0x0020
+#define BCM43xx_TXHDRFLAG_RTSCTS_OFDM		0x0080
+#define BCM43xx_TXHDRFLAG_FALLBACKOFDM		0x0100
+#define BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM	0x0200
+#define BCM43xx_TXHDRFLAG_CTS			0x0400
+#define BCM43xx_TXHDRFLAG_FRAMEBURST		0x0800
+
+#define BCM43xx_TXHDRCTL_OFDM			0x0001
+#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE		0x0010
+#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK	0x0030
+#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT	8
+
+#define BCM43xx_TXHDR_RATE_MASK			0x0F00
+#define BCM43xx_TXHDR_RATE_SHIFT		8
+#define BCM43xx_TXHDR_RTSRATE_MASK		0xF000
+#define BCM43xx_TXHDR_RTSRATE_SHIFT		12
+#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK	0x00F0
+#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT	4
+#define BCM43xx_TXHDR_WSEC_ALGO_MASK		0x0003
+#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT		0
+
+void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
+			    struct bcm43xx_txhdr *txhdr,
+			    const unsigned char *fragment_data,
+			    const unsigned int fragment_len,
+			    const int is_first_fragment,
+			    const u16 cookie);
+
+/* RX header as received from the hardware. */
+struct bcm43xx_rxhdr {
+	/* Frame Length. Must be generated explicitely in PIO mode. */
+	__le16 frame_length;
+	PAD_BYTES(2);
+	/* Flags field 1 */
+	__le16 flags1;
+	u8 rssi;
+	u8 signal_quality;
+	PAD_BYTES(2);
+	/* Flags field 3 */
+	__le16 flags3;
+	/* Flags field 2 */
+	__le16 flags2;
+	/* Lower 16bits of the TSF at the time the frame started. */
+	__le16 mactime;
+	PAD_BYTES(14);
+} __attribute__((__packed__));
+
+#define BCM43xx_RXHDR_FLAGS1_OFDM		(1 << 0)
+/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL???	(1 << 3) FIXME */
+#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE	(1 << 7)
+#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ	(1 << 14)
+
+#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME	(1 << 0)
+#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME		(1 << 2)
+/*FIXME: WEP related flags */
+
+#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ	(1 << 10)
+
+/* Transmit Status as received from the hardware. */
+struct bcm43xx_hwxmitstatus {
+	PAD_BYTES(4);
+	__le16 cookie;
+	u8 flags;
+	u8 cnt1:4,
+	   cnt2:4;
+	PAD_BYTES(2);
+	__le16 seq;
+	__le16 unknown; //FIXME
+} __attribute__((__packed__));
+
+/* Transmit Status in CPU byteorder. */
+struct bcm43xx_xmitstatus {
+	u16 cookie;
+	u8 flags;
+	u8 cnt1:4,
+	   cnt2:4;
+	u16 seq;
+	u16 unknown; //FIXME
+};
+
+#define BCM43xx_TXSTAT_FLAG_ACK		0x01
+//TODO #define BCM43xx_TXSTAT_FLAG_???	0x02
+//TODO #define BCM43xx_TXSTAT_FLAG_???	0x04
+//TODO #define BCM43xx_TXSTAT_FLAG_???	0x08
+//TODO #define BCM43xx_TXSTAT_FLAG_???	0x10
+#define BCM43xx_TXSTAT_FLAG_IGNORE	0x20
+//TODO #define BCM43xx_TXSTAT_FLAG_???	0x40
+//TODO #define BCM43xx_TXSTAT_FLAG_???	0x80
+
+u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate);
+u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate);
+
+int bcm43xx_rx(struct bcm43xx_private *bcm,
+	       struct sk_buff *skb,
+	       struct bcm43xx_rxhdr *rxhdr);
+
+#endif /* BCM43xx_XMIT_H_ */
diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h
index 1fc72fe..cc1ee7f 100644
--- a/drivers/net/wireless/hostap/hostap_80211.h
+++ b/drivers/net/wireless/hostap/hostap_80211.h
@@ -92,8 +92,6 @@
 void hostap_dump_tx_80211(const char *name, struct sk_buff *skb);
 int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev);
 int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev);
-struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
-				   struct ieee80211_crypt_data *crypt);
 int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
 
 #endif /* HOSTAP_80211_H */
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index 4a85e63..06a5214 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -299,8 +299,8 @@
 
 
 /* Called only from software IRQ */
-struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
-				   struct ieee80211_crypt_data *crypt)
+static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
+					  struct ieee80211_crypt_data *crypt)
 {
 	struct hostap_interface *iface;
 	local_info_t *local;
@@ -317,7 +317,7 @@
 	}
 
 	if (local->tkip_countermeasures &&
-	    crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) {
+	    strcmp(crypt->ops->name, "TKIP") == 0) {
 		hdr = (struct ieee80211_hdr_4addr *) skb->data;
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
@@ -469,7 +469,7 @@
 	}
 
 	if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt &&
-	    !(fc & IEEE80211_FCTL_VERS)) {
+	    !(fc & IEEE80211_FCTL_PROTECTED)) {
 		no_encrypt = 1;
 		PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing "
 		       "unencrypted EAPOL frame\n", dev->name);
@@ -535,5 +535,4 @@
 
 
 EXPORT_SYMBOL(hostap_dump_tx_80211);
-EXPORT_SYMBOL(hostap_tx_encrypt);
 EXPORT_SYMBOL(hostap_master_start_xmit);
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 6fd0bf7..8dfdfbd 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -3858,7 +3858,7 @@
 	unsigned long flags;
 
 	/* Note : you may have realised that, as this is a SET operation,
-	 * this is priviledged and therefore a normal user can't
+	 * this is privileged and therefore a normal user can't
 	 * perform scanning.
 	 * This is not an error, while the device perform scanning,
 	 * traffic doesn't flow, so it's a perfect DoS...
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index e5bb9f5..989599a 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -747,7 +747,7 @@
 
 	if (essid->length) {
 		dwrq->flags = 1;	/* set ESSID to ON for Wireless Extensions */
-		/* if it is to big, trunk it */
+		/* if it is too big, trunk it */
 		dwrq->length = min((u8)IW_ESSID_MAX_SIZE, essid->length);
 	} else {
 		dwrq->flags = 0;
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index b41d666..bfa0cc3 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -22,6 +22,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/init.h> /* For __init, __exit */
+#include <linux/dma-mapping.h>
 
 #include "prismcompat.h"
 #include "islpci_dev.h"
@@ -124,7 +125,7 @@
 	}
 
 	/* enable PCI DMA */
-	if (pci_set_dma_mask(pdev, 0xffffffff)) {
+	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
 		printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME);
 		goto do_pci_disable_device;
         }
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index 330d386..fc4bc9b 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -217,11 +217,10 @@
 	cpu_buf->tracing = 0;
 }
 
-void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
+void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
+				unsigned long event, int is_kernel)
 {
 	struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()];
-	unsigned long pc = profile_pc(regs);
-	int is_kernel = !user_mode(regs);
 
 	if (!backtrace_depth) {
 		log_sample(cpu_buf, pc, is_kernel, event);
@@ -238,6 +237,14 @@
 	oprofile_end_trace(cpu_buf);
 }
 
+void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
+{
+	int is_kernel = !user_mode(regs);
+	unsigned long pc = profile_pc(regs);
+
+	oprofile_add_ext_sample(pc, regs, event, is_kernel);
+}
+
 void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)
 {
 	struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()];
diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c
index e94b1e4..f0acb66 100644
--- a/drivers/oprofile/oprofile_stats.c
+++ b/drivers/oprofile/oprofile_stats.c
@@ -22,7 +22,7 @@
 	struct oprofile_cpu_buffer * cpu_buf; 
 	int i;
  
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		cpu_buf = &cpu_buffer[i]; 
 		cpu_buf->sample_received = 0;
 		cpu_buf->sample_lost_overflow = 0;
@@ -46,7 +46,7 @@
 	if (!dir)
 		return;
 
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		cpu_buf = &cpu_buffer[i]; 
 		snprintf(buf, 10, "cpu%d", i);
 		cpudir = oprofilefs_mkdir(sb, dir, buf);
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index d6bae69..b62da9b 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -130,7 +130,7 @@
 
 
 static struct dentry * __oprofilefs_create_file(struct super_block * sb,
-	struct dentry * root, char const * name, struct file_operations * fops,
+	struct dentry * root, char const * name, const struct file_operations * fops,
 	int perm)
 {
 	struct dentry * dentry;
@@ -203,7 +203,7 @@
 
  
 int oprofilefs_create_file(struct super_block * sb, struct dentry * root,
-	char const * name, struct file_operations * fops)
+	char const * name, const struct file_operations * fops)
 {
 	if (!__oprofilefs_create_file(sb, root, name, fops, 0644))
 		return -EFAULT;
@@ -212,7 +212,7 @@
 
 
 int oprofilefs_create_file_perm(struct super_block * sb, struct dentry * root,
-	char const * name, struct file_operations * fops, int perm)
+	char const * name, const struct file_operations * fops, int perm)
 {
 	if (!__oprofilefs_create_file(sb, root, name, fops, perm))
 		return -EFAULT;
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index 93f8a8f..a5d8262 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -1560,7 +1560,7 @@
 	*ioc_p = ioc;
 
 	ioc->hw_path = dev->hw_path;
-	ioc->ioc_regs = ioremap(dev->hpa.start, 4096);
+	ioc->ioc_regs = ioremap_nocache(dev->hpa.start, 4096);
 	ccio_ioc_init(ioc);
 	ccio_init_resources(ioc);
 	hppa_dma_ops = &ccio_ops;
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 3d1a7f9..6e8ed0c 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -5,6 +5,7 @@
 **	(c) Copyright 1999 SuSE GmbH
 **	(c) Copyright 1999,2000 Hewlett-Packard Company
 **	(c) Copyright 2000 Grant Grundler
+**	(c) Copyright 2006 Helge Deller
 **
 **	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
@@ -785,7 +786,7 @@
 		if((io_addr & (1 << i)) == 0)
 			continue;
 
-		start = (unsigned long)(signed int)(0xf0000000 | (i << 23));
+		start = F_EXTEND(0xf0000000UL) | (i << 23);
 		end = start + 8 * 1024 * 1024 - 1;
 
 		DBG("DINO RANGE %d is at 0x%lx-0x%lx\n", count,
@@ -996,7 +997,7 @@
 	}
 
 	dino_dev->hba.dev = dev;
-	dino_dev->hba.base_addr = ioremap(hpa, 4096);
+	dino_dev->hba.base_addr = ioremap_nocache(hpa, 4096);
 	dino_dev->hba.lmmio_space_offset = 0;	/* CPU addrs == bus addrs */
 	spin_lock_init(&dino_dev->dinosaur_pen);
 	dino_dev->hba.iommu = ccio_get_iommu(dev);
diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
index 3d94d86..9d3bd15 100644
--- a/drivers/parisc/eisa.c
+++ b/drivers/parisc/eisa.c
@@ -366,7 +366,7 @@
 			eisa_dev.eeprom_addr = MIRAGE_EEPROM_BASE_ADDR;
 		}
 	}
-	eisa_eeprom_addr = ioremap(eisa_dev.eeprom_addr, HPEE_MAX_LENGTH);
+	eisa_eeprom_addr = ioremap_nocache(eisa_dev.eeprom_addr, HPEE_MAX_LENGTH);
 	result = eisa_enumerator(eisa_dev.eeprom_addr, &eisa_dev.hba.io_space,
 			&eisa_dev.hba.lmmio_space);
 	init_eisa_pic();
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index 8d7a363..7a458d5 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -879,7 +879,7 @@
 		return NULL;
 	}
 
-	isi->addr = ioremap(hpa, 4096);
+	isi->addr = ioremap_nocache(hpa, 4096);
 	isi->isi_hpa = hpa;
 	isi->isi_version = iosapic_rd_version(isi);
 	isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index e8a2a4a..3fe4a77 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1213,7 +1213,7 @@
 			** Postable I/O port space is per PCI host adapter.
 			** base of 64MB PIOP region
 			*/
-			lba_dev->iop_base = ioremap(p->start, 64 * 1024 * 1024);
+			lba_dev->iop_base = ioremap_nocache(p->start, 64 * 1024 * 1024);
 
 			sprintf(lba_dev->hba.io_name, "PCI%02lx Ports",
 					lba_dev->hba.bus_num.start);
@@ -1525,7 +1525,7 @@
 	u32 func_class;
 	void *tmp_obj;
 	char *version;
-	void __iomem *addr = ioremap(dev->hpa.start, 4096);
+	void __iomem *addr = ioremap_nocache(dev->hpa.start, 4096);
 
 	/* Read HW Rev First */
 	func_class = READ_REG32(addr + LBA_FCLASS);
@@ -1619,7 +1619,7 @@
 	} else {
 		if (!astro_iop_base) {
 			/* Sprockets PDC uses NPIOP region */
-			astro_iop_base = ioremap(LBA_PORT_BASE, 64 * 1024);
+			astro_iop_base = ioremap_nocache(LBA_PORT_BASE, 64 * 1024);
 			pci_port = &lba_astro_port_ops;
 		}
 
@@ -1700,7 +1700,7 @@
 */
 void lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask)
 {
-	void __iomem * base_addr = ioremap(lba->hpa.start, 4096);
+	void __iomem * base_addr = ioremap_nocache(lba->hpa.start, 4096);
 
 	imask <<= 2;	/* adjust for hints - 2 more bits */
 
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index 3627a2d..298f2dd 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -499,11 +499,16 @@
 static struct notifier_block led_notifier = {
 	.notifier_call = led_halt,
 };
+static int notifier_disabled = 0;
 
 static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) 
 {
 	char *txt;
-	
+
+	if (notifier_disabled)
+		return NOTIFY_OK;
+
+	notifier_disabled = 1;
 	switch (event) {
 	case SYS_RESTART:	txt = "SYSTEM RESTART";
 				break;
@@ -527,7 +532,6 @@
 		if (led_func_ptr)
 			led_func_ptr(0xff); /* turn all LEDs ON */
 	
-	unregister_reboot_notifier(&led_notifier);
 	return NOTIFY_OK;
 }
 
@@ -758,6 +762,12 @@
 	return 1;
 }
 
+static void __exit led_exit(void)
+{
+	unregister_reboot_notifier(&led_notifier);
+	return;
+}
+
 #ifdef CONFIG_PROC_FS
 module_init(led_create_procfs)
 #endif
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index a28e178..4e53be9 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -4,9 +4,8 @@
  *    Copyright (C) 2005-2006 Thibaut VARENE <varenet@parisc-linux.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.
+ *    it under the terms of the GNU General Public License, version 2, as
+ *    published by the Free Software Foundation.
  *
  *    This program is distributed in the hope that it will be useful,
  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c
index 54b2b7f..0bcab83 100644
--- a/drivers/parisc/power.c
+++ b/drivers/parisc/power.c
@@ -251,7 +251,8 @@
 	}
 
 	/* Register a call for panic conditions. */
-	notifier_chain_register(&panic_notifier_list, &parisc_panic_block);
+	atomic_notifier_chain_register(&panic_notifier_list,
+			&parisc_panic_block);
 
 	tasklet_enable(&power_tasklet);
 
@@ -264,7 +265,8 @@
 		return;
 
 	tasklet_disable(&power_tasklet);
-	notifier_chain_unregister(&panic_notifier_list, &parisc_panic_block);
+	atomic_notifier_chain_unregister(&panic_notifier_list,
+			&parisc_panic_block);
 	power_tasklet.func = NULL;
 	pdc_soft_power_button(0);
 }
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 0821747..42b32ff 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -1642,9 +1642,9 @@
 **
 **************************************************************************/
 
-static void __iomem *ioc_remap(struct sba_device *sba_dev, int offset)
+static void __iomem *ioc_remap(struct sba_device *sba_dev, unsigned int offset)
 {
-	return ioremap(sba_dev->dev->hpa.start + offset, SBA_FUNC_SIZE);
+	return ioremap_nocache(sba_dev->dev->hpa.start + offset, SBA_FUNC_SIZE);
 }
 
 static void sba_hw_init(struct sba_device *sba_dev)
@@ -2040,7 +2040,7 @@
 	u32 func_class;
 	int i;
 	char *version;
-	void __iomem *sba_addr = ioremap(dev->hpa.start, SBA_FUNC_SIZE);
+	void __iomem *sba_addr = ioremap_nocache(dev->hpa.start, SBA_FUNC_SIZE);
 	struct proc_dir_entry *info_entry, *bitmap_entry, *root;
 
 	sba_dump_ranges(sba_addr);
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index ad6d3b2..719b863 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -12,6 +12,7 @@
  *      (C) Copyright 2001 John Marvin <jsm fc hp com>
  *      (C) Copyright 2003 Grant Grundler <grundler parisc-linux org>
  *	(C) Copyright 2005 Kyle McMartin <kyle@parisc-linux.org>
+ *	(C) Copyright 2006 Helge Deller <deller@gmx.de>
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License as
@@ -388,43 +389,34 @@
 	return local_irq;
 }
 
-static struct uart_port serial[] = {
-	{
-		.iotype		= UPIO_PORT,
-		.line		= 0,
-		.type		= PORT_16550A,
-		.uartclk	= 115200*16,
-		.fifosize	= 16,
-	},
-	{
-		.iotype		= UPIO_PORT,
-		.line		= 1,
-		.type		= PORT_16550A,
-		.uartclk	= 115200*16,
-		.fifosize	= 16,
-	}
-};
-
 static void __devinit superio_serial_init(void)
 {
 #ifdef CONFIG_SERIAL_8250
 	int retval;
-        
-	serial[0].iobase = sio_dev.sp1_base;
-	serial[0].irq = SP1_IRQ;
-	spin_lock_init(&serial[0].lock);
+	struct uart_port serial_port;
 
-	retval = early_serial_setup(&serial[0]);
+	memset(&serial_port, 0, sizeof(serial_port));
+	serial_port.iotype	= UPIO_PORT;
+	serial_port.type	= PORT_16550A;
+	serial_port.uartclk	= 115200*16;
+	serial_port.fifosize	= 16;
+	spin_lock_init(&serial_port.lock);
+
+	/* serial port #1 */
+	serial_port.iobase	= sio_dev.sp1_base;
+	serial_port.irq		= SP1_IRQ;
+	serial_port.line	= 0;
+	retval = early_serial_setup(&serial_port);
 	if (retval < 0) {
 		printk(KERN_WARNING PFX "Register Serial #0 failed.\n");
 		return;
 	}
 
-	serial[1].iobase = sio_dev.sp2_base;
-	serial[1].irq = SP2_IRQ;
-	spin_lock_init(&serial[1].lock);
-	retval = early_serial_setup(&serial[1]);
-
+	/* serial port #2 */
+	serial_port.iobase	= sio_dev.sp2_base;
+	serial_port.irq		= SP2_IRQ;
+	serial_port.line	= 1;
+	retval = early_serial_setup(&serial_port);
 	if (retval < 0)
 		printk(KERN_WARNING PFX "Register Serial #1 failed.\n");
 #endif /* CONFIG_SERIAL_8250 */
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 9302b8f..d589002 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -3126,9 +3126,9 @@
  * autoirq is PARPORT_IRQ_NONE, PARPORT_IRQ_AUTO, or PARPORT_IRQ_PROBEONLY
  * autodma is PARPORT_DMA_NONE or PARPORT_DMA_AUTO
  */
-static int __init parport_pc_find_ports (int autoirq, int autodma)
+static void __init parport_pc_find_ports (int autoirq, int autodma)
 {
-	int count = 0, r;
+	int count = 0, err;
 
 #ifdef CONFIG_PARPORT_PC_SUPERIO
 	detect_and_report_winbond ();
@@ -3140,23 +3140,17 @@
 
 	/* PnP ports, skip detection if SuperIO already found them */
 	if (!count) {
-		r = pnp_register_driver (&parport_pc_pnp_driver);
-		if (r >= 0) {
+		err = pnp_register_driver (&parport_pc_pnp_driver);
+		if (!err)
 			pnp_registered_parport = 1;
-			count += r;
-		}
 	}
 
 	/* ISA ports and whatever (see asm/parport.h). */
-	count += parport_pc_find_nonpci_ports (autoirq, autodma);
+	parport_pc_find_nonpci_ports (autoirq, autodma);
 
-	r = pci_register_driver (&parport_pc_pci_driver);
-	if (r)
-		return r;
-	pci_registered_parport = 1;
-	count += 1;
-
-	return count;
+	err = pci_register_driver (&parport_pc_pci_driver);
+	if (!err)
+		pci_registered_parport = 1;
 }
 
 /*
@@ -3381,8 +3375,6 @@
 
 static int __init parport_pc_init(void)
 {
-	int count = 0;
-
 	if (parse_parport_params())
 		return -EINVAL;
 
@@ -3395,12 +3387,11 @@
 				break;
 			if ((io_hi[i]) == PARPORT_IOHI_AUTO)
 			       io_hi[i] = 0x400 + io[i];
-			if (parport_pc_probe_port(io[i], io_hi[i],
-						  irqval[i], dmaval[i], NULL))
-				count++;
+			parport_pc_probe_port(io[i], io_hi[i],
+						  irqval[i], dmaval[i], NULL);
 		}
 	} else
-		count += parport_pc_find_ports (irqval[0], dmaval[0]);
+		parport_pc_find_ports (irqval[0], dmaval[0]);
 
 	return 0;
 }
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index ea62bed..bbbfd79 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -32,6 +32,7 @@
 #include <linux/kmod.h>
 
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <asm/irq.h>
 
 #undef PARPORT_PARANOID
@@ -50,7 +51,7 @@
 
 static LIST_HEAD(drivers);
 
-static DECLARE_MUTEX(registration_lock);
+static DEFINE_MUTEX(registration_lock);
 
 /* What you can do to a port that's gone away.. */
 static void dead_write_lines (struct parport *p, unsigned char b){}
@@ -158,11 +159,11 @@
 	if (list_empty(&portlist))
 		get_lowlevel_driver ();
 
-	down(&registration_lock);
+	mutex_lock(&registration_lock);
 	list_for_each_entry(port, &portlist, list)
 		drv->attach(port);
 	list_add(&drv->list, &drivers);
-	up(&registration_lock);
+	mutex_unlock(&registration_lock);
 
 	return 0;
 }
@@ -188,11 +189,11 @@
 {
 	struct parport *port;
 
-	down(&registration_lock);
+	mutex_lock(&registration_lock);
 	list_del_init(&drv->list);
 	list_for_each_entry(port, &portlist, list)
 		drv->detach(port);
-	up(&registration_lock);
+	mutex_unlock(&registration_lock);
 }
 
 static void free_port (struct parport *port)
@@ -366,7 +367,7 @@
 #endif
 
 	parport_proc_register(port);
-	down(&registration_lock);
+	mutex_lock(&registration_lock);
 	spin_lock_irq(&parportlist_lock);
 	list_add_tail(&port->list, &portlist);
 	for (i = 1; i < 3; i++) {
@@ -383,7 +384,7 @@
 		if (slave)
 			attach_driver_chain(slave);
 	}
-	up(&registration_lock);
+	mutex_unlock(&registration_lock);
 }
 
 /**
@@ -409,7 +410,7 @@
 {
 	int i;
 
-	down(&registration_lock);
+	mutex_lock(&registration_lock);
 
 	/* Spread the word. */
 	detach_driver_chain (port);
@@ -436,7 +437,7 @@
 	}
 	spin_unlock(&parportlist_lock);
 
-	up(&registration_lock);
+	mutex_unlock(&registration_lock);
 
 	parport_proc_unregister(port);
 
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index 3eefe2c..46825fe 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -19,7 +19,7 @@
 #include <linux/string.h>
 
 #include <asm/pci-bridge.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/rtas.h>
 #include <asm/vio.h>
 
@@ -27,7 +27,7 @@
 #include "rpaphp.h"
 #include "rpadlpar.h"
 
-static DECLARE_MUTEX(rpadlpar_sem);
+static DEFINE_MUTEX(rpadlpar_mutex);
 
 #define DLPAR_MODULE_NAME "rpadlpar_io"
 
@@ -300,7 +300,7 @@
 	int node_type;
 	int rc = -EIO;
 
-	if (down_interruptible(&rpadlpar_sem))
+	if (mutex_lock_interruptible(&rpadlpar_mutex))
 		return -ERESTARTSYS;
 
 	/* Find newly added node */
@@ -324,7 +324,7 @@
 
 	printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name);
 exit:
-	up(&rpadlpar_sem);
+	mutex_unlock(&rpadlpar_mutex);
 	return rc;
 }
 
@@ -417,7 +417,7 @@
 	int node_type;
 	int rc = 0;
 
-	if (down_interruptible(&rpadlpar_sem))
+	if (mutex_lock_interruptible(&rpadlpar_mutex))
 		return -ERESTARTSYS;
 
 	dn = find_dlpar_node(drc_name, &node_type);
@@ -439,7 +439,7 @@
 	}
 	printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name);
 exit:
-	up(&rpadlpar_sem);
+	mutex_unlock(&rpadlpar_mutex);
 	return rc;
 }
 
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index c402da8..8cb9abd 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -15,6 +15,7 @@
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/types.h>
+#include <linux/mutex.h>
 
 #include <asm/sn/addrs.h>
 #include <asm/sn/l1.h>
@@ -81,7 +82,7 @@
 	.get_power_status       = get_power_status,
 };
 
-static DECLARE_MUTEX(sn_hotplug_sem);
+static DEFINE_MUTEX(sn_hotplug_mutex);
 
 static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot,
 	       		  char *buf)
@@ -346,7 +347,7 @@
 	int rc;
 
 	/* Serialize the Linux PCI infrastructure */
-	down(&sn_hotplug_sem);
+	mutex_lock(&sn_hotplug_mutex);
 
 	/*
 	 * Power-on and initialize the slot in the SN
@@ -354,7 +355,7 @@
 	 */
 	rc = sn_slot_enable(bss_hotplug_slot, slot->device_num);
 	if (rc) {
-		up(&sn_hotplug_sem);
+		mutex_unlock(&sn_hotplug_mutex);
 		return rc;
 	}
 
@@ -362,7 +363,7 @@
 				  PCI_DEVFN(slot->device_num + 1, 0));
 	if (!num_funcs) {
 		dev_dbg(slot->pci_bus->self, "no device in slot\n");
-		up(&sn_hotplug_sem);
+		mutex_unlock(&sn_hotplug_mutex);
 		return -ENODEV;
 	}
 
@@ -402,7 +403,7 @@
 	if (new_ppb)
 		pci_bus_add_devices(new_bus);
 
-	up(&sn_hotplug_sem);
+	mutex_unlock(&sn_hotplug_mutex);
 
 	if (rc == 0)
 		dev_dbg(slot->pci_bus->self,
@@ -422,7 +423,7 @@
 	int rc;
 
 	/* Acquire update access to the bus */
-	down(&sn_hotplug_sem);
+	mutex_lock(&sn_hotplug_mutex);
 
 	/* is it okay to bring this slot down? */
 	rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
@@ -450,7 +451,7 @@
 			     PCI_REQ_SLOT_DISABLE);
  leaving:
 	/* Release the bus lock */
-	up(&sn_hotplug_sem);
+	mutex_unlock(&sn_hotplug_mutex);
 
 	return rc;
 }
@@ -462,9 +463,9 @@
 	struct pcibus_info *pcibus_info;
 
 	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
-	down(&sn_hotplug_sem);
+	mutex_lock(&sn_hotplug_mutex);
 	*value = pcibus_info->pbi_enabled_devices & (1 << slot->device_num);
-	up(&sn_hotplug_sem);
+	mutex_unlock(&sn_hotplug_mutex);
 	return 0;
 }
 
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
index 0574efd..459e6e1 100644
--- a/drivers/pcmcia/vrc4171_card.c
+++ b/drivers/pcmcia/vrc4171_card.c
@@ -634,7 +634,7 @@
 static int __devinit vrc4171_card_setup(char *options)
 {
 	if (options == NULL || *options == '\0')
-		return 0;
+		return 1;
 
 	if (strncmp(options, "irq:", 4) == 0) {
 		int irq;
@@ -644,7 +644,7 @@
 			vrc4171_irq = irq;
 
 		if (*options != ',')
-			return 0;
+			return 1;
 		options++;
 	}
 
@@ -663,10 +663,10 @@
 			}
 
 			if (*options != ',')
-				return 0;
+				return 1;
 			options++;
 		} else
-			return 0;
+			return 1;
 
 	}
 
@@ -688,7 +688,7 @@
 			}
 
 			if (*options != ',')
-				return 0;
+				return 1;
 			options++;
 
 			if (strncmp(options, "memnoprobe", 10) == 0)
@@ -700,7 +700,7 @@
 		}
 	}
 
-	return 0;
+	return 1;
 }
 
 __setup("vrc4171_card=", vrc4171_card_setup);
diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c
index 57f38db..6004196 100644
--- a/drivers/pcmcia/vrc4173_cardu.c
+++ b/drivers/pcmcia/vrc4173_cardu.c
@@ -516,7 +516,7 @@
 static int __devinit vrc4173_cardu_setup(char *options)
 {
 	if (options == NULL || *options == '\0')
-		return 0;
+		return 1;
 
 	if (strncmp(options, "cardu1:", 7) == 0) {
 		options += 7;
@@ -527,9 +527,9 @@
 			}
 
 			if (*options != ',')
-				return 0;
+				return 1;
 		} else
-			return 0;
+			return 1;
 	}
 
 	if (strncmp(options, "cardu2:", 7) == 0) {
@@ -538,7 +538,7 @@
 			cardu_sockets[CARDU2].noprobe = 1;
 	}
 
-	return 0;
+	return 1;
 }
 
 __setup("vrc4173_cardu=", vrc4173_cardu_setup);
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index b68eef2..bb19c64 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -47,7 +47,7 @@
 {
 	dev->card_link = NULL;
 }
- 
+
 static void card_remove_first(struct pnp_dev * dev)
 {
 	struct pnp_card_driver * drv = to_pnp_card_driver(dev->driver);
@@ -361,7 +361,7 @@
 
 int pnp_register_card_driver(struct pnp_card_driver * drv)
 {
-	int count;
+	int error;
 	struct list_head *pos, *temp;
 
 	drv->link.name = drv->name;
@@ -372,21 +372,19 @@
 	drv->link.suspend = drv->suspend ? card_suspend : NULL;
 	drv->link.resume = drv->resume ? card_resume : NULL;
 
-	count = pnp_register_driver(&drv->link);
-	if (count < 0)
-		return count;
+	error = pnp_register_driver(&drv->link);
+	if (error < 0)
+		return error;
 
 	spin_lock(&pnp_lock);
 	list_add_tail(&drv->global_list, &pnp_card_drivers);
 	spin_unlock(&pnp_lock);
 
-	count = 0;
-
 	list_for_each_safe(pos,temp,&pnp_cards){
 		struct pnp_card *card = list_entry(pos, struct pnp_card, global_list);
-		count += card_probe(card,drv);
+		card_probe(card,drv);
 	}
-	return count;
+	return 0;
 }
 
 /**
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index 7cafacd..e54c153 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -201,31 +201,14 @@
 	.resume = pnp_bus_resume,
 };
 
-
-static int count_devices(struct device * dev, void * c)
-{
-	int * count = c;
-	(*count)++;
-	return 0;
-}
-
 int pnp_register_driver(struct pnp_driver *drv)
 {
-	int count;
-
 	pnp_dbg("the driver '%s' has been registered", drv->name);
 
 	drv->driver.name = drv->name;
 	drv->driver.bus = &pnp_bus_type;
 
-	count = driver_register(&drv->driver);
-
-	/* get the number of initial matches */
-	if (count >= 0){
-		count = 0;
-		driver_for_each_device(&drv->driver, NULL, &count, count_devices);
-	}
-	return count;
+	return driver_register(&drv->driver);
 }
 
 void pnp_unregister_driver(struct pnp_driver *drv)
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index b1b4b68..ac7c2bb 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -42,6 +42,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/isapnp.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 #if 0
@@ -92,7 +93,7 @@
 #define _LTAG_FIXEDMEM32RANGE	0x86
 
 static unsigned char isapnp_checksum_value;
-static DECLARE_MUTEX(isapnp_cfg_mutex);
+static DEFINE_MUTEX(isapnp_cfg_mutex);
 static int isapnp_detected;
 static int isapnp_csn_count;
 
@@ -903,7 +904,7 @@
 {
 	if (csn < 1 || csn > isapnp_csn_count || logdev > 10)
 		return -EINVAL;
-	down(&isapnp_cfg_mutex);
+	mutex_lock(&isapnp_cfg_mutex);
 	isapnp_wait();
 	isapnp_key();
 	isapnp_wake(csn);
@@ -929,7 +930,7 @@
 int isapnp_cfg_end(void)
 {
 	isapnp_wait();
-	up(&isapnp_cfg_mutex);
+	mutex_unlock(&isapnp_cfg_mutex);
 	return 0;
 }
 
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
new file mode 100644
index 0000000..929dd80
--- /dev/null
+++ b/drivers/rtc/Kconfig
@@ -0,0 +1,165 @@
+\#
+# RTC class/drivers configuration
+#
+
+menu "Real Time Clock"
+
+config RTC_LIB
+	tristate
+
+config RTC_CLASS
+	tristate "RTC class"
+	depends on EXPERIMENTAL
+	default n
+	select RTC_LIB
+	help
+	  Generic RTC class support. If you say yes here, you will
+ 	  be allowed to plug one or more RTCs to your system. You will
+	  probably want to enable one of more of the interfaces below.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-class.
+
+config RTC_HCTOSYS
+	bool "Set system time from RTC on startup"
+	depends on RTC_CLASS = y
+	default y
+	help
+	  If you say yes here, the system time will be set using
+	  the value read from the specified RTC device. This is useful
+	  in order to avoid unnecessary fschk runs.
+
+config RTC_HCTOSYS_DEVICE
+	string "The RTC to read the time from"
+	depends on RTC_HCTOSYS = y
+	default "rtc0"
+	help
+	  The RTC device that will be used as the source for
+	  the system time, usually rtc0.
+
+comment "RTC interfaces"
+	depends on RTC_CLASS
+
+config RTC_INTF_SYSFS
+	tristate "sysfs"
+	depends on RTC_CLASS && SYSFS
+	default RTC_CLASS
+	help
+	  Say yes here if you want to use your RTC using the sysfs
+	  interface, /sys/class/rtc/rtcX .
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-sysfs.
+
+config RTC_INTF_PROC
+	tristate "proc"
+	depends on RTC_CLASS && PROC_FS
+	default RTC_CLASS
+	help
+	  Say yes here if you want to use your RTC using the proc
+	  interface, /proc/driver/rtc .
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-proc.
+
+config RTC_INTF_DEV
+	tristate "dev"
+	depends on RTC_CLASS
+	default RTC_CLASS
+	help
+	  Say yes here if you want to use your RTC using the dev
+	  interface, /dev/rtc .
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-dev.
+
+comment "RTC drivers"
+	depends on RTC_CLASS
+
+config RTC_DRV_X1205
+	tristate "Xicor/Intersil X1205"
+	depends on RTC_CLASS && I2C
+	help
+	  If you say yes here you get support for the
+	  Xicor/Intersil X1205 RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-x1205.
+
+config RTC_DRV_DS1672
+	tristate "Dallas/Maxim DS1672"
+	depends on RTC_CLASS && I2C
+	help
+	  If you say yes here you get support for the
+	  Dallas/Maxim DS1672 timekeeping chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-ds1672.
+
+config RTC_DRV_PCF8563
+	tristate "Philips PCF8563/Epson RTC8564"
+	depends on RTC_CLASS && I2C
+	help
+	  If you say yes here you get support for the
+	  Philips PCF8563 RTC chip. The Epson RTC8564
+	  should work as well.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-pcf8563.
+
+config RTC_DRV_RS5C372
+	tristate "Ricoh RS5C372A/B"
+	depends on RTC_CLASS && I2C
+	help
+	  If you say yes here you get support for the
+	  Ricoh RS5C372A and RS5C372B RTC chips.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-rs5c372.
+
+config RTC_DRV_M48T86
+	tristate "ST M48T86/Dallas DS12887"
+	depends on RTC_CLASS
+	help
+	  If you say Y here you will get support for the
+	  ST M48T86 and Dallas DS12887 RTC chips.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-m48t86.
+
+config RTC_DRV_EP93XX
+	tristate "Cirrus Logic EP93XX"
+	depends on RTC_CLASS && ARCH_EP93XX
+	help
+	  If you say yes here you get support for the
+	  RTC embedded in the Cirrus Logic EP93XX processors.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-ep93xx.
+
+config RTC_DRV_SA1100
+	tristate "SA11x0/PXA2xx"
+	depends on RTC_CLASS && (ARCH_SA1100 || ARCH_PXA)
+	help
+	  If you say Y here you will get access to the real time clock
+	  built into your SA11x0 or PXA2xx CPU.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rtc-sa1100.
+
+config RTC_DRV_TEST
+	tristate "Test driver/device"
+	depends on RTC_CLASS
+	help
+	  If you say yes here you get support for the
+	  RTC test driver. It's a software RTC which can be
+	  used to test the RTC subsystem APIs. It gets
+	  the time from the system clock.
+	  You want this driver only if you are doing development
+	  on the RTC subsystem. Please read the source code
+	  for further details.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-test.
+
+endmenu
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
new file mode 100644
index 0000000..8d4c7fe
--- /dev/null
+++ b/drivers/rtc/Makefile
@@ -0,0 +1,21 @@
+#
+# Makefile for RTC class/drivers.
+#
+
+obj-$(CONFIG_RTC_LIB)		+= rtc-lib.o
+obj-$(CONFIG_RTC_HCTOSYS)	+= hctosys.o
+obj-$(CONFIG_RTC_CLASS)		+= rtc-core.o
+rtc-core-y			:= class.o interface.o
+
+obj-$(CONFIG_RTC_INTF_SYSFS)	+= rtc-sysfs.o
+obj-$(CONFIG_RTC_INTF_PROC)	+= rtc-proc.o
+obj-$(CONFIG_RTC_INTF_DEV)	+= rtc-dev.o
+
+obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205.o
+obj-$(CONFIG_RTC_DRV_TEST)	+= rtc-test.o
+obj-$(CONFIG_RTC_DRV_DS1672)	+= rtc-ds1672.o
+obj-$(CONFIG_RTC_DRV_PCF8563)	+= rtc-pcf8563.o
+obj-$(CONFIG_RTC_DRV_RS5C372)	+= rtc-rs5c372.o
+obj-$(CONFIG_RTC_DRV_M48T86)	+= rtc-m48t86.o
+obj-$(CONFIG_RTC_DRV_EP93XX)	+= rtc-ep93xx.o
+obj-$(CONFIG_RTC_DRV_SA1100)	+= rtc-sa1100.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
new file mode 100644
index 0000000..8533936
--- /dev/null
+++ b/drivers/rtc/class.c
@@ -0,0 +1,145 @@
+/*
+ * RTC subsystem, base class
+ *
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * class skeleton from drivers/hwmon/hwmon.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/kdev_t.h>
+#include <linux/idr.h>
+
+static DEFINE_IDR(rtc_idr);
+static DEFINE_MUTEX(idr_lock);
+struct class *rtc_class;
+
+static void rtc_device_release(struct class_device *class_dev)
+{
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+	mutex_lock(&idr_lock);
+	idr_remove(&rtc_idr, rtc->id);
+	mutex_unlock(&idr_lock);
+	kfree(rtc);
+}
+
+/**
+ * rtc_device_register - register w/ RTC class
+ * @dev: the device to register
+ *
+ * rtc_device_unregister() must be called when the class device is no
+ * longer needed.
+ *
+ * Returns the pointer to the new struct class device.
+ */
+struct rtc_device *rtc_device_register(const char *name, struct device *dev,
+					struct rtc_class_ops *ops,
+					struct module *owner)
+{
+	struct rtc_device *rtc;
+	int id, err;
+
+	if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+
+	mutex_lock(&idr_lock);
+	err = idr_get_new(&rtc_idr, NULL, &id);
+	mutex_unlock(&idr_lock);
+
+	if (err < 0)
+		goto exit;
+
+	id = id & MAX_ID_MASK;
+
+	rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
+	if (rtc == NULL) {
+		err = -ENOMEM;
+		goto exit_idr;
+	}
+
+	rtc->id = id;
+	rtc->ops = ops;
+	rtc->owner = owner;
+	rtc->class_dev.dev = dev;
+	rtc->class_dev.class = rtc_class;
+	rtc->class_dev.release = rtc_device_release;
+
+	mutex_init(&rtc->ops_lock);
+	spin_lock_init(&rtc->irq_lock);
+	spin_lock_init(&rtc->irq_task_lock);
+
+	strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
+	snprintf(rtc->class_dev.class_id, BUS_ID_SIZE, "rtc%d", id);
+
+	err = class_device_register(&rtc->class_dev);
+	if (err)
+		goto exit_kfree;
+
+	dev_info(dev, "rtc core: registered %s as %s\n",
+			rtc->name, rtc->class_dev.class_id);
+
+	return rtc;
+
+exit_kfree:
+	kfree(rtc);
+
+exit_idr:
+	idr_remove(&rtc_idr, id);
+
+exit:
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(rtc_device_register);
+
+
+/**
+ * rtc_device_unregister - removes the previously registered RTC class device
+ *
+ * @rtc: the RTC class device to destroy
+ */
+void rtc_device_unregister(struct rtc_device *rtc)
+{
+	mutex_lock(&rtc->ops_lock);
+	rtc->ops = NULL;
+	mutex_unlock(&rtc->ops_lock);
+	class_device_unregister(&rtc->class_dev);
+}
+EXPORT_SYMBOL_GPL(rtc_device_unregister);
+
+int rtc_interface_register(struct class_interface *intf)
+{
+	intf->class = rtc_class;
+	return class_interface_register(intf);
+}
+EXPORT_SYMBOL_GPL(rtc_interface_register);
+
+static int __init rtc_init(void)
+{
+	rtc_class = class_create(THIS_MODULE, "rtc");
+	if (IS_ERR(rtc_class)) {
+		printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
+		return PTR_ERR(rtc_class);
+	}
+	return 0;
+}
+
+static void __exit rtc_exit(void)
+{
+	class_destroy(rtc_class);
+}
+
+module_init(rtc_init);
+module_exit(rtc_exit);
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towerteh.it>");
+MODULE_DESCRIPTION("RTC class support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
new file mode 100644
index 0000000..d02fe9a
--- /dev/null
+++ b/drivers/rtc/hctosys.c
@@ -0,0 +1,69 @@
+/*
+ * RTC subsystem, initialize system time on startup
+ *
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * 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/rtc.h>
+
+/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
+ * whether it stores the most close value or the value with partial
+ * seconds truncated. However, it is important that we use it to store
+ * the truncated value. This is because otherwise it is necessary,
+ * in an rtc sync function, to read both xtime.tv_sec and
+ * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
+ * of >32bits is not possible. So storing the most close value would
+ * slow down the sync API. So here we have the truncated value and
+ * the best guess is to add 0.5s.
+ */
+
+static int __init rtc_hctosys(void)
+{
+	int err;
+	struct rtc_time tm;
+	struct class_device *class_dev = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+
+	if (class_dev == NULL) {
+		printk("%s: unable to open rtc device (%s)\n",
+			__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+		return -ENODEV;
+	}
+
+	err = rtc_read_time(class_dev, &tm);
+	if (err == 0) {
+		err = rtc_valid_tm(&tm);
+		if (err == 0) {
+			struct timespec tv;
+
+			tv.tv_nsec = NSEC_PER_SEC >> 1;
+
+			rtc_tm_to_time(&tm, &tv.tv_sec);
+
+			do_settimeofday(&tv);
+
+			dev_info(class_dev->dev,
+				"setting the system clock to "
+				"%d-%02d-%02d %02d:%02d:%02d (%u)\n",
+				tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+				tm.tm_hour, tm.tm_min, tm.tm_sec,
+				(unsigned int) tv.tv_sec);
+		}
+		else
+			dev_err(class_dev->dev,
+				"hctosys: invalid date/time\n");
+	}
+	else
+		dev_err(class_dev->dev,
+			"hctosys: unable to read the hardware clock\n");
+
+	rtc_class_close(class_dev);
+
+	return 0;
+}
+
+late_initcall(rtc_hctosys);
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
new file mode 100644
index 0000000..56e4907
--- /dev/null
+++ b/drivers/rtc/interface.c
@@ -0,0 +1,277 @@
+/*
+ * RTC subsystem, interface functions
+ *
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on arch/arm/common/rtctime.c
+ *
+ * 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/rtc.h>
+
+int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm)
+{
+	int err;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	err = mutex_lock_interruptible(&rtc->ops_lock);
+	if (err)
+		return -EBUSY;
+
+	if (!rtc->ops)
+		err = -ENODEV;
+	else if (!rtc->ops->read_time)
+		err = -EINVAL;
+	else {
+		memset(tm, 0, sizeof(struct rtc_time));
+		err = rtc->ops->read_time(class_dev->dev, tm);
+	}
+
+	mutex_unlock(&rtc->ops_lock);
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtc_read_time);
+
+int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm)
+{
+	int err;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	err = rtc_valid_tm(tm);
+	if (err != 0)
+		return err;
+
+	err = mutex_lock_interruptible(&rtc->ops_lock);
+	if (err)
+		return -EBUSY;
+
+	if (!rtc->ops)
+		err = -ENODEV;
+	else if (!rtc->ops->set_time)
+		err = -EINVAL;
+	else
+		err = rtc->ops->set_time(class_dev->dev, tm);
+
+	mutex_unlock(&rtc->ops_lock);
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtc_set_time);
+
+int rtc_set_mmss(struct class_device *class_dev, unsigned long secs)
+{
+	int err;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	err = mutex_lock_interruptible(&rtc->ops_lock);
+	if (err)
+		return -EBUSY;
+
+	if (!rtc->ops)
+		err = -ENODEV;
+	else if (rtc->ops->set_mmss)
+		err = rtc->ops->set_mmss(class_dev->dev, secs);
+	else if (rtc->ops->read_time && rtc->ops->set_time) {
+		struct rtc_time new, old;
+
+		err = rtc->ops->read_time(class_dev->dev, &old);
+		if (err == 0) {
+			rtc_time_to_tm(secs, &new);
+
+			/*
+			 * avoid writing when we're going to change the day of
+			 * the month. We will retry in the next minute. This
+			 * basically means that if the RTC must not drift
+			 * by more than 1 minute in 11 minutes.
+			 */
+			if (!((old.tm_hour == 23 && old.tm_min == 59) ||
+				(new.tm_hour == 23 && new.tm_min == 59)))
+				err = rtc->ops->set_time(class_dev->dev, &new);
+		}
+	}
+	else
+		err = -EINVAL;
+
+	mutex_unlock(&rtc->ops_lock);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtc_set_mmss);
+
+int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
+{
+	int err;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	err = mutex_lock_interruptible(&rtc->ops_lock);
+	if (err)
+		return -EBUSY;
+
+	if (rtc->ops == NULL)
+		err = -ENODEV;
+	else if (!rtc->ops->read_alarm)
+		err = -EINVAL;
+	else {
+		memset(alarm, 0, sizeof(struct rtc_wkalrm));
+		err = rtc->ops->read_alarm(class_dev->dev, alarm);
+	}
+
+	mutex_unlock(&rtc->ops_lock);
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtc_read_alarm);
+
+int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
+{
+	int err;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	err = mutex_lock_interruptible(&rtc->ops_lock);
+	if (err)
+		return -EBUSY;
+
+	if (!rtc->ops)
+		err = -ENODEV;
+	else if (!rtc->ops->set_alarm)
+		err = -EINVAL;
+	else
+		err = rtc->ops->set_alarm(class_dev->dev, alarm);
+
+	mutex_unlock(&rtc->ops_lock);
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtc_set_alarm);
+
+void rtc_update_irq(struct class_device *class_dev,
+		unsigned long num, unsigned long events)
+{
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	spin_lock(&rtc->irq_lock);
+	rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
+	spin_unlock(&rtc->irq_lock);
+
+	spin_lock(&rtc->irq_task_lock);
+	if (rtc->irq_task)
+		rtc->irq_task->func(rtc->irq_task->private_data);
+	spin_unlock(&rtc->irq_task_lock);
+
+	wake_up_interruptible(&rtc->irq_queue);
+	kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
+}
+EXPORT_SYMBOL_GPL(rtc_update_irq);
+
+struct class_device *rtc_class_open(char *name)
+{
+	struct class_device *class_dev = NULL,
+				*class_dev_tmp;
+
+	down(&rtc_class->sem);
+	list_for_each_entry(class_dev_tmp, &rtc_class->children, node) {
+		if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) {
+			class_dev = class_dev_tmp;
+			break;
+		}
+	}
+
+	if (class_dev) {
+		if (!try_module_get(to_rtc_device(class_dev)->owner))
+			class_dev = NULL;
+	}
+	up(&rtc_class->sem);
+
+	return class_dev;
+}
+EXPORT_SYMBOL_GPL(rtc_class_open);
+
+void rtc_class_close(struct class_device *class_dev)
+{
+	module_put(to_rtc_device(class_dev)->owner);
+}
+EXPORT_SYMBOL_GPL(rtc_class_close);
+
+int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task)
+{
+	int retval = -EBUSY;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	if (task == NULL || task->func == NULL)
+		return -EINVAL;
+
+	spin_lock(&rtc->irq_task_lock);
+	if (rtc->irq_task == NULL) {
+		rtc->irq_task = task;
+		retval = 0;
+	}
+	spin_unlock(&rtc->irq_task_lock);
+
+	return retval;
+}
+EXPORT_SYMBOL_GPL(rtc_irq_register);
+
+void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task)
+{
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	spin_lock(&rtc->irq_task_lock);
+	if (rtc->irq_task == task)
+		rtc->irq_task = NULL;
+	spin_unlock(&rtc->irq_task_lock);
+}
+EXPORT_SYMBOL_GPL(rtc_irq_unregister);
+
+int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int enabled)
+{
+	int err = 0;
+	unsigned long flags;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	spin_lock_irqsave(&rtc->irq_task_lock, flags);
+	if (rtc->irq_task != task)
+		err = -ENXIO;
+	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
+
+	if (err == 0)
+		err = rtc->ops->irq_set_state(class_dev->dev, enabled);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtc_irq_set_state);
+
+int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq)
+{
+	int err = 0, tmp = 0;
+	unsigned long flags;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	/* allowed range is 2-8192 */
+	if (freq < 2 || freq > 8192)
+		return -EINVAL;
+/*
+	FIXME: this does not belong here, will move where appropriate
+	at a later stage. It cannot hurt right now, trust me :)
+	if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE)))
+		return -EACCES;
+*/
+	/* check if freq is a power of 2 */
+	while (freq > (1 << tmp))
+		tmp++;
+
+	if (freq != (1 << tmp))
+		return -EINVAL;
+
+	spin_lock_irqsave(&rtc->irq_task_lock, flags);
+	if (rtc->irq_task != task)
+		err = -ENXIO;
+	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
+
+	if (err == 0) {
+		err = rtc->ops->irq_set_freq(class_dev->dev, freq);
+		if (err == 0)
+			rtc->irq_freq = freq;
+	}
+	return err;
+}
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
new file mode 100644
index 0000000..b1e3e61
--- /dev/null
+++ b/drivers/rtc/rtc-dev.c
@@ -0,0 +1,382 @@
+/*
+ * RTC subsystem, dev interface
+ *
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on arch/arm/common/rtctime.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+
+static struct class *rtc_dev_class;
+static dev_t rtc_devt;
+
+#define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */
+
+static int rtc_dev_open(struct inode *inode, struct file *file)
+{
+	int err;
+	struct rtc_device *rtc = container_of(inode->i_cdev,
+					struct rtc_device, char_dev);
+	struct rtc_class_ops *ops = rtc->ops;
+
+	/* We keep the lock as long as the device is in use
+	 * and return immediately if busy
+	 */
+	if (!(mutex_trylock(&rtc->char_lock)))
+		return -EBUSY;
+
+	file->private_data = &rtc->class_dev;
+
+	err = ops->open ? ops->open(rtc->class_dev.dev) : 0;
+	if (err == 0) {
+		spin_lock_irq(&rtc->irq_lock);
+		rtc->irq_data = 0;
+		spin_unlock_irq(&rtc->irq_lock);
+
+		return 0;
+	}
+
+	/* something has gone wrong, release the lock */
+	mutex_unlock(&rtc->char_lock);
+	return err;
+}
+
+
+static ssize_t
+rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+	struct rtc_device *rtc = to_rtc_device(file->private_data);
+
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long data;
+	ssize_t ret;
+
+	if (count < sizeof(unsigned long))
+		return -EINVAL;
+
+	add_wait_queue(&rtc->irq_queue, &wait);
+	do {
+		__set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irq(&rtc->irq_lock);
+		data = rtc->irq_data;
+		rtc->irq_data = 0;
+		spin_unlock_irq(&rtc->irq_lock);
+
+		if (data != 0) {
+			ret = 0;
+			break;
+		}
+		if (file->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			break;
+		}
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	} while (1);
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&rtc->irq_queue, &wait);
+
+	if (ret == 0) {
+		/* Check for any data updates */
+		if (rtc->ops->read_callback)
+			data = rtc->ops->read_callback(rtc->class_dev.dev, data);
+
+		ret = put_user(data, (unsigned long __user *)buf);
+		if (ret == 0)
+			ret = sizeof(unsigned long);
+	}
+	return ret;
+}
+
+static unsigned int rtc_dev_poll(struct file *file, poll_table *wait)
+{
+	struct rtc_device *rtc = to_rtc_device(file->private_data);
+	unsigned long data;
+
+	poll_wait(file, &rtc->irq_queue, wait);
+
+	data = rtc->irq_data;
+
+	return (data != 0) ? (POLLIN | POLLRDNORM) : 0;
+}
+
+static int rtc_dev_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	struct class_device *class_dev = file->private_data;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+	struct rtc_class_ops *ops = rtc->ops;
+	struct rtc_time tm;
+	struct rtc_wkalrm alarm;
+	void __user *uarg = (void __user *) arg;
+
+	/* avoid conflicting IRQ users */
+	if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) {
+		spin_lock(&rtc->irq_task_lock);
+		if (rtc->irq_task)
+			err = -EBUSY;
+		spin_unlock(&rtc->irq_task_lock);
+
+		if (err < 0)
+			return err;
+	}
+
+	/* try the driver's ioctl interface */
+	if (ops->ioctl) {
+		err = ops->ioctl(class_dev->dev, cmd, arg);
+		if (err != -EINVAL)
+			return err;
+	}
+
+	/* if the driver does not provide the ioctl interface
+	 * or if that particular ioctl was not implemented
+	 * (-EINVAL), we will try to emulate here.
+	 */
+
+	switch (cmd) {
+	case RTC_ALM_READ:
+		err = rtc_read_alarm(class_dev, &alarm);
+		if (err < 0)
+			return err;
+
+		if (copy_to_user(uarg, &alarm.time, sizeof(tm)))
+			return -EFAULT;
+		break;
+
+	case RTC_ALM_SET:
+		if (copy_from_user(&alarm.time, uarg, sizeof(tm)))
+			return -EFAULT;
+
+		alarm.enabled = 0;
+		alarm.pending = 0;
+		alarm.time.tm_mday = -1;
+		alarm.time.tm_mon = -1;
+		alarm.time.tm_year = -1;
+		alarm.time.tm_wday = -1;
+		alarm.time.tm_yday = -1;
+		alarm.time.tm_isdst = -1;
+		err = rtc_set_alarm(class_dev, &alarm);
+		break;
+
+	case RTC_RD_TIME:
+		err = rtc_read_time(class_dev, &tm);
+		if (err < 0)
+			return err;
+
+		if (copy_to_user(uarg, &tm, sizeof(tm)))
+			return -EFAULT;
+		break;
+
+	case RTC_SET_TIME:
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		if (copy_from_user(&tm, uarg, sizeof(tm)))
+			return -EFAULT;
+
+		err = rtc_set_time(class_dev, &tm);
+		break;
+#if 0
+	case RTC_EPOCH_SET:
+#ifndef rtc_epoch
+		/*
+		 * There were no RTC clocks before 1900.
+		 */
+		if (arg < 1900) {
+			err = -EINVAL;
+			break;
+		}
+		if (!capable(CAP_SYS_TIME)) {
+			err = -EACCES;
+			break;
+		}
+		rtc_epoch = arg;
+		err = 0;
+#endif
+		break;
+
+	case RTC_EPOCH_READ:
+		err = put_user(rtc_epoch, (unsigned long __user *)uarg);
+		break;
+#endif
+	case RTC_WKALM_SET:
+		if (copy_from_user(&alarm, uarg, sizeof(alarm)))
+			return -EFAULT;
+
+		err = rtc_set_alarm(class_dev, &alarm);
+		break;
+
+	case RTC_WKALM_RD:
+		err = rtc_read_alarm(class_dev, &alarm);
+		if (err < 0)
+			return err;
+
+		if (copy_to_user(uarg, &alarm, sizeof(alarm)))
+			return -EFAULT;
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static int rtc_dev_release(struct inode *inode, struct file *file)
+{
+	struct rtc_device *rtc = to_rtc_device(file->private_data);
+
+	if (rtc->ops->release)
+		rtc->ops->release(rtc->class_dev.dev);
+
+	mutex_unlock(&rtc->char_lock);
+	return 0;
+}
+
+static int rtc_dev_fasync(int fd, struct file *file, int on)
+{
+	struct rtc_device *rtc = to_rtc_device(file->private_data);
+	return fasync_helper(fd, file, on, &rtc->async_queue);
+}
+
+static struct file_operations rtc_dev_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= rtc_dev_read,
+	.poll		= rtc_dev_poll,
+	.ioctl		= rtc_dev_ioctl,
+	.open		= rtc_dev_open,
+	.release	= rtc_dev_release,
+	.fasync		= rtc_dev_fasync,
+};
+
+/* insertion/removal hooks */
+
+static int rtc_dev_add_device(struct class_device *class_dev,
+				struct class_interface *class_intf)
+{
+	int err = 0;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	if (rtc->id >= RTC_DEV_MAX) {
+		dev_err(class_dev->dev, "too many RTCs\n");
+		return -EINVAL;
+	}
+
+	mutex_init(&rtc->char_lock);
+	spin_lock_init(&rtc->irq_lock);
+	init_waitqueue_head(&rtc->irq_queue);
+
+	cdev_init(&rtc->char_dev, &rtc_dev_fops);
+	rtc->char_dev.owner = rtc->owner;
+
+	if (cdev_add(&rtc->char_dev, MKDEV(MAJOR(rtc_devt), rtc->id), 1)) {
+		cdev_del(&rtc->char_dev);
+		dev_err(class_dev->dev,
+			"failed to add char device %d:%d\n",
+			MAJOR(rtc_devt), rtc->id);
+		return -ENODEV;
+	}
+
+	rtc->rtc_dev = class_device_create(rtc_dev_class, NULL,
+						MKDEV(MAJOR(rtc_devt), rtc->id),
+						class_dev->dev, "rtc%d", rtc->id);
+	if (IS_ERR(rtc->rtc_dev)) {
+		dev_err(class_dev->dev, "cannot create rtc_dev device\n");
+		err = PTR_ERR(rtc->rtc_dev);
+		goto err_cdev_del;
+	}
+
+	dev_info(class_dev->dev, "rtc intf: dev (%d:%d)\n",
+		MAJOR(rtc->rtc_dev->devt),
+		MINOR(rtc->rtc_dev->devt));
+
+	return 0;
+
+err_cdev_del:
+
+	cdev_del(&rtc->char_dev);
+	return err;
+}
+
+static void rtc_dev_remove_device(struct class_device *class_dev,
+					struct class_interface *class_intf)
+{
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	if (rtc->rtc_dev) {
+		dev_dbg(class_dev->dev, "removing char %d:%d\n",
+			MAJOR(rtc->rtc_dev->devt),
+			MINOR(rtc->rtc_dev->devt));
+
+		class_device_unregister(rtc->rtc_dev);
+		cdev_del(&rtc->char_dev);
+	}
+}
+
+/* interface registration */
+
+static struct class_interface rtc_dev_interface = {
+	.add = &rtc_dev_add_device,
+	.remove = &rtc_dev_remove_device,
+};
+
+static int __init rtc_dev_init(void)
+{
+	int err;
+
+	rtc_dev_class = class_create(THIS_MODULE, "rtc-dev");
+	if (IS_ERR(rtc_dev_class))
+		return PTR_ERR(rtc_dev_class);
+
+	err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
+	if (err < 0) {
+		printk(KERN_ERR "%s: failed to allocate char dev region\n",
+			__FILE__);
+		goto err_destroy_class;
+	}
+
+	err = rtc_interface_register(&rtc_dev_interface);
+	if (err < 0) {
+		printk(KERN_ERR "%s: failed to register the interface\n",
+			__FILE__);
+		goto err_unregister_chrdev;
+	}
+
+	return 0;
+
+err_unregister_chrdev:
+	unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
+
+err_destroy_class:
+	class_destroy(rtc_dev_class);
+
+	return err;
+}
+
+static void __exit rtc_dev_exit(void)
+{
+	class_interface_unregister(&rtc_dev_interface);
+	class_destroy(rtc_dev_class);
+	unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
+}
+
+module_init(rtc_dev_init);
+module_exit(rtc_dev_exit);
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("RTC class dev interface");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
new file mode 100644
index 0000000..358695a
--- /dev/null
+++ b/drivers/rtc/rtc-ds1672.c
@@ -0,0 +1,233 @@
+/*
+ * An rtc/i2c driver for the Dallas DS1672
+ * Copyright 2005 Alessandro Zummo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#define DRV_VERSION "0.2"
+
+/* Addresses to scan: none. This chip cannot be detected. */
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD;
+
+/* Registers */
+
+#define DS1672_REG_CNT_BASE	0
+#define DS1672_REG_CONTROL	4
+#define DS1672_REG_TRICKLE	5
+
+
+/* Prototypes */
+static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind);
+
+/*
+ * In the routines that deal directly with the ds1672 hardware, we use
+ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
+ * Epoch is initialized as 2000. Time is set to UTC.
+ */
+static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+	unsigned long time;
+	unsigned char addr = DS1672_REG_CNT_BASE;
+	unsigned char buf[4];
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 1, &addr },		/* setup read ptr */
+		{ client->addr, I2C_M_RD, 4, buf },	/* read date */
+	};
+
+	/* read date registers */
+	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	dev_dbg(&client->dev,
+		"%s: raw read data - counters=%02x,%02x,%02x,%02x\n"
+		__FUNCTION__,
+		buf[0], buf[1], buf[2], buf[3]);
+
+	time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+	rtc_time_to_tm(time, tm);
+
+	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	return 0;
+}
+
+static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs)
+{
+	int xfer;
+	unsigned char buf[5];
+
+	buf[0] = DS1672_REG_CNT_BASE;
+	buf[1] = secs & 0x000000FF;
+	buf[2] = (secs & 0x0000FF00) >> 8;
+	buf[3] = (secs & 0x00FF0000) >> 16;
+	buf[4] = (secs & 0xFF000000) >> 24;
+
+	xfer = i2c_master_send(client, buf, 5);
+	if (xfer != 5) {
+		dev_err(&client->dev, "%s: send: %d\n", __FUNCTION__, xfer);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+	unsigned long secs;
+
+	dev_dbg(&client->dev,
+		"%s: secs=%d, mins=%d, hours=%d, ",
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	rtc_tm_to_time(tm, &secs);
+
+	return ds1672_set_mmss(client, secs);
+}
+
+static int ds1672_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return ds1672_get_datetime(to_i2c_client(dev), tm);
+}
+
+static int ds1672_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return ds1672_set_datetime(to_i2c_client(dev), tm);
+}
+
+static int ds1672_rtc_set_mmss(struct device *dev, unsigned long secs)
+{
+	return ds1672_set_mmss(to_i2c_client(dev), secs);
+}
+
+static struct rtc_class_ops ds1672_rtc_ops = {
+	.read_time	= ds1672_rtc_read_time,
+	.set_time	= ds1672_rtc_set_time,
+	.set_mmss	= ds1672_rtc_set_mmss,
+};
+
+static int ds1672_attach(struct i2c_adapter *adapter)
+{
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+	return i2c_probe(adapter, &addr_data, ds1672_probe);
+}
+
+static int ds1672_detach(struct i2c_client *client)
+{
+	int err;
+	struct rtc_device *rtc = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "%s\n", __FUNCTION__);
+
+ 	if (rtc)
+		rtc_device_unregister(rtc);
+
+	if ((err = i2c_detach_client(client)))
+		return err;
+
+	kfree(client);
+
+	return 0;
+}
+
+static struct i2c_driver ds1672_driver = {
+	.driver		= {
+		.name	= "ds1672",
+	},
+	.id		= I2C_DRIVERID_DS1672,
+	.attach_adapter = &ds1672_attach,
+	.detach_client	= &ds1672_detach,
+};
+
+static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
+{
+	int err = 0;
+	struct i2c_client *client;
+	struct rtc_device *rtc;
+
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	/* I2C client */
+	client->addr = address;
+	client->driver = &ds1672_driver;
+	client->adapter	= adapter;
+
+	strlcpy(client->name, ds1672_driver.driver.name, I2C_NAME_SIZE);
+
+	/* Inform the i2c layer */
+	if ((err = i2c_attach_client(client)))
+		goto exit_kfree;
+
+	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+	rtc = rtc_device_register(ds1672_driver.driver.name, &client->dev,
+				&ds1672_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		err = PTR_ERR(rtc);
+		dev_err(&client->dev,
+			"unable to register the class device\n");
+		goto exit_detach;
+	}
+
+	i2c_set_clientdata(client, rtc);
+
+	return 0;
+
+exit_detach:
+	i2c_detach_client(client);
+
+exit_kfree:
+	kfree(client);
+
+exit:
+	return err;
+}
+
+static int __init ds1672_init(void)
+{
+	return i2c_add_driver(&ds1672_driver);
+}
+
+static void __exit ds1672_exit(void)
+{
+	i2c_del_driver(&ds1672_driver);
+}
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ds1672_init);
+module_exit(ds1672_exit);
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c
new file mode 100644
index 0000000..0dd80ea
--- /dev/null
+++ b/drivers/rtc/rtc-ep93xx.c
@@ -0,0 +1,162 @@
+/*
+ * A driver for the RTC embedded in the Cirrus Logic EP93XX processors
+ * Copyright (c) 2006 Tower Technologies
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <asm/hardware.h>
+
+#define EP93XX_RTC_REG(x)	(EP93XX_RTC_BASE + (x))
+#define EP93XX_RTC_DATA		EP93XX_RTC_REG(0x0000)
+#define EP93XX_RTC_LOAD		EP93XX_RTC_REG(0x000C)
+#define EP93XX_RTC_SWCOMP	EP93XX_RTC_REG(0x0108)
+
+#define DRV_VERSION "0.2"
+
+static int ep93xx_get_swcomp(struct device *dev, unsigned short *preload,
+				unsigned short *delete)
+{
+	unsigned short comp = __raw_readl(EP93XX_RTC_SWCOMP);
+
+	if (preload)
+		*preload = comp & 0xffff;
+
+	if (delete)
+		*delete = (comp >> 16) & 0x1f;
+
+	return 0;
+}
+
+static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	unsigned long time = __raw_readl(EP93XX_RTC_DATA);
+
+	rtc_time_to_tm(time, tm);
+	return 0;
+}
+
+static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs)
+{
+	__raw_writel(secs + 1, EP93XX_RTC_LOAD);
+	return 0;
+}
+
+static int ep93xx_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	int err;
+	unsigned long secs;
+
+	err = rtc_tm_to_time(tm, &secs);
+	if (err != 0)
+		return err;
+
+	return ep93xx_rtc_set_mmss(dev, secs);
+}
+
+static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	unsigned short preload, delete;
+
+	ep93xx_get_swcomp(dev, &preload, &delete);
+
+	seq_printf(seq, "24hr\t\t: yes\n");
+	seq_printf(seq, "preload\t\t: %d\n", preload);
+	seq_printf(seq, "delete\t\t: %d\n", delete);
+
+	return 0;
+}
+
+static struct rtc_class_ops ep93xx_rtc_ops = {
+	.read_time	= ep93xx_rtc_read_time,
+	.set_time	= ep93xx_rtc_set_time,
+	.set_mmss	= ep93xx_rtc_set_mmss,
+	.proc		= ep93xx_rtc_proc,
+};
+
+static ssize_t ep93xx_sysfs_show_comp_preload(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	unsigned short preload;
+
+	ep93xx_get_swcomp(dev, &preload, NULL);
+
+	return sprintf(buf, "%d\n", preload);
+}
+static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_sysfs_show_comp_preload, NULL);
+
+static ssize_t ep93xx_sysfs_show_comp_delete(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	unsigned short delete;
+
+	ep93xx_get_swcomp(dev, NULL, &delete);
+
+	return sprintf(buf, "%d\n", delete);
+}
+static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_sysfs_show_comp_delete, NULL);
+
+
+static int __devinit ep93xx_rtc_probe(struct platform_device *dev)
+{
+	struct rtc_device *rtc = rtc_device_register("ep93xx",
+				&dev->dev, &ep93xx_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		dev_err(&dev->dev, "unable to register\n");
+		return PTR_ERR(rtc);
+	}
+
+	platform_set_drvdata(dev, rtc);
+
+	device_create_file(&dev->dev, &dev_attr_comp_preload);
+	device_create_file(&dev->dev, &dev_attr_comp_delete);
+
+	return 0;
+}
+
+static int __devexit ep93xx_rtc_remove(struct platform_device *dev)
+{
+	struct rtc_device *rtc = platform_get_drvdata(dev);
+
+ 	if (rtc)
+		rtc_device_unregister(rtc);
+
+	platform_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver ep93xx_rtc_platform_driver = {
+	.driver		= {
+		.name	= "ep93xx-rtc",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ep93xx_rtc_probe,
+	.remove		= __devexit_p(ep93xx_rtc_remove),
+};
+
+static int __init ep93xx_rtc_init(void)
+{
+	return platform_driver_register(&ep93xx_rtc_platform_driver);
+}
+
+static void __exit ep93xx_rtc_exit(void)
+{
+	platform_driver_unregister(&ep93xx_rtc_platform_driver);
+}
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("EP93XX RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ep93xx_rtc_init);
+module_exit(ep93xx_rtc_exit);
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
new file mode 100644
index 0000000..cfedc1d
--- /dev/null
+++ b/drivers/rtc/rtc-lib.c
@@ -0,0 +1,101 @@
+/*
+ * rtc and date/time utility functions
+ *
+ * Copyright (C) 2005-06 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on arch/arm/common/rtctime.c and other bits
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+
+static const unsigned char rtc_days_in_month[] = {
+	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
+#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
+
+int rtc_month_days(unsigned int month, unsigned int year)
+{
+	return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1);
+}
+EXPORT_SYMBOL(rtc_month_days);
+
+/*
+ * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
+ */
+void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
+{
+	register int days, month, year;
+
+	days = time / 86400;
+	time -= days * 86400;
+
+	/* day of the week, 1970-01-01 was a Thursday */
+	tm->tm_wday = (days + 4) % 7;
+
+	year = 1970 + days / 365;
+	days -= (year - 1970) * 365
+		+ LEAPS_THRU_END_OF(year - 1)
+		- LEAPS_THRU_END_OF(1970 - 1);
+	if (days < 0) {
+		year -= 1;
+		days += 365 + LEAP_YEAR(year);
+	}
+	tm->tm_year = year - 1900;
+	tm->tm_yday = days + 1;
+
+	for (month = 0; month < 11; month++) {
+		int newdays;
+
+		newdays = days - rtc_month_days(month, year);
+		if (newdays < 0)
+			break;
+		days = newdays;
+	}
+	tm->tm_mon = month;
+	tm->tm_mday = days + 1;
+
+	tm->tm_hour = time / 3600;
+	time -= tm->tm_hour * 3600;
+	tm->tm_min = time / 60;
+	tm->tm_sec = time - tm->tm_min * 60;
+}
+EXPORT_SYMBOL(rtc_time_to_tm);
+
+/*
+ * Does the rtc_time represent a valid date/time?
+ */
+int rtc_valid_tm(struct rtc_time *tm)
+{
+	if (tm->tm_year < 70
+		|| tm->tm_mon >= 12
+		|| tm->tm_mday < 1
+		|| tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900)
+		|| tm->tm_hour >= 24
+		|| tm->tm_min >= 60
+		|| tm->tm_sec >= 60)
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL(rtc_valid_tm);
+
+/*
+ * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
+ */
+int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
+{
+	*time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+			tm->tm_hour, tm->tm_min, tm->tm_sec);
+	return 0;
+}
+EXPORT_SYMBOL(rtc_tm_to_time);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c
new file mode 100644
index 0000000..db445c8
--- /dev/null
+++ b/drivers/rtc/rtc-m48t86.c
@@ -0,0 +1,209 @@
+/*
+ * ST M48T86 / Dallas DS12887 RTC driver
+ * Copyright (c) 2006 Tower Technologies
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This drivers only supports the clock running in BCD and 24H mode.
+ * If it will be ever adapted to binary and 12H mode, care must be taken
+ * to not introduce bugs.
+ */
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/m48t86.h>
+#include <linux/bcd.h>
+
+#define M48T86_REG_SEC		0x00
+#define M48T86_REG_SECALRM	0x01
+#define M48T86_REG_MIN		0x02
+#define M48T86_REG_MINALRM	0x03
+#define M48T86_REG_HOUR	0x04
+#define M48T86_REG_HOURALRM	0x05
+#define M48T86_REG_DOW		0x06 /* 1 = sunday */
+#define M48T86_REG_DOM		0x07
+#define M48T86_REG_MONTH	0x08 /* 1 - 12 */
+#define M48T86_REG_YEAR		0x09 /* 0 - 99 */
+#define M48T86_REG_A		0x0A
+#define M48T86_REG_B		0x0B
+#define M48T86_REG_C		0x0C
+#define M48T86_REG_D		0x0D
+
+#define M48T86_REG_B_H24	(1 << 1)
+#define M48T86_REG_B_DM		(1 << 2)
+#define M48T86_REG_B_SET	(1 << 7)
+#define M48T86_REG_D_VRT	(1 << 7)
+
+#define DRV_VERSION "0.1"
+
+
+static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	unsigned char reg;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct m48t86_ops *ops = pdev->dev.platform_data;
+
+	reg = ops->readb(M48T86_REG_B);
+
+	if (reg & M48T86_REG_B_DM) {
+		/* data (binary) mode */
+		tm->tm_sec	= ops->readb(M48T86_REG_SEC);
+		tm->tm_min	= ops->readb(M48T86_REG_MIN);
+		tm->tm_hour	= ops->readb(M48T86_REG_HOUR) & 0x3F;
+		tm->tm_mday	= ops->readb(M48T86_REG_DOM);
+		/* tm_mon is 0-11 */
+		tm->tm_mon	= ops->readb(M48T86_REG_MONTH) - 1;
+		tm->tm_year	= ops->readb(M48T86_REG_YEAR) + 100;
+		tm->tm_wday	= ops->readb(M48T86_REG_DOW);
+	} else {
+		/* bcd mode */
+		tm->tm_sec	= BCD2BIN(ops->readb(M48T86_REG_SEC));
+		tm->tm_min	= BCD2BIN(ops->readb(M48T86_REG_MIN));
+		tm->tm_hour	= BCD2BIN(ops->readb(M48T86_REG_HOUR) & 0x3F);
+		tm->tm_mday	= BCD2BIN(ops->readb(M48T86_REG_DOM));
+		/* tm_mon is 0-11 */
+		tm->tm_mon	= BCD2BIN(ops->readb(M48T86_REG_MONTH)) - 1;
+		tm->tm_year	= BCD2BIN(ops->readb(M48T86_REG_YEAR)) + 100;
+		tm->tm_wday	= BCD2BIN(ops->readb(M48T86_REG_DOW));
+	}
+
+	/* correct the hour if the clock is in 12h mode */
+	if (!(reg & M48T86_REG_B_H24))
+		if (ops->readb(M48T86_REG_HOUR) & 0x80)
+			tm->tm_hour += 12;
+
+	return 0;
+}
+
+static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	unsigned char reg;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct m48t86_ops *ops = pdev->dev.platform_data;
+
+	reg = ops->readb(M48T86_REG_B);
+
+	/* update flag and 24h mode */
+	reg |= M48T86_REG_B_SET | M48T86_REG_B_H24;
+	ops->writeb(reg, M48T86_REG_B);
+
+	if (reg & M48T86_REG_B_DM) {
+		/* data (binary) mode */
+		ops->writeb(tm->tm_sec, M48T86_REG_SEC);
+		ops->writeb(tm->tm_min, M48T86_REG_MIN);
+		ops->writeb(tm->tm_hour, M48T86_REG_HOUR);
+		ops->writeb(tm->tm_mday, M48T86_REG_DOM);
+		ops->writeb(tm->tm_mon + 1, M48T86_REG_MONTH);
+		ops->writeb(tm->tm_year % 100, M48T86_REG_YEAR);
+		ops->writeb(tm->tm_wday, M48T86_REG_DOW);
+	} else {
+		/* bcd mode */
+		ops->writeb(BIN2BCD(tm->tm_sec), M48T86_REG_SEC);
+		ops->writeb(BIN2BCD(tm->tm_min), M48T86_REG_MIN);
+		ops->writeb(BIN2BCD(tm->tm_hour), M48T86_REG_HOUR);
+		ops->writeb(BIN2BCD(tm->tm_mday), M48T86_REG_DOM);
+		ops->writeb(BIN2BCD(tm->tm_mon + 1), M48T86_REG_MONTH);
+		ops->writeb(BIN2BCD(tm->tm_year % 100), M48T86_REG_YEAR);
+		ops->writeb(BIN2BCD(tm->tm_wday), M48T86_REG_DOW);
+	}
+
+	/* update ended */
+	reg &= ~M48T86_REG_B_SET;
+	ops->writeb(reg, M48T86_REG_B);
+
+	return 0;
+}
+
+static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	unsigned char reg;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct m48t86_ops *ops = pdev->dev.platform_data;
+
+	reg = ops->readb(M48T86_REG_B);
+
+	seq_printf(seq, "24hr\t\t: %s\n",
+		 (reg & M48T86_REG_B_H24) ? "yes" : "no");
+
+	seq_printf(seq, "mode\t\t: %s\n",
+		 (reg & M48T86_REG_B_DM) ? "binary" : "bcd");
+
+	reg = ops->readb(M48T86_REG_D);
+
+	seq_printf(seq, "battery\t\t: %s\n",
+		 (reg & M48T86_REG_D_VRT) ? "ok" : "exhausted");
+
+	return 0;
+}
+
+static struct rtc_class_ops m48t86_rtc_ops = {
+	.read_time	= m48t86_rtc_read_time,
+	.set_time	= m48t86_rtc_set_time,
+	.proc		= m48t86_rtc_proc,
+};
+
+static int __devinit m48t86_rtc_probe(struct platform_device *dev)
+{
+	unsigned char reg;
+	struct m48t86_ops *ops = dev->dev.platform_data;
+	struct rtc_device *rtc = rtc_device_register("m48t86",
+				&dev->dev, &m48t86_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		dev_err(&dev->dev, "unable to register\n");
+		return PTR_ERR(rtc);
+	}
+
+	platform_set_drvdata(dev, rtc);
+
+	/* read battery status */
+	reg = ops->readb(M48T86_REG_D);
+	dev_info(&dev->dev, "battery %s\n",
+		(reg & M48T86_REG_D_VRT) ? "ok" : "exhausted");
+
+	return 0;
+}
+
+static int __devexit m48t86_rtc_remove(struct platform_device *dev)
+{
+	struct rtc_device *rtc = platform_get_drvdata(dev);
+
+ 	if (rtc)
+		rtc_device_unregister(rtc);
+
+	platform_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver m48t86_rtc_platform_driver = {
+	.driver		= {
+		.name	= "rtc-m48t86",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= m48t86_rtc_probe,
+	.remove		= __devexit_p(m48t86_rtc_remove),
+};
+
+static int __init m48t86_rtc_init(void)
+{
+	return platform_driver_register(&m48t86_rtc_platform_driver);
+}
+
+static void __exit m48t86_rtc_exit(void)
+{
+	platform_driver_unregister(&m48t86_rtc_platform_driver);
+}
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("M48T86 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(m48t86_rtc_init);
+module_exit(m48t86_rtc_exit);
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
new file mode 100644
index 0000000..d857d45
--- /dev/null
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -0,0 +1,353 @@
+/*
+ * An I2C driver for the Philips PCF8563 RTC
+ * Copyright 2005-06 Tower Technologies
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ * Maintainers: http://www.nslu2-linux.org/
+ *
+ * based on the other drivers in this same directory.
+ *
+ * http://www.semiconductors.philips.com/acrobat/datasheets/PCF8563-04.pdf
+ *
+ * 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/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+
+#define DRV_VERSION "0.4.2"
+
+/* Addresses to scan: none
+ * This chip cannot be reliably autodetected. An empty eeprom
+ * located at 0x51 will pass the validation routine due to
+ * the way the registers are implemented.
+ */
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Module parameters */
+I2C_CLIENT_INSMOD;
+
+#define PCF8563_REG_ST1		0x00 /* status */
+#define PCF8563_REG_ST2		0x01
+
+#define PCF8563_REG_SC		0x02 /* datetime */
+#define PCF8563_REG_MN		0x03
+#define PCF8563_REG_HR		0x04
+#define PCF8563_REG_DM		0x05
+#define PCF8563_REG_DW		0x06
+#define PCF8563_REG_MO		0x07
+#define PCF8563_REG_YR		0x08
+
+#define PCF8563_REG_AMN		0x09 /* alarm */
+#define PCF8563_REG_AHR		0x0A
+#define PCF8563_REG_ADM		0x0B
+#define PCF8563_REG_ADW		0x0C
+
+#define PCF8563_REG_CLKO	0x0D /* clock out */
+#define PCF8563_REG_TMRC	0x0E /* timer control */
+#define PCF8563_REG_TMR		0x0F /* timer */
+
+#define PCF8563_SC_LV		0x80 /* low voltage */
+#define PCF8563_MO_C		0x80 /* century */
+
+static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind);
+static int pcf8563_detach(struct i2c_client *client);
+
+/*
+ * In the routines that deal directly with the pcf8563 hardware, we use
+ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
+ */
+static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+	unsigned char buf[13] = { PCF8563_REG_ST1 };
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 1, buf },	/* setup read ptr */
+		{ client->addr, I2C_M_RD, 13, buf },	/* read status + date */
+	};
+
+	/* read registers */
+	if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	if (buf[PCF8563_REG_SC] & PCF8563_SC_LV)
+		dev_info(&client->dev,
+			"low voltage detected, date/time is not reliable.\n");
+
+	dev_dbg(&client->dev,
+		"%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "
+		"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
+		__FUNCTION__,
+		buf[0], buf[1], buf[2], buf[3],
+		buf[4], buf[5], buf[6], buf[7],
+		buf[8]);
+
+
+	tm->tm_sec = BCD2BIN(buf[PCF8563_REG_SC] & 0x7F);
+	tm->tm_min = BCD2BIN(buf[PCF8563_REG_MN] & 0x7F);
+	tm->tm_hour = BCD2BIN(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */
+	tm->tm_mday = BCD2BIN(buf[PCF8563_REG_DM] & 0x3F);
+	tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
+	tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
+	tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR])
+		+ (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 100 : 0);
+
+	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	/* the clock can give out invalid datetime, but we cannot return
+	 * -EINVAL otherwise hwclock will refuse to set the time on bootup.
+	 */
+	if (rtc_valid_tm(tm) < 0)
+		dev_err(&client->dev, "retrieved date/time is not valid.\n");
+
+	return 0;
+}
+
+static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+	int i, err;
+	unsigned char buf[9];
+
+	dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	/* hours, minutes and seconds */
+	buf[PCF8563_REG_SC] = BIN2BCD(tm->tm_sec);
+	buf[PCF8563_REG_MN] = BIN2BCD(tm->tm_min);
+	buf[PCF8563_REG_HR] = BIN2BCD(tm->tm_hour);
+
+	buf[PCF8563_REG_DM] = BIN2BCD(tm->tm_mday);
+
+	/* month, 1 - 12 */
+	buf[PCF8563_REG_MO] = BIN2BCD(tm->tm_mon + 1);
+
+	/* year and century */
+	buf[PCF8563_REG_YR] = BIN2BCD(tm->tm_year % 100);
+	if (tm->tm_year / 100)
+		buf[PCF8563_REG_MO] |= PCF8563_MO_C;
+
+	buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
+
+	/* write register's data */
+	for (i = 0; i < 7; i++) {
+		unsigned char data[2] = { PCF8563_REG_SC + i,
+						buf[PCF8563_REG_SC + i] };
+
+		err = i2c_master_send(client, data, sizeof(data));
+		if (err != sizeof(data)) {
+			dev_err(&client->dev,
+				"%s: err=%d addr=%02x, data=%02x\n",
+				__FUNCTION__, err, data[0], data[1]);
+			return -EIO;
+		}
+	};
+
+	return 0;
+}
+
+struct pcf8563_limit
+{
+	unsigned char reg;
+	unsigned char mask;
+	unsigned char min;
+	unsigned char max;
+};
+
+static int pcf8563_validate_client(struct i2c_client *client)
+{
+	int i;
+
+	static const struct pcf8563_limit pattern[] = {
+		/* register, mask, min, max */
+		{ PCF8563_REG_SC,	0x7F,	0,	59	},
+		{ PCF8563_REG_MN,	0x7F,	0,	59	},
+		{ PCF8563_REG_HR,	0x3F,	0,	23	},
+		{ PCF8563_REG_DM,	0x3F,	0,	31	},
+		{ PCF8563_REG_MO,	0x1F,	0,	12	},
+	};
+
+	/* check limits (only registers with bcd values) */
+	for (i = 0; i < ARRAY_SIZE(pattern); i++) {
+		int xfer;
+		unsigned char value;
+		unsigned char buf = pattern[i].reg;
+
+		struct i2c_msg msgs[] = {
+			{ client->addr, 0, 1, &buf },
+			{ client->addr, I2C_M_RD, 1, &buf },
+		};
+
+		xfer = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+
+		if (xfer != ARRAY_SIZE(msgs)) {
+			dev_err(&client->adapter->dev,
+				"%s: could not read register 0x%02X\n",
+				__FUNCTION__, pattern[i].reg);
+
+			return -EIO;
+		}
+
+		value = BCD2BIN(buf & pattern[i].mask);
+
+		if (value > pattern[i].max ||
+			value < pattern[i].min) {
+			dev_dbg(&client->adapter->dev,
+				"%s: pattern=%d, reg=%x, mask=0x%02x, min=%d, "
+				"max=%d, value=%d, raw=0x%02X\n",
+				__FUNCTION__, i, pattern[i].reg, pattern[i].mask,
+				pattern[i].min, pattern[i].max,
+				value, buf);
+
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return pcf8563_get_datetime(to_i2c_client(dev), tm);
+}
+
+static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return pcf8563_set_datetime(to_i2c_client(dev), tm);
+}
+
+static int pcf8563_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	seq_printf(seq, "24hr\t\t: yes\n");
+	return 0;
+}
+
+static struct rtc_class_ops pcf8563_rtc_ops = {
+	.proc		= pcf8563_rtc_proc,
+	.read_time	= pcf8563_rtc_read_time,
+	.set_time	= pcf8563_rtc_set_time,
+};
+
+static int pcf8563_attach(struct i2c_adapter *adapter)
+{
+	return i2c_probe(adapter, &addr_data, pcf8563_probe);
+}
+
+static struct i2c_driver pcf8563_driver = {
+	.driver		= {
+		.name	= "pcf8563",
+	},
+	.id		= I2C_DRIVERID_PCF8563,
+	.attach_adapter = &pcf8563_attach,
+	.detach_client	= &pcf8563_detach,
+};
+
+static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct rtc_device *rtc;
+
+	int err = 0;
+
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	client->addr = address;
+	client->driver = &pcf8563_driver;
+	client->adapter	= adapter;
+
+	strlcpy(client->name, pcf8563_driver.driver.name, I2C_NAME_SIZE);
+
+	/* Verify the chip is really an PCF8563 */
+	if (kind < 0) {
+		if (pcf8563_validate_client(client) < 0) {
+			err = -ENODEV;
+			goto exit_kfree;
+		}
+	}
+
+	/* Inform the i2c layer */
+	if ((err = i2c_attach_client(client)))
+		goto exit_kfree;
+
+	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+	rtc = rtc_device_register(pcf8563_driver.driver.name, &client->dev,
+				&pcf8563_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		err = PTR_ERR(rtc);
+		dev_err(&client->dev,
+			"unable to register the class device\n");
+		goto exit_detach;
+	}
+
+	i2c_set_clientdata(client, rtc);
+
+	return 0;
+
+exit_detach:
+	i2c_detach_client(client);
+
+exit_kfree:
+	kfree(client);
+
+exit:
+	return err;
+}
+
+static int pcf8563_detach(struct i2c_client *client)
+{
+	int err;
+	struct rtc_device *rtc = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "%s\n", __FUNCTION__);
+
+	if (rtc)
+		rtc_device_unregister(rtc);
+
+	if ((err = i2c_detach_client(client)))
+		return err;
+
+	kfree(client);
+
+	return 0;
+}
+
+static int __init pcf8563_init(void)
+{
+	return i2c_add_driver(&pcf8563_driver);
+}
+
+static void __exit pcf8563_exit(void)
+{
+	i2c_del_driver(&pcf8563_driver);
+}
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(pcf8563_init);
+module_exit(pcf8563_exit);
diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c
new file mode 100644
index 0000000..90b8a97
--- /dev/null
+++ b/drivers/rtc/rtc-proc.c
@@ -0,0 +1,162 @@
+/*
+ * RTC subsystem, proc interface
+ *
+ * Copyright (C) 2005-06 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on arch/arm/common/rtctime.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static struct class_device *rtc_dev = NULL;
+static DEFINE_MUTEX(rtc_lock);
+
+static int rtc_proc_show(struct seq_file *seq, void *offset)
+{
+	int err;
+	struct class_device *class_dev = seq->private;
+	struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
+	struct rtc_wkalrm alrm;
+	struct rtc_time tm;
+
+	err = rtc_read_time(class_dev, &tm);
+	if (err == 0) {
+		seq_printf(seq,
+			"rtc_time\t: %02d:%02d:%02d\n"
+			"rtc_date\t: %04d-%02d-%02d\n",
+			tm.tm_hour, tm.tm_min, tm.tm_sec,
+			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+	}
+
+	err = rtc_read_alarm(class_dev, &alrm);
+	if (err == 0) {
+		seq_printf(seq, "alrm_time\t: ");
+		if ((unsigned int)alrm.time.tm_hour <= 24)
+			seq_printf(seq, "%02d:", alrm.time.tm_hour);
+		else
+			seq_printf(seq, "**:");
+		if ((unsigned int)alrm.time.tm_min <= 59)
+			seq_printf(seq, "%02d:", alrm.time.tm_min);
+		else
+			seq_printf(seq, "**:");
+		if ((unsigned int)alrm.time.tm_sec <= 59)
+			seq_printf(seq, "%02d\n", alrm.time.tm_sec);
+		else
+			seq_printf(seq, "**\n");
+
+		seq_printf(seq, "alrm_date\t: ");
+		if ((unsigned int)alrm.time.tm_year <= 200)
+			seq_printf(seq, "%04d-", alrm.time.tm_year + 1900);
+		else
+			seq_printf(seq, "****-");
+		if ((unsigned int)alrm.time.tm_mon <= 11)
+			seq_printf(seq, "%02d-", alrm.time.tm_mon + 1);
+		else
+			seq_printf(seq, "**-");
+		if ((unsigned int)alrm.time.tm_mday <= 31)
+			seq_printf(seq, "%02d\n", alrm.time.tm_mday);
+		else
+			seq_printf(seq, "**\n");
+		seq_printf(seq, "alrm_wakeup\t: %s\n",
+				alrm.enabled ? "yes" : "no");
+		seq_printf(seq, "alrm_pending\t: %s\n",
+				alrm.pending ? "yes" : "no");
+	}
+
+	if (ops->proc)
+		ops->proc(class_dev->dev, seq);
+
+	return 0;
+}
+
+static int rtc_proc_open(struct inode *inode, struct file *file)
+{
+	struct class_device *class_dev = PDE(inode)->data;
+
+	if (!try_module_get(THIS_MODULE))
+		return -ENODEV;
+
+	return single_open(file, rtc_proc_show, class_dev);
+}
+
+static int rtc_proc_release(struct inode *inode, struct file *file)
+{
+	int res = single_release(inode, file);
+	module_put(THIS_MODULE);
+	return res;
+}
+
+static struct file_operations rtc_proc_fops = {
+	.open		= rtc_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= rtc_proc_release,
+};
+
+static int rtc_proc_add_device(struct class_device *class_dev,
+					struct class_interface *class_intf)
+{
+	mutex_lock(&rtc_lock);
+	if (rtc_dev == NULL) {
+		struct proc_dir_entry *ent;
+
+		rtc_dev = class_dev;
+
+		ent = create_proc_entry("driver/rtc", 0, NULL);
+		if (ent) {
+			struct rtc_device *rtc = to_rtc_device(class_dev);
+
+			ent->proc_fops = &rtc_proc_fops;
+			ent->owner = rtc->owner;
+			ent->data = class_dev;
+
+			dev_info(class_dev->dev, "rtc intf: proc\n");
+		}
+		else
+			rtc_dev = NULL;
+	}
+	mutex_unlock(&rtc_lock);
+
+	return 0;
+}
+
+static void rtc_proc_remove_device(struct class_device *class_dev,
+					struct class_interface *class_intf)
+{
+	mutex_lock(&rtc_lock);
+	if (rtc_dev == class_dev) {
+		remove_proc_entry("driver/rtc", NULL);
+		rtc_dev = NULL;
+	}
+	mutex_unlock(&rtc_lock);
+}
+
+static struct class_interface rtc_proc_interface = {
+	.add = &rtc_proc_add_device,
+	.remove = &rtc_proc_remove_device,
+};
+
+static int __init rtc_proc_init(void)
+{
+	return rtc_interface_register(&rtc_proc_interface);
+}
+
+static void __exit rtc_proc_exit(void)
+{
+	class_interface_unregister(&rtc_proc_interface);
+}
+
+module_init(rtc_proc_init);
+module_exit(rtc_proc_exit);
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("RTC class proc interface");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
new file mode 100644
index 0000000..396c868
--- /dev/null
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -0,0 +1,294 @@
+/*
+ * An I2C driver for the Ricoh RS5C372 RTC
+ *
+ * Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net>
+ * Copyright (C) 2006 Tower Technologies
+ *
+ * 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/i2c.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+#define DRV_VERSION "0.2"
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD;
+
+#define RS5C372_REG_SECS	0
+#define RS5C372_REG_MINS	1
+#define RS5C372_REG_HOURS	2
+#define RS5C372_REG_WDAY	3
+#define RS5C372_REG_DAY		4
+#define RS5C372_REG_MONTH	5
+#define RS5C372_REG_YEAR	6
+#define RS5C372_REG_TRIM	7
+
+#define RS5C372_TRIM_XSL	0x80
+#define RS5C372_TRIM_MASK	0x7F
+
+#define RS5C372_REG_BASE	0
+
+static int rs5c372_attach(struct i2c_adapter *adapter);
+static int rs5c372_detach(struct i2c_client *client);
+static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind);
+
+static struct i2c_driver rs5c372_driver = {
+	.driver		= {
+		.name	= "rs5c372",
+	},
+	.attach_adapter	= &rs5c372_attach,
+	.detach_client	= &rs5c372_detach,
+};
+
+static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+	unsigned char buf[7] = { RS5C372_REG_BASE };
+
+	/* this implements the 1st reading method, according
+	 * to the datasheet. buf[0] is initialized with
+	 * address ptr and transmission format register.
+	 */
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 1, buf },
+		{ client->addr, I2C_M_RD, 7, buf },
+	};
+
+	if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	tm->tm_sec = BCD2BIN(buf[RS5C372_REG_SECS] & 0x7f);
+	tm->tm_min = BCD2BIN(buf[RS5C372_REG_MINS] & 0x7f);
+	tm->tm_hour = BCD2BIN(buf[RS5C372_REG_HOURS] & 0x3f);
+	tm->tm_wday = BCD2BIN(buf[RS5C372_REG_WDAY] & 0x07);
+	tm->tm_mday = BCD2BIN(buf[RS5C372_REG_DAY] & 0x3f);
+
+	/* tm->tm_mon is zero-based */
+	tm->tm_mon = BCD2BIN(buf[RS5C372_REG_MONTH] & 0x1f) - 1;
+
+	/* year is 1900 + tm->tm_year */
+	tm->tm_year = BCD2BIN(buf[RS5C372_REG_YEAR]) + 100;
+
+	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	return 0;
+}
+
+static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+	unsigned char buf[8] = { RS5C372_REG_BASE };
+
+	dev_dbg(&client->dev,
+		"%s: secs=%d, mins=%d, hours=%d ",
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	buf[1] = BIN2BCD(tm->tm_sec);
+	buf[2] = BIN2BCD(tm->tm_min);
+	buf[3] = BIN2BCD(tm->tm_hour);
+	buf[4] = BIN2BCD(tm->tm_wday);
+	buf[5] = BIN2BCD(tm->tm_mday);
+	buf[6] = BIN2BCD(tm->tm_mon + 1);
+	buf[7] = BIN2BCD(tm->tm_year - 100);
+
+	if ((i2c_master_send(client, buf, 8)) != 8) {
+		dev_err(&client->dev, "%s: write error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim)
+{
+	unsigned char buf = RS5C372_REG_TRIM;
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 1, &buf },
+		{ client->addr, I2C_M_RD, 1, &buf },
+	};
+
+	if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, trim);
+
+	if (osc)
+		*osc = (buf & RS5C372_TRIM_XSL) ? 32000 : 32768;
+
+	if (trim)
+		*trim = buf & RS5C372_TRIM_MASK;
+
+	return 0;
+}
+
+static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return rs5c372_get_datetime(to_i2c_client(dev), tm);
+}
+
+static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return rs5c372_set_datetime(to_i2c_client(dev), tm);
+}
+
+static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	int err, osc, trim;
+
+	seq_printf(seq, "24hr\t\t: yes\n");
+
+	if ((err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim)) == 0) {
+		seq_printf(seq, "%d.%03d KHz\n", osc / 1000, osc % 1000);
+		seq_printf(seq, "trim\t: %d\n", trim);
+	}
+
+	return 0;
+}
+
+static struct rtc_class_ops rs5c372_rtc_ops = {
+	.proc		= rs5c372_rtc_proc,
+	.read_time	= rs5c372_rtc_read_time,
+	.set_time	= rs5c372_rtc_set_time,
+};
+
+static ssize_t rs5c372_sysfs_show_trim(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int trim;
+
+	if (rs5c372_get_trim(to_i2c_client(dev), NULL, &trim) == 0)
+		return sprintf(buf, "0x%2x\n", trim);
+
+	return 0;
+}
+static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL);
+
+static ssize_t rs5c372_sysfs_show_osc(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int osc;
+
+	if (rs5c372_get_trim(to_i2c_client(dev), &osc, NULL) == 0)
+		return sprintf(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000);
+
+	return 0;
+}
+static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL);
+
+static int rs5c372_attach(struct i2c_adapter *adapter)
+{
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+	return i2c_probe(adapter, &addr_data, rs5c372_probe);
+}
+
+static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
+{
+	int err = 0;
+	struct i2c_client *client;
+	struct rtc_device *rtc;
+
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	/* I2C client */
+	client->addr = address;
+	client->driver = &rs5c372_driver;
+	client->adapter = adapter;
+
+	strlcpy(client->name, rs5c372_driver.driver.name, I2C_NAME_SIZE);
+
+	/* Inform the i2c layer */
+	if ((err = i2c_attach_client(client)))
+		goto exit_kfree;
+
+	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+	rtc = rtc_device_register(rs5c372_driver.driver.name, &client->dev,
+				&rs5c372_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		err = PTR_ERR(rtc);
+		dev_err(&client->dev,
+			"unable to register the class device\n");
+		goto exit_detach;
+	}
+
+	i2c_set_clientdata(client, rtc);
+
+	device_create_file(&client->dev, &dev_attr_trim);
+	device_create_file(&client->dev, &dev_attr_osc);
+
+	return 0;
+
+exit_detach:
+	i2c_detach_client(client);
+
+exit_kfree:
+	kfree(client);
+
+exit:
+	return err;
+}
+
+static int rs5c372_detach(struct i2c_client *client)
+{
+	int err;
+	struct rtc_device *rtc = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "%s\n", __FUNCTION__);
+
+	if (rtc)
+		rtc_device_unregister(rtc);
+
+	if ((err = i2c_detach_client(client)))
+		return err;
+
+	kfree(client);
+
+	return 0;
+}
+
+static __init int rs5c372_init(void)
+{
+	return i2c_add_driver(&rs5c372_driver);
+}
+
+static __exit void rs5c372_exit(void)
+{
+	i2c_del_driver(&rs5c372_driver);
+}
+
+module_init(rs5c372_init);
+module_exit(rs5c372_exit);
+
+MODULE_AUTHOR(
+		"Pavel Mironchik <pmironchik@optifacio.net>, "
+		"Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
new file mode 100644
index 0000000..83b2bb4
--- /dev/null
+++ b/drivers/rtc/rtc-sa1100.c
@@ -0,0 +1,388 @@
+/*
+ * Real Time Clock interface for StrongARM SA1x00 and XScale PXA2xx
+ *
+ * Copyright (c) 2000 Nils Faerber
+ *
+ * Based on rtc.c by Paul Gortmaker
+ *
+ * Original Driver by Nils Faerber <nils@kernelconcepts.de>
+ *
+ * Modifications from:
+ *   CIH <cih@coventive.com>
+ *   Nicolas Pitre <nico@cam.org>
+ *   Andrew Christian <andrew.christian@hp.com>
+ *
+ * Converted to the RTC subsystem and Driver Model
+ *   by Richard Purdie <rpurdie@rpsys.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/pm.h>
+
+#include <asm/bitops.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/rtc.h>
+
+#ifdef CONFIG_ARCH_PXA
+#include <asm/arch/pxa-regs.h>
+#endif
+
+#define TIMER_FREQ		CLOCK_TICK_RATE
+#define RTC_DEF_DIVIDER		32768 - 1
+#define RTC_DEF_TRIM		0
+
+static unsigned long rtc_freq = 1024;
+static struct rtc_time rtc_alarm;
+static spinlock_t sa1100_rtc_lock = SPIN_LOCK_UNLOCKED;
+
+static int rtc_update_alarm(struct rtc_time *alrm)
+{
+	struct rtc_time alarm_tm, now_tm;
+	unsigned long now, time;
+	int ret;
+
+	do {
+		now = RCNR;
+		rtc_time_to_tm(now, &now_tm);
+		rtc_next_alarm_time(&alarm_tm, &now_tm, alrm);
+		ret = rtc_tm_to_time(&alarm_tm, &time);
+		if (ret != 0)
+			break;
+
+		RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL);
+		RTAR = time;
+	} while (now != RCNR);
+
+	return ret;
+}
+
+static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id,
+		struct pt_regs *regs)
+{
+	struct platform_device *pdev = to_platform_device(dev_id);
+	struct rtc_device *rtc = platform_get_drvdata(pdev);
+	unsigned int rtsr;
+	unsigned long events = 0;
+
+	spin_lock(&sa1100_rtc_lock);
+
+	rtsr = RTSR;
+	/* clear interrupt sources */
+	RTSR = 0;
+	RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2);
+
+	/* clear alarm interrupt if it has occurred */
+	if (rtsr & RTSR_AL)
+		rtsr &= ~RTSR_ALE;
+	RTSR = rtsr & (RTSR_ALE | RTSR_HZE);
+
+	/* update irq data & counter */
+	if (rtsr & RTSR_AL)
+		events |= RTC_AF | RTC_IRQF;
+	if (rtsr & RTSR_HZ)
+		events |= RTC_UF | RTC_IRQF;
+
+	rtc_update_irq(&rtc->class_dev, 1, events);
+
+	if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm))
+		rtc_update_alarm(&rtc_alarm);
+
+	spin_unlock(&sa1100_rtc_lock);
+
+	return IRQ_HANDLED;
+}
+
+static int rtc_timer1_count;
+
+static irqreturn_t timer1_interrupt(int irq, void *dev_id,
+		struct pt_regs *regs)
+{
+	struct platform_device *pdev = to_platform_device(dev_id);
+	struct rtc_device *rtc = platform_get_drvdata(pdev);
+
+	/*
+	 * If we match for the first time, rtc_timer1_count will be 1.
+	 * Otherwise, we wrapped around (very unlikely but
+	 * still possible) so compute the amount of missed periods.
+	 * The match reg is updated only when the data is actually retrieved
+	 * to avoid unnecessary interrupts.
+	 */
+	OSSR = OSSR_M1;	/* clear match on timer1 */
+
+	rtc_update_irq(&rtc->class_dev, rtc_timer1_count, RTC_PF | RTC_IRQF);
+
+	if (rtc_timer1_count == 1)
+		rtc_timer1_count = (rtc_freq * ((1<<30)/(TIMER_FREQ>>2)));
+
+	return IRQ_HANDLED;
+}
+
+static int sa1100_rtc_read_callback(struct device *dev, int data)
+{
+	if (data & RTC_PF) {
+		/* interpolate missed periods and set match for the next */
+		unsigned long period = TIMER_FREQ/rtc_freq;
+		unsigned long oscr = OSCR;
+		unsigned long osmr1 = OSMR1;
+		unsigned long missed = (oscr - osmr1)/period;
+		data += missed << 8;
+		OSSR = OSSR_M1;	/* clear match on timer 1 */
+		OSMR1 = osmr1 + (missed + 1)*period;
+		/* Ensure we didn't miss another match in the mean time.
+		 * Here we compare (match - OSCR) 8 instead of 0 --
+		 * see comment in pxa_timer_interrupt() for explanation.
+		 */
+		while( (signed long)((osmr1 = OSMR1) - OSCR) <= 8 ) {
+			data += 0x100;
+			OSSR = OSSR_M1;	/* clear match on timer 1 */
+			OSMR1 = osmr1 + period;
+		}
+	}
+	return data;
+}
+
+static int sa1100_rtc_open(struct device *dev)
+{
+	int ret;
+
+	ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, SA_INTERRUPT,
+				"rtc 1Hz", dev);
+	if (ret) {
+		printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTC1Hz);
+		goto fail_ui;
+	}
+	ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, SA_INTERRUPT,
+				"rtc Alrm", dev);
+	if (ret) {
+		printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTCAlrm);
+		goto fail_ai;
+	}
+	ret = request_irq(IRQ_OST1, timer1_interrupt, SA_INTERRUPT,
+				"rtc timer", dev);
+	if (ret) {
+		printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_OST1);
+		goto fail_pi;
+	}
+	return 0;
+
+ fail_pi:
+	free_irq(IRQ_RTCAlrm, NULL);
+ fail_ai:
+	free_irq(IRQ_RTC1Hz, NULL);
+ fail_ui:
+	return ret;
+}
+
+static void sa1100_rtc_release(struct device *dev)
+{
+	spin_lock_irq(&sa1100_rtc_lock);
+	RTSR = 0;
+	OIER &= ~OIER_E1;
+	OSSR = OSSR_M1;
+	spin_unlock_irq(&sa1100_rtc_lock);
+
+	free_irq(IRQ_OST1, dev);
+	free_irq(IRQ_RTCAlrm, dev);
+	free_irq(IRQ_RTC1Hz, dev);
+}
+
+
+static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
+		unsigned long arg)
+{
+	switch(cmd) {
+	case RTC_AIE_OFF:
+		spin_lock_irq(&sa1100_rtc_lock);
+		RTSR &= ~RTSR_ALE;
+		spin_unlock_irq(&sa1100_rtc_lock);
+		return 0;
+	case RTC_AIE_ON:
+		spin_lock_irq(&sa1100_rtc_lock);
+		RTSR |= RTSR_ALE;
+		spin_unlock_irq(&sa1100_rtc_lock);
+		return 0;
+	case RTC_UIE_OFF:
+		spin_lock_irq(&sa1100_rtc_lock);
+		RTSR &= ~RTSR_HZE;
+		spin_unlock_irq(&sa1100_rtc_lock);
+		return 0;
+	case RTC_UIE_ON:
+		spin_lock_irq(&sa1100_rtc_lock);
+		RTSR |= RTSR_HZE;
+		spin_unlock_irq(&sa1100_rtc_lock);
+		return 0;
+	case RTC_PIE_OFF:
+		spin_lock_irq(&sa1100_rtc_lock);
+		OIER &= ~OIER_E1;
+		spin_unlock_irq(&sa1100_rtc_lock);
+		return 0;
+	case RTC_PIE_ON:
+		if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE))
+			return -EACCES;
+		spin_lock_irq(&sa1100_rtc_lock);
+		OSMR1 = TIMER_FREQ/rtc_freq + OSCR;
+		OIER |= OIER_E1;
+		rtc_timer1_count = 1;
+		spin_unlock_irq(&sa1100_rtc_lock);
+		return 0;
+	case RTC_IRQP_READ:
+		return put_user(rtc_freq, (unsigned long *)arg);
+	case RTC_IRQP_SET:
+		if (arg < 1 || arg > TIMER_FREQ)
+			return -EINVAL;
+		if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
+			return -EACCES;
+		rtc_freq = arg;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	rtc_time_to_tm(RCNR, tm);
+	return 0;
+}
+
+static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	unsigned long time;
+	int ret;
+
+	ret = rtc_tm_to_time(tm, &time);
+	if (ret == 0)
+		RCNR = time;
+	return ret;
+}
+
+static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time));
+	alrm->pending = RTSR & RTSR_AL ? 1 : 0;
+	return 0;
+}
+
+static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	int ret;
+
+	spin_lock_irq(&sa1100_rtc_lock);
+	ret = rtc_update_alarm(&alrm->time);
+	if (ret == 0) {
+		memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time));
+
+		if (alrm->enabled)
+			enable_irq_wake(IRQ_RTCAlrm);
+		else
+			disable_irq_wake(IRQ_RTCAlrm);
+	}
+	spin_unlock_irq(&sa1100_rtc_lock);
+
+	return ret;
+}
+
+static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	seq_printf(seq, "trim/divider\t: 0x%08x\n", RTTR);
+	seq_printf(seq, "alarm_IRQ\t: %s\n",
+			(RTSR & RTSR_ALE) ? "yes" : "no" );
+	seq_printf(seq, "update_IRQ\t: %s\n",
+			(RTSR & RTSR_HZE) ? "yes" : "no");
+	seq_printf(seq, "periodic_IRQ\t: %s\n",
+			(OIER & OIER_E1) ? "yes" : "no");
+	seq_printf(seq, "periodic_freq\t: %ld\n", rtc_freq);
+
+	return 0;
+}
+
+static struct rtc_class_ops sa1100_rtc_ops = {
+	.open = sa1100_rtc_open,
+	.read_callback = sa1100_rtc_read_callback,
+	.release = sa1100_rtc_release,
+	.ioctl = sa1100_rtc_ioctl,
+	.read_time = sa1100_rtc_read_time,
+	.set_time = sa1100_rtc_set_time,
+	.read_alarm = sa1100_rtc_read_alarm,
+	.set_alarm = sa1100_rtc_set_alarm,
+	.proc = sa1100_rtc_proc,
+};
+
+static int sa1100_rtc_probe(struct platform_device *pdev)
+{
+	struct rtc_device *rtc;
+
+	/*
+	 * According to the manual we should be able to let RTTR be zero
+	 * and then a default diviser for a 32.768KHz clock is used.
+	 * Apparently this doesn't work, at least for my SA1110 rev 5.
+	 * If the clock divider is uninitialized then reset it to the
+	 * default value to get the 1Hz clock.
+	 */
+	if (RTTR == 0) {
+		RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
+		printk(KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n");
+		/* The current RTC value probably doesn't make sense either */
+		RCNR = 0;
+	}
+
+	rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops,
+				THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		dev_err(&pdev->dev, "Unable to register the RTC device\n");
+		return PTR_ERR(rtc);
+	}
+
+	platform_set_drvdata(pdev, rtc);
+
+	dev_info(&pdev->dev, "SA11xx/PXA2xx RTC Registered\n");
+
+	return 0;
+}
+
+static int sa1100_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_device *rtc = platform_get_drvdata(pdev);
+
+ 	if (rtc)
+		rtc_device_unregister(rtc);
+
+	return 0;
+}
+
+static struct platform_driver sa1100_rtc_driver = {
+	.probe		= sa1100_rtc_probe,
+	.remove		= sa1100_rtc_remove,
+	.driver		= {
+		.name		= "sa1100-rtc",
+	},
+};
+
+static int __init sa1100_rtc_init(void)
+{
+	return platform_driver_register(&sa1100_rtc_driver);
+}
+
+static void __exit sa1100_rtc_exit(void)
+{
+	platform_driver_unregister(&sa1100_rtc_driver);
+}
+
+module_init(sa1100_rtc_init);
+module_exit(sa1100_rtc_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("SA11x0/PXA2xx Realtime Clock Driver (RTC)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
new file mode 100644
index 0000000..7c1f3d2
--- /dev/null
+++ b/drivers/rtc/rtc-sysfs.c
@@ -0,0 +1,124 @@
+/*
+ * RTC subsystem, sysfs interface
+ *
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+
+/* device attributes */
+
+static ssize_t rtc_sysfs_show_name(struct class_device *dev, char *buf)
+{
+	return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
+}
+static CLASS_DEVICE_ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL);
+
+static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf)
+{
+	ssize_t retval;
+	struct rtc_time tm;
+
+	retval = rtc_read_time(dev, &tm);
+	if (retval == 0) {
+		retval = sprintf(buf, "%04d-%02d-%02d\n",
+			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+	}
+
+	return retval;
+}
+static CLASS_DEVICE_ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL);
+
+static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf)
+{
+	ssize_t retval;
+	struct rtc_time tm;
+
+	retval = rtc_read_time(dev, &tm);
+	if (retval == 0) {
+		retval = sprintf(buf, "%02d:%02d:%02d\n",
+			tm.tm_hour, tm.tm_min, tm.tm_sec);
+	}
+
+	return retval;
+}
+static CLASS_DEVICE_ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL);
+
+static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf)
+{
+	ssize_t retval;
+	struct rtc_time tm;
+
+	retval = rtc_read_time(dev, &tm);
+	if (retval == 0) {
+		unsigned long time;
+		rtc_tm_to_time(&tm, &time);
+		retval = sprintf(buf, "%lu\n", time);
+	}
+
+	return retval;
+}
+static CLASS_DEVICE_ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL);
+
+static struct attribute *rtc_attrs[] = {
+	&class_device_attr_name.attr,
+	&class_device_attr_date.attr,
+	&class_device_attr_time.attr,
+	&class_device_attr_since_epoch.attr,
+	NULL,
+};
+
+static struct attribute_group rtc_attr_group = {
+	.attrs = rtc_attrs,
+};
+
+static int __devinit rtc_sysfs_add_device(struct class_device *class_dev,
+					struct class_interface *class_intf)
+{
+	int err;
+
+	dev_info(class_dev->dev, "rtc intf: sysfs\n");
+
+	err = sysfs_create_group(&class_dev->kobj, &rtc_attr_group);
+	if (err)
+		dev_err(class_dev->dev,
+			"failed to create sysfs attributes\n");
+
+	return err;
+}
+
+static void rtc_sysfs_remove_device(struct class_device *class_dev,
+				struct class_interface *class_intf)
+{
+	sysfs_remove_group(&class_dev->kobj, &rtc_attr_group);
+}
+
+/* interface registration */
+
+static struct class_interface rtc_sysfs_interface = {
+	.add = &rtc_sysfs_add_device,
+	.remove = &rtc_sysfs_remove_device,
+};
+
+static int __init rtc_sysfs_init(void)
+{
+	return rtc_interface_register(&rtc_sysfs_interface);
+}
+
+static void __exit rtc_sysfs_exit(void)
+{
+	class_interface_unregister(&rtc_sysfs_interface);
+}
+
+module_init(rtc_sysfs_init);
+module_exit(rtc_sysfs_exit);
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("RTC class sysfs interface");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
new file mode 100644
index 0000000..43d1074
--- /dev/null
+++ b/drivers/rtc/rtc-test.c
@@ -0,0 +1,204 @@
+/*
+ * An RTC test device/driver
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+static struct platform_device *test0 = NULL, *test1 = NULL;
+
+static int test_rtc_read_alarm(struct device *dev,
+	struct rtc_wkalrm *alrm)
+{
+	return 0;
+}
+
+static int test_rtc_set_alarm(struct device *dev,
+	struct rtc_wkalrm *alrm)
+{
+	return 0;
+}
+
+static int test_rtc_read_time(struct device *dev,
+	struct rtc_time *tm)
+{
+	rtc_time_to_tm(get_seconds(), tm);
+	return 0;
+}
+
+static int test_rtc_set_time(struct device *dev,
+	struct rtc_time *tm)
+{
+	return 0;
+}
+
+static int test_rtc_set_mmss(struct device *dev, unsigned long secs)
+{
+	return 0;
+}
+
+static int test_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	struct platform_device *plat_dev = to_platform_device(dev);
+
+	seq_printf(seq, "24hr\t\t: yes\n");
+	seq_printf(seq, "test\t\t: yes\n");
+	seq_printf(seq, "id\t\t: %d\n", plat_dev->id);
+
+	return 0;
+}
+
+static int test_rtc_ioctl(struct device *dev, unsigned int cmd,
+	unsigned long arg)
+{
+	/* We do support interrupts, they're generated
+	 * using the sysfs interface.
+	 */
+	switch (cmd) {
+	case RTC_PIE_ON:
+	case RTC_PIE_OFF:
+	case RTC_UIE_ON:
+	case RTC_UIE_OFF:
+	case RTC_AIE_ON:
+	case RTC_AIE_OFF:
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static struct rtc_class_ops test_rtc_ops = {
+	.proc = test_rtc_proc,
+	.read_time = test_rtc_read_time,
+	.set_time = test_rtc_set_time,
+	.read_alarm = test_rtc_read_alarm,
+	.set_alarm = test_rtc_set_alarm,
+	.set_mmss = test_rtc_set_mmss,
+	.ioctl = test_rtc_ioctl,
+};
+
+static ssize_t test_irq_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", 42);
+}
+static ssize_t test_irq_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int retval;
+	struct platform_device *plat_dev = to_platform_device(dev);
+	struct rtc_device *rtc = platform_get_drvdata(plat_dev);
+
+	retval = count;
+	if (strncmp(buf, "tick", 4) == 0)
+		rtc_update_irq(&rtc->class_dev, 1, RTC_PF | RTC_IRQF);
+	else if (strncmp(buf, "alarm", 5) == 0)
+		rtc_update_irq(&rtc->class_dev, 1, RTC_AF | RTC_IRQF);
+	else if (strncmp(buf, "update", 6) == 0)
+		rtc_update_irq(&rtc->class_dev, 1, RTC_UF | RTC_IRQF);
+	else
+		retval = -EINVAL;
+
+	return retval;
+}
+static DEVICE_ATTR(irq, S_IRUGO | S_IWUSR, test_irq_show, test_irq_store);
+
+static int test_probe(struct platform_device *plat_dev)
+{
+	int err;
+	struct rtc_device *rtc = rtc_device_register("test", &plat_dev->dev,
+						&test_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		err = PTR_ERR(rtc);
+		dev_err(&plat_dev->dev,
+			"unable to register the class device\n");
+		return err;
+	}
+	device_create_file(&plat_dev->dev, &dev_attr_irq);
+
+	platform_set_drvdata(plat_dev, rtc);
+
+	return 0;
+}
+
+static int __devexit test_remove(struct platform_device *plat_dev)
+{
+	struct rtc_device *rtc = platform_get_drvdata(plat_dev);
+
+	rtc_device_unregister(rtc);
+	device_remove_file(&plat_dev->dev, &dev_attr_irq);
+
+	return 0;
+}
+
+static struct platform_driver test_drv = {
+	.probe	= test_probe,
+	.remove = __devexit_p(test_remove),
+	.driver = {
+		.name = "rtc-test",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init test_init(void)
+{
+	int err;
+
+	if ((err = platform_driver_register(&test_drv)))
+		return err;
+
+	if ((test0 = platform_device_alloc("rtc-test", 0)) == NULL) {
+		err = -ENOMEM;
+		goto exit_driver_unregister;
+	}
+
+	if ((test1 = platform_device_alloc("rtc-test", 1)) == NULL) {
+		err = -ENOMEM;
+		goto exit_free_test0;
+	}
+
+	if ((err = platform_device_add(test0)))
+		goto exit_free_test1;
+
+	if ((err = platform_device_add(test1)))
+		goto exit_device_unregister;
+
+	return 0;
+
+exit_device_unregister:
+	platform_device_unregister(test0);
+
+exit_free_test1:
+	platform_device_put(test1);
+
+exit_free_test0:
+	platform_device_put(test0);
+
+exit_driver_unregister:
+	platform_driver_unregister(&test_drv);
+	return err;
+}
+
+static void __exit test_exit(void)
+{
+	platform_device_unregister(test0);
+	platform_device_unregister(test1);
+	platform_driver_unregister(&test_drv);
+}
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("RTC test driver/device");
+MODULE_LICENSE("GPL");
+
+module_init(test_init);
+module_exit(test_exit);
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
new file mode 100644
index 0000000..621d17a
--- /dev/null
+++ b/drivers/rtc/rtc-x1205.c
@@ -0,0 +1,619 @@
+/*
+ * An i2c driver for the Xicor/Intersil X1205 RTC
+ * Copyright 2004 Karen Spearel
+ * Copyright 2005 Alessandro Zummo
+ *
+ * please send all reports to:
+ * 	Karen Spearel <kas111 at gmail dot com>
+ *	Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on a lot of other RTC drivers.
+ *
+ * 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/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+
+#define DRV_VERSION "1.0.6"
+
+/* Addresses to scan: none. This chip is located at
+ * 0x6f and uses a two bytes register addressing.
+ * Two bytes need to be written to read a single register,
+ * while most other chips just require one and take the second
+ * one as the data to be written. To prevent corrupting
+ * unknown chips, the user must explicitely set the probe parameter.
+ */
+
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD;
+
+/* offsets into CCR area */
+
+#define CCR_SEC			0
+#define CCR_MIN			1
+#define CCR_HOUR		2
+#define CCR_MDAY		3
+#define CCR_MONTH		4
+#define CCR_YEAR		5
+#define CCR_WDAY		6
+#define CCR_Y2K			7
+
+#define X1205_REG_SR		0x3F	/* status register */
+#define X1205_REG_Y2K		0x37
+#define X1205_REG_DW		0x36
+#define X1205_REG_YR		0x35
+#define X1205_REG_MO		0x34
+#define X1205_REG_DT		0x33
+#define X1205_REG_HR		0x32
+#define X1205_REG_MN		0x31
+#define X1205_REG_SC		0x30
+#define X1205_REG_DTR		0x13
+#define X1205_REG_ATR		0x12
+#define X1205_REG_INT		0x11
+#define X1205_REG_0		0x10
+#define X1205_REG_Y2K1		0x0F
+#define X1205_REG_DWA1		0x0E
+#define X1205_REG_YRA1		0x0D
+#define X1205_REG_MOA1		0x0C
+#define X1205_REG_DTA1		0x0B
+#define X1205_REG_HRA1		0x0A
+#define X1205_REG_MNA1		0x09
+#define X1205_REG_SCA1		0x08
+#define X1205_REG_Y2K0		0x07
+#define X1205_REG_DWA0		0x06
+#define X1205_REG_YRA0		0x05
+#define X1205_REG_MOA0		0x04
+#define X1205_REG_DTA0		0x03
+#define X1205_REG_HRA0		0x02
+#define X1205_REG_MNA0		0x01
+#define X1205_REG_SCA0		0x00
+
+#define X1205_CCR_BASE		0x30	/* Base address of CCR */
+#define X1205_ALM0_BASE		0x00	/* Base address of ALARM0 */
+
+#define X1205_SR_RTCF		0x01	/* Clock failure */
+#define X1205_SR_WEL		0x02	/* Write Enable Latch */
+#define X1205_SR_RWEL		0x04	/* Register Write Enable */
+
+#define X1205_DTR_DTR0		0x01
+#define X1205_DTR_DTR1		0x02
+#define X1205_DTR_DTR2		0x04
+
+#define X1205_HR_MIL		0x80	/* Set in ccr.hour for 24 hr mode */
+
+/* Prototypes */
+static int x1205_attach(struct i2c_adapter *adapter);
+static int x1205_detach(struct i2c_client *client);
+static int x1205_probe(struct i2c_adapter *adapter, int address, int kind);
+
+static struct i2c_driver x1205_driver = {
+	.driver		= {
+		.name	= "x1205",
+	},
+	.id		= I2C_DRIVERID_X1205,
+	.attach_adapter = &x1205_attach,
+	.detach_client	= &x1205_detach,
+};
+
+/*
+ * In the routines that deal directly with the x1205 hardware, we use
+ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
+ * Epoch is initialized as 2000. Time is set to UTC.
+ */
+static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
+				unsigned char reg_base)
+{
+	unsigned char dt_addr[2] = { 0, reg_base };
+
+	unsigned char buf[8];
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 2, dt_addr },	/* setup read ptr */
+		{ client->addr, I2C_M_RD, 8, buf },	/* read date */
+	};
+
+	/* read date registers */
+	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	dev_dbg(&client->dev,
+		"%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
+		"mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
+		__FUNCTION__,
+		buf[0], buf[1], buf[2], buf[3],
+		buf[4], buf[5], buf[6], buf[7]);
+
+	tm->tm_sec = BCD2BIN(buf[CCR_SEC]);
+	tm->tm_min = BCD2BIN(buf[CCR_MIN]);
+	tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
+	tm->tm_mday = BCD2BIN(buf[CCR_MDAY]);
+	tm->tm_mon = BCD2BIN(buf[CCR_MONTH]) - 1; /* mon is 0-11 */
+	tm->tm_year = BCD2BIN(buf[CCR_YEAR])
+			+ (BCD2BIN(buf[CCR_Y2K]) * 100) - 1900;
+	tm->tm_wday = buf[CCR_WDAY];
+
+	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	return 0;
+}
+
+static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
+{
+	static unsigned char sr_addr[2] = { 0, X1205_REG_SR };
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 2, sr_addr },	/* setup read ptr */
+		{ client->addr, I2C_M_RD, 1, sr },	/* read status */
+	};
+
+	/* read status register */
+	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
+				int datetoo, u8 reg_base)
+{
+	int i, xfer;
+	unsigned char buf[8];
+
+	static const unsigned char wel[3] = { 0, X1205_REG_SR,
+						X1205_SR_WEL };
+
+	static const unsigned char rwel[3] = { 0, X1205_REG_SR,
+						X1205_SR_WEL | X1205_SR_RWEL };
+
+	static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 };
+
+	dev_dbg(&client->dev,
+		"%s: secs=%d, mins=%d, hours=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour);
+
+	buf[CCR_SEC] = BIN2BCD(tm->tm_sec);
+	buf[CCR_MIN] = BIN2BCD(tm->tm_min);
+
+	/* set hour and 24hr bit */
+	buf[CCR_HOUR] = BIN2BCD(tm->tm_hour) | X1205_HR_MIL;
+
+	/* should we also set the date? */
+	if (datetoo) {
+		dev_dbg(&client->dev,
+			"%s: mday=%d, mon=%d, year=%d, wday=%d\n",
+			__FUNCTION__,
+			tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+		buf[CCR_MDAY] = BIN2BCD(tm->tm_mday);
+
+		/* month, 1 - 12 */
+		buf[CCR_MONTH] = BIN2BCD(tm->tm_mon + 1);
+
+		/* year, since the rtc epoch*/
+		buf[CCR_YEAR] = BIN2BCD(tm->tm_year % 100);
+		buf[CCR_WDAY] = tm->tm_wday & 0x07;
+		buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100);
+	}
+
+	/* this sequence is required to unlock the chip */
+	if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
+		dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer);
+		return -EIO;
+	}
+
+	if ((xfer = i2c_master_send(client, rwel, 3)) != 3) {
+		dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer);
+		return -EIO;
+	}
+
+	/* write register's data */
+	for (i = 0; i < (datetoo ? 8 : 3); i++) {
+		unsigned char rdata[3] = { 0, reg_base + i, buf[i] };
+
+		xfer = i2c_master_send(client, rdata, 3);
+		if (xfer != 3) {
+			dev_err(&client->dev,
+				"%s: xfer=%d addr=%02x, data=%02x\n",
+				__FUNCTION__,
+				 xfer, rdata[1], rdata[2]);
+			return -EIO;
+		}
+	};
+
+	/* disable further writes */
+	if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
+		dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int x1205_fix_osc(struct i2c_client *client)
+{
+	int err;
+	struct rtc_time tm;
+
+	tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+
+	if ((err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE)) < 0)
+		dev_err(&client->dev,
+			"unable to restart the oscillator\n");
+
+	return err;
+}
+
+static int x1205_get_dtrim(struct i2c_client *client, int *trim)
+{
+	unsigned char dtr;
+	static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR };
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 2, dtr_addr },	/* setup read ptr */
+		{ client->addr, I2C_M_RD, 1, &dtr }, 	/* read dtr */
+	};
+
+	/* read dtr register */
+	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	dev_dbg(&client->dev, "%s: raw dtr=%x\n", __FUNCTION__, dtr);
+
+	*trim = 0;
+
+	if (dtr & X1205_DTR_DTR0)
+		*trim += 20;
+
+	if (dtr & X1205_DTR_DTR1)
+		*trim += 10;
+
+	if (dtr & X1205_DTR_DTR2)
+		*trim = -*trim;
+
+	return 0;
+}
+
+static int x1205_get_atrim(struct i2c_client *client, int *trim)
+{
+	s8 atr;
+	static unsigned char atr_addr[2] = { 0, X1205_REG_ATR };
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 2, atr_addr },	/* setup read ptr */
+		{ client->addr, I2C_M_RD, 1, &atr }, 	/* read atr */
+	};
+
+	/* read atr register */
+	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	dev_dbg(&client->dev, "%s: raw atr=%x\n", __FUNCTION__, atr);
+
+	/* atr is a two's complement value on 6 bits,
+	 * perform sign extension. The formula is
+	 * Catr = (atr * 0.25pF) + 11.00pF.
+	 */
+	if (atr & 0x20)
+		atr |= 0xC0;
+
+	dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __FUNCTION__, atr, atr);
+
+	*trim = (atr * 250) + 11000;
+
+	dev_dbg(&client->dev, "%s: real=%d\n", __FUNCTION__, *trim);
+
+	return 0;
+}
+
+struct x1205_limit
+{
+	unsigned char reg, mask, min, max;
+};
+
+static int x1205_validate_client(struct i2c_client *client)
+{
+	int i, xfer;
+
+	/* Probe array. We will read the register at the specified
+	 * address and check if the given bits are zero.
+	 */
+	static const unsigned char probe_zero_pattern[] = {
+		/* register, mask */
+		X1205_REG_SR,	0x18,
+		X1205_REG_DTR,	0xF8,
+		X1205_REG_ATR,	0xC0,
+		X1205_REG_INT,	0x18,
+		X1205_REG_0,	0xFF,
+	};
+
+	static const struct x1205_limit probe_limits_pattern[] = {
+		/* register, mask, min, max */
+		{ X1205_REG_Y2K,	0xFF,	19,	20	},
+		{ X1205_REG_DW,		0xFF,	0,	6	},
+		{ X1205_REG_YR,		0xFF,	0,	99	},
+		{ X1205_REG_MO,		0xFF,	0,	12	},
+		{ X1205_REG_DT,		0xFF,	0,	31	},
+		{ X1205_REG_HR,		0x7F,	0,	23	},
+		{ X1205_REG_MN,		0xFF,	0,	59	},
+		{ X1205_REG_SC,		0xFF,	0,	59	},
+		{ X1205_REG_Y2K1,	0xFF,	19,	20	},
+		{ X1205_REG_Y2K0,	0xFF,	19,	20	},
+	};
+
+	/* check that registers have bits a 0 where expected */
+	for (i = 0; i < ARRAY_SIZE(probe_zero_pattern); i += 2) {
+		unsigned char buf;
+
+		unsigned char addr[2] = { 0, probe_zero_pattern[i] };
+
+		struct i2c_msg msgs[2] = {
+			{ client->addr, 0, 2, addr },
+			{ client->addr, I2C_M_RD, 1, &buf },
+		};
+
+		if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
+			dev_err(&client->adapter->dev,
+				"%s: could not read register %x\n",
+				__FUNCTION__, probe_zero_pattern[i]);
+
+			return -EIO;
+		}
+
+		if ((buf & probe_zero_pattern[i+1]) != 0) {
+			dev_err(&client->adapter->dev,
+				"%s: register=%02x, zero pattern=%d, value=%x\n",
+				__FUNCTION__, probe_zero_pattern[i], i, buf);
+
+			return -ENODEV;
+		}
+	}
+
+	/* check limits (only registers with bcd values) */
+	for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) {
+		unsigned char reg, value;
+
+		unsigned char addr[2] = { 0, probe_limits_pattern[i].reg };
+
+		struct i2c_msg msgs[2] = {
+			{ client->addr, 0, 2, addr },
+			{ client->addr, I2C_M_RD, 1, &reg },
+		};
+
+		if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
+			dev_err(&client->adapter->dev,
+				"%s: could not read register %x\n",
+				__FUNCTION__, probe_limits_pattern[i].reg);
+
+			return -EIO;
+		}
+
+		value = BCD2BIN(reg & probe_limits_pattern[i].mask);
+
+		if (value > probe_limits_pattern[i].max ||
+			value < probe_limits_pattern[i].min) {
+			dev_dbg(&client->adapter->dev,
+				"%s: register=%x, lim pattern=%d, value=%d\n",
+				__FUNCTION__, probe_limits_pattern[i].reg,
+				i, value);
+
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	return x1205_get_datetime(to_i2c_client(dev),
+		&alrm->time, X1205_ALM0_BASE);
+}
+
+static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	return x1205_set_datetime(to_i2c_client(dev),
+		&alrm->time, 1, X1205_ALM0_BASE);
+}
+
+static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return x1205_get_datetime(to_i2c_client(dev),
+		tm, X1205_CCR_BASE);
+}
+
+static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return x1205_set_datetime(to_i2c_client(dev),
+		tm, 1, X1205_CCR_BASE);
+}
+
+static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	int err, dtrim, atrim;
+
+	seq_printf(seq, "24hr\t\t: yes\n");
+
+	if ((err = x1205_get_dtrim(to_i2c_client(dev), &dtrim)) == 0)
+		seq_printf(seq, "digital_trim\t: %d ppm\n", dtrim);
+
+	if ((err = x1205_get_atrim(to_i2c_client(dev), &atrim)) == 0)
+		seq_printf(seq, "analog_trim\t: %d.%02d pF\n",
+			atrim / 1000, atrim % 1000);
+	return 0;
+}
+
+static struct rtc_class_ops x1205_rtc_ops = {
+	.proc		= x1205_rtc_proc,
+	.read_time	= x1205_rtc_read_time,
+	.set_time	= x1205_rtc_set_time,
+	.read_alarm	= x1205_rtc_read_alarm,
+	.set_alarm	= x1205_rtc_set_alarm,
+};
+
+static ssize_t x1205_sysfs_show_atrim(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int atrim;
+
+	if (x1205_get_atrim(to_i2c_client(dev), &atrim) == 0)
+		return sprintf(buf, "%d.%02d pF\n",
+			atrim / 1000, atrim % 1000);
+	return 0;
+}
+static DEVICE_ATTR(atrim, S_IRUGO, x1205_sysfs_show_atrim, NULL);
+
+static ssize_t x1205_sysfs_show_dtrim(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int dtrim;
+
+	if (x1205_get_dtrim(to_i2c_client(dev), &dtrim) == 0)
+		return sprintf(buf, "%d ppm\n", dtrim);
+
+	return 0;
+}
+static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL);
+
+static int x1205_attach(struct i2c_adapter *adapter)
+{
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+	return i2c_probe(adapter, &addr_data, x1205_probe);
+}
+
+static int x1205_probe(struct i2c_adapter *adapter, int address, int kind)
+{
+	int err = 0;
+	unsigned char sr;
+	struct i2c_client *client;
+	struct rtc_device *rtc;
+
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	/* I2C client */
+	client->addr = address;
+	client->driver = &x1205_driver;
+	client->adapter	= adapter;
+
+	strlcpy(client->name, x1205_driver.driver.name, I2C_NAME_SIZE);
+
+	/* Verify the chip is really an X1205 */
+	if (kind < 0) {
+		if (x1205_validate_client(client) < 0) {
+			err = -ENODEV;
+			goto exit_kfree;
+		}
+	}
+
+	/* Inform the i2c layer */
+	if ((err = i2c_attach_client(client)))
+		goto exit_kfree;
+
+	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+	rtc = rtc_device_register(x1205_driver.driver.name, &client->dev,
+				&x1205_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		err = PTR_ERR(rtc);
+		dev_err(&client->dev,
+			"unable to register the class device\n");
+		goto exit_detach;
+	}
+
+	i2c_set_clientdata(client, rtc);
+
+	/* Check for power failures and eventualy enable the osc */
+	if ((err = x1205_get_status(client, &sr)) == 0) {
+		if (sr & X1205_SR_RTCF) {
+			dev_err(&client->dev,
+				"power failure detected, "
+				"please set the clock\n");
+			udelay(50);
+			x1205_fix_osc(client);
+		}
+	}
+	else
+		dev_err(&client->dev, "couldn't read status\n");
+
+	device_create_file(&client->dev, &dev_attr_atrim);
+	device_create_file(&client->dev, &dev_attr_dtrim);
+
+	return 0;
+
+exit_detach:
+	i2c_detach_client(client);
+
+exit_kfree:
+	kfree(client);
+
+exit:
+	return err;
+}
+
+static int x1205_detach(struct i2c_client *client)
+{
+	int err;
+	struct rtc_device *rtc = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "%s\n", __FUNCTION__);
+
+ 	if (rtc)
+		rtc_device_unregister(rtc);
+
+	if ((err = i2c_detach_client(client)))
+		return err;
+
+	kfree(client);
+
+	return 0;
+}
+
+static int __init x1205_init(void)
+{
+	return i2c_add_driver(&x1205_driver);
+}
+
+static void __exit x1205_exit(void)
+{
+	i2c_del_driver(&x1205_driver);
+}
+
+MODULE_AUTHOR(
+	"Karen Spearel <kas111 at gmail dot com>, "
+	"Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("Xicor/Intersil X1205 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(x1205_init);
+module_exit(x1205_exit);
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 2f72010..c1c6f13 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -437,8 +437,7 @@
 	spin_lock(&dasd_devmap_lock);
 	for (i = 0; i < 256; i++) {
 		list_for_each_entry_safe(devmap, n, &dasd_hashlists[i], list) {
-			if (devmap->device != NULL)
-				BUG();
+			BUG_ON(devmap->device != NULL);
 			list_del(&devmap->list);
 			kfree(devmap);
 		}
@@ -547,8 +546,7 @@
 
 	/* First remove device pointer from devmap. */
 	devmap = dasd_find_busid(device->cdev->dev.bus_id);
-	if (IS_ERR(devmap))
-		BUG();
+	BUG_ON(IS_ERR(devmap));
 	spin_lock(&dasd_devmap_lock);
 	if (devmap->device != device) {
 		spin_unlock(&dasd_devmap_lock);
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index bd06607..eecb2af 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -28,6 +28,7 @@
 #include <linux/major.h>
 #include <linux/kdev_t.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 
 struct class *class3270;
 
@@ -59,7 +60,7 @@
 #define RAW3270_FLAGS_CONSOLE	8	/* Device is the console. */
 
 /* Semaphore to protect global data of raw3270 (devices, views, etc). */
-static DECLARE_MUTEX(raw3270_sem);
+static DEFINE_MUTEX(raw3270_mutex);
 
 /* List of 3270 devices. */
 static struct list_head raw3270_devices = LIST_HEAD_INIT(raw3270_devices);
@@ -815,7 +816,7 @@
 	 * number for it. Note: there is no device with minor 0,
 	 * see special case for fs3270.c:fs3270_open().
 	 */
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	/* Keep the list sorted. */
 	minor = RAW3270_FIRSTMINOR;
 	rp->minor = -1;
@@ -832,7 +833,7 @@
 		rp->minor = minor;
 		list_add_tail(&rp->list, &raw3270_devices);
 	}
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 	/* No free minor number? Then give up. */
 	if (rp->minor == -1)
 		return -EUSERS;
@@ -1003,7 +1004,7 @@
 
 	if (minor <= 0)
 		return -ENODEV;
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	rc = -ENODEV;
 	list_for_each_entry(rp, &raw3270_devices, list) {
 		if (rp->minor != minor)
@@ -1024,7 +1025,7 @@
 		spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
 		break;
 	}
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 	return rc;
 }
 
@@ -1038,7 +1039,7 @@
 	struct raw3270_view *view, *tmp;
 	unsigned long flags;
 
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	view = ERR_PTR(-ENODEV);
 	list_for_each_entry(rp, &raw3270_devices, list) {
 		if (rp->minor != minor)
@@ -1057,7 +1058,7 @@
 		spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
 		break;
 	}
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 	return view;
 }
 
@@ -1104,7 +1105,7 @@
 	struct ccw_device *cdev;
 
 	/* Remove from device chain. */
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	if (rp->clttydev)
 		class_device_destroy(class3270,
 				     MKDEV(IBM_TTY3270_MAJOR, rp->minor));
@@ -1112,7 +1113,7 @@
 		class_device_destroy(class3270,
 				     MKDEV(IBM_FS3270_MAJOR, rp->minor));
 	list_del_init(&rp->list);
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 
 	/* Disconnect from ccw_device. */
 	cdev = rp->cdev;
@@ -1208,13 +1209,13 @@
 	if (!np)
 		return -ENOMEM;
 	np->notifier = notifier;
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	list_add_tail(&np->list, &raw3270_notifier);
 	list_for_each_entry(rp, &raw3270_devices, list) {
 		get_device(&rp->cdev->dev);
 		notifier(rp->minor, 1);
 	}
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 	return 0;
 }
 
@@ -1222,14 +1223,14 @@
 {
 	struct raw3270_notifier *np;
 
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	list_for_each_entry(np, &raw3270_notifier, list)
 		if (np->notifier == notifier) {
 			list_del(&np->list);
 			kfree(np);
 			break;
 		}
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 }
 
 /*
@@ -1256,10 +1257,10 @@
 		goto failure;
 	raw3270_create_attributes(rp);
 	set_bit(RAW3270_FLAGS_READY, &rp->flags);
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	list_for_each_entry(np, &raw3270_notifier, list)
 		np->notifier(rp->minor, 1);
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 	return 0;
 
 failure:
@@ -1307,10 +1308,10 @@
 	}
 	spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
 
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	list_for_each_entry(np, &raw3270_notifier, list)
 		np->notifier(rp->minor, 0);
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 
 	/* Reset 3270 device. */
 	raw3270_reset_device(rp);
@@ -1370,13 +1371,13 @@
 	rc = ccw_driver_register(&raw3270_ccw_driver);
 	if (rc == 0) {
 		/* Create attributes for early (= console) device. */
-		down(&raw3270_sem);
+		mutex_lock(&raw3270_mutex);
 		class3270 = class_create(THIS_MODULE, "3270");
 		list_for_each_entry(rp, &raw3270_devices, list) {
 			get_device(&rp->cdev->dev);
 			raw3270_create_attributes(rp);
 		}
-		up(&raw3270_sem);
+		mutex_unlock(&raw3270_mutex);
 	}
 	return rc;
 }
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 95b92f3..395cfc6 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -829,18 +829,6 @@
 	device_unregister(&unit->sysfs_device);
 }
 
-static void *
-zfcp_mempool_alloc(gfp_t gfp_mask, void *size)
-{
-	return kmalloc((size_t) size, gfp_mask);
-}
-
-static void
-zfcp_mempool_free(void *element, void *size)
-{
-	kfree(element);
-}
-
 /*
  * Allocates a combined QTCB/fsf_req buffer for erp actions and fcp/SCSI
  * commands.
@@ -853,51 +841,39 @@
 zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
 {
 	adapter->pool.fsf_req_erp =
-		mempool_create(ZFCP_POOL_FSF_REQ_ERP_NR,
-			       zfcp_mempool_alloc, zfcp_mempool_free, (void *)
-			       sizeof(struct zfcp_fsf_req_pool_element));
-
-	if (NULL == adapter->pool.fsf_req_erp)
+		mempool_create_kmalloc_pool(ZFCP_POOL_FSF_REQ_ERP_NR,
+				sizeof(struct zfcp_fsf_req_pool_element));
+	if (!adapter->pool.fsf_req_erp)
 		return -ENOMEM;
 
 	adapter->pool.fsf_req_scsi =
-		mempool_create(ZFCP_POOL_FSF_REQ_SCSI_NR,
-			       zfcp_mempool_alloc, zfcp_mempool_free, (void *)
-			       sizeof(struct zfcp_fsf_req_pool_element));
-
-	if (NULL == adapter->pool.fsf_req_scsi)
+		mempool_create_kmalloc_pool(ZFCP_POOL_FSF_REQ_SCSI_NR,
+				sizeof(struct zfcp_fsf_req_pool_element));
+	if (!adapter->pool.fsf_req_scsi)
 		return -ENOMEM;
 
 	adapter->pool.fsf_req_abort =
-		mempool_create(ZFCP_POOL_FSF_REQ_ABORT_NR,
-			       zfcp_mempool_alloc, zfcp_mempool_free, (void *)
-			       sizeof(struct zfcp_fsf_req_pool_element));
-
-	if (NULL == adapter->pool.fsf_req_abort)
+		mempool_create_kmalloc_pool(ZFCP_POOL_FSF_REQ_ABORT_NR,
+				sizeof(struct zfcp_fsf_req_pool_element));
+	if (!adapter->pool.fsf_req_abort)
 		return -ENOMEM;
 
 	adapter->pool.fsf_req_status_read =
-		mempool_create(ZFCP_POOL_STATUS_READ_NR,
-			       zfcp_mempool_alloc, zfcp_mempool_free,
-			       (void *) sizeof(struct zfcp_fsf_req));
-
-	if (NULL == adapter->pool.fsf_req_status_read)
+		mempool_create_kmalloc_pool(ZFCP_POOL_STATUS_READ_NR,
+					    sizeof(struct zfcp_fsf_req));
+	if (!adapter->pool.fsf_req_status_read)
 		return -ENOMEM;
 
 	adapter->pool.data_status_read =
-		mempool_create(ZFCP_POOL_STATUS_READ_NR,
-			       zfcp_mempool_alloc, zfcp_mempool_free,
-			       (void *) sizeof(struct fsf_status_read_buffer));
-
-	if (NULL == adapter->pool.data_status_read)
+		mempool_create_kmalloc_pool(ZFCP_POOL_STATUS_READ_NR,
+					sizeof(struct fsf_status_read_buffer));
+	if (!adapter->pool.data_status_read)
 		return -ENOMEM;
 
 	adapter->pool.data_gid_pn =
-		mempool_create(ZFCP_POOL_DATA_GID_PN_NR,
-			       zfcp_mempool_alloc, zfcp_mempool_free, (void *)
-			       sizeof(struct zfcp_gid_pn_data));
-
-	if (NULL == adapter->pool.data_gid_pn)
+		mempool_create_kmalloc_pool(ZFCP_POOL_DATA_GID_PN_NR,
+					    sizeof(struct zfcp_gid_pn_data));
+	if (!adapter->pool.data_gid_pn)
 		return -ENOMEM;
 
 	return 0;
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 0ab26d0..0d2b447 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -1026,7 +1026,7 @@
 	tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
 } /* End twa_free_request_id() */
 
-/* This function will get parameter table entires from the firmware */
+/* This function will get parameter table entries from the firmware */
 static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes)
 {
 	TW_Command_Full *full_command_packet;
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 1c45934..bde3d58 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -41,6 +41,8 @@
 #include <linux/stat.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
+#include <linux/jiffies.h>
+#include <linux/dma-mapping.h>
 #include <scsi/scsicam.h>
 
 #include <asm/dma.h>
@@ -676,7 +678,7 @@
 		if (pci_enable_device(PCI_Device))
 			continue;
 
-		if (pci_set_dma_mask(PCI_Device, (u64) 0xffffffff))
+		if (pci_set_dma_mask(PCI_Device, DMA_32BIT_MASK ))
 			continue;
 
 		Bus = PCI_Device->bus->number;
@@ -831,7 +833,7 @@
 		if (pci_enable_device(PCI_Device))
 			continue;
 
-		if (pci_set_dma_mask(PCI_Device, (u64) 0xffffffff))
+		if (pci_set_dma_mask(PCI_Device, DMA_32BIT_MASK))
 			continue;
 
 		Bus = PCI_Device->bus->number;
@@ -885,7 +887,7 @@
 		if (pci_enable_device(PCI_Device))
 			continue;
 
-		if (pci_set_dma_mask(PCI_Device, (u64) 0xffffffff))
+		if (pci_set_dma_mask(PCI_Device, DMA_32BIT_MASK))
 			continue;
 
 		Bus = PCI_Device->bus->number;
@@ -2896,7 +2898,7 @@
 		 */
 		if (HostAdapter->ActiveCommands[TargetID] == 0)
 			HostAdapter->LastSequencePoint[TargetID] = jiffies;
-		else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 4 * HZ) {
+		else if (time_after(jiffies, HostAdapter->LastSequencePoint[TargetID] + 4 * HZ)) {
 			HostAdapter->LastSequencePoint[TargetID] = jiffies;
 			QueueTag = BusLogic_OrderedQueueTag;
 		}
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index 9f45ae1..3dce21c 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -89,6 +89,7 @@
 #include <linux/string.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -1052,7 +1053,7 @@
 
 	if (pci_enable_device(pdev))
 		goto out;
-	if (pci_set_dma_mask(pdev, 0xffffffffULL)) {
+	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
 		printk(KERN_WARNING "Unable to set 32bit DMA "
 				    "on inia100 adapter, ignoring.\n");
 		goto out_disable_device;
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index a16f8de..8df4a0e 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/completion.h>
 #include <linux/blkdev.h>
+#include <linux/dma-mapping.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index c259633..7203307 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -45,6 +45,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
 #include <linux/syscalls.h>
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
@@ -806,8 +807,8 @@
 	 * to driver communication memory to be allocated below 2gig
 	 */
 	if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) 
-		if (pci_set_dma_mask(pdev, 0x7FFFFFFFULL) ||
-				pci_set_consistent_dma_mask(pdev, 0x7FFFFFFFULL))
+		if (pci_set_dma_mask(pdev, DMA_31BIT_MASK) ||
+				pci_set_consistent_dma_mask(pdev, DMA_31BIT_MASK))
 			goto out;
 	
 	pci_set_master(pdev);
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index ffba656..1bd82c4 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -293,6 +293,10 @@
 	  board_ahci }, /* JMicron JMB360 */
 	{ 0x197b, 0x2363, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_ahci }, /* JMicron JMB363 */
+	{ PCI_VENDOR_ID_ATI, 0x4380, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ATI SB600 non-raid */
+	{ PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ATI SB600 raid */
 	{ }	/* terminate list */
 };
 
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 2d5be84..24e71b5 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -301,7 +301,7 @@
 	.mask = 0x3,
 	.map = {
 		/* PM   PS   SM   SS       MAP */
-		{  P0,  P1,  P2,  P3 }, /* 00b */
+		{  P0,  P2,  P1,  P3 }, /* 00b */
 		{ IDE, IDE,  P1,  P3 }, /* 01b */
 		{  P0,  P2, IDE, IDE }, /* 10b */
 		{  RV,  RV,  RV,  RV },
@@ -312,7 +312,7 @@
 	.mask = 0x3,
 	.map = {
 		/* PM   PS   SM   SS       MAP */
-		{  P0,  P1,  P2,  P3 }, /* 00b */
+		{  P0,  P2,  RV,  RV }, /* 00b */
 		{  RV,  RV,  RV,  RV },
 		{  P0,  P2, IDE, IDE }, /* 10b */
 		{  RV,  RV,  RV,  RV },
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 5227a77..a198d86 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -28,6 +28,7 @@
 #include <linux/spinlock.h>
 #include <linux/pci.h>
 #include <linux/blkdev.h>
+#include <linux/dma-mapping.h>
 #include <asm/system.h>
 #include <asm/io.h>
 
@@ -2631,7 +2632,7 @@
 	if (pci_enable_device(pdev))
 		return -EIO;
 
-        if (!pci_set_dma_mask(pdev, 0xFFFFFFFFUL)) {
+        if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
                 printk(KERN_INFO "atp870u: use 32bit DMA mask.\n");
         } else {
                 printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 6e6b293..b1b704a 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -57,6 +57,7 @@
 #include <linux/reboot.h>
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
+#include <linux/dma-mapping.h>
 
 #include <linux/timer.h>
 #include <linux/string.h>
@@ -906,8 +907,8 @@
 	}
 
 	pci_set_master(pDev);
-	if (pci_set_dma_mask(pDev, 0xffffffffffffffffULL) &&
-	    pci_set_dma_mask(pDev, 0xffffffffULL))
+	if (pci_set_dma_mask(pDev, DMA_64BIT_MASK) &&
+	    pci_set_dma_mask(pDev, DMA_32BIT_MASK))
 		return -EINVAL;
 
 	base_addr0_phys = pci_resource_start(pDev,0);
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index b3f9de8..059eeee 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -490,6 +490,7 @@
 #include <linux/init.h>
 #include <linux/ctype.h>
 #include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
 #include <asm/byteorder.h>
 #include <asm/dma.h>
 #include <asm/io.h>
@@ -1426,7 +1427,7 @@
 
 	if (ha->pdev) {
 		pci_set_master(ha->pdev);
-		if (pci_set_dma_mask(ha->pdev, 0xffffffff))
+		if (pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK))
 			printk("%s: warning, pci_set_dma_mask failed.\n",
 			       ha->board_name);
 	}
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 62e3cda..d5740bb 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -388,6 +388,7 @@
 #include <linux/proc_fs.h>
 #include <linux/time.h>
 #include <linux/timer.h>
+#include <linux/dma-mapping.h>
 #ifdef GDTH_RTC
 #include <linux/mc146818rtc.h>
 #endif
@@ -671,7 +672,7 @@
 static struct notifier_block gdth_notifier = {
     gdth_halt, NULL, 0
 };
-
+static int notifier_disabled = 0;
 
 static void gdth_delay(int milliseconds)
 {
@@ -4527,15 +4528,15 @@
             if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat &GDT_64BIT)||
                 /* 64-bit DMA only supported from FW >= x.43 */
                 (!ha->dma64_support)) {
-                if (pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffff)) {
+                if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
                     printk(KERN_WARNING "GDT-PCI %d: Unable to set 32-bit DMA\n", hanum);
                     err = TRUE;
                 }
             } else {
                 shp->max_cmd_len = 16;
-                if (!pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffffffffffffULL)) {
+                if (!pci_set_dma_mask(pcistr[ctr].pdev, DMA_64BIT_MASK)) {
                     printk("GDT-PCI %d: 64-bit DMA enabled\n", hanum);
-                } else if (pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffff)) {
+                } else if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
                     printk(KERN_WARNING "GDT-PCI %d: Unable to set 64/32-bit DMA\n", hanum);
                     err = TRUE;
                 }
@@ -4595,13 +4596,13 @@
         add_timer(&gdth_timer);
 #endif
         major = register_chrdev(0,"gdth",&gdth_fops);
+        notifier_disabled = 0;
         register_reboot_notifier(&gdth_notifier);
     }
     gdth_polling = FALSE;
     return gdth_ctr_vcount;
 }
 
-
 static int gdth_release(struct Scsi_Host *shp)
 {
     int hanum;
@@ -5632,10 +5633,14 @@
     char            cmnd[MAX_COMMAND_SIZE];   
 #endif
 
+    if (notifier_disabled)
+    	return NOTIFY_OK;
+
     TRACE2(("gdth_halt() event %d\n",(int)event));
     if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF)
         return NOTIFY_DONE;
 
+    notifier_disabled = 1;
     printk("GDT-HA: Flushing all host drives .. ");
     for (hanum = 0; hanum < gdth_ctr_count; ++hanum) {
         gdth_flush(hanum);
@@ -5679,7 +5684,6 @@
 #ifdef GDTH_STATISTICS
     del_timer(&gdth_timer);
 #endif
-    unregister_reboot_notifier(&gdth_notifier);
     return NOTIFY_OK;
 }
 
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 3a8462e..24eb59e 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -2488,7 +2488,7 @@
 	}
 	ints[0] = i - 1;
 	internal_ibmmca_scsi_setup(cur, ints);
-	return 0;
+	return 1;
 }
 
 __setup("ibmmcascsi=", option_setup);
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index ea6f3c0..0cc7f65 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -127,6 +127,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
+#include <linux/dma-mapping.h>
 #include <asm/io.h>
 
 #include <scsi/scsi.h>
@@ -2780,7 +2781,7 @@
 			if (((dRegValue & 0xFF00) >> 8) == 0xFF)
 				dRegValue = 0;
 			wBIOS = (wBIOS << 8) + ((UWORD) ((dRegValue & 0xFF00) >> 8));
-			if (pci_set_dma_mask(pDev, 0xffffffff)) {
+			if (pci_set_dma_mask(pDev, DMA_32BIT_MASK)) {
 				printk(KERN_WARNING 
 				       "i91u: Could not set 32 bit DMA mask\n");
 				continue;
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 481708d..a4c0b04 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -179,6 +179,7 @@
 
 #include <linux/blkdev.h>
 #include <linux/types.h>
+#include <linux/dma-mapping.h>
 
 #include <scsi/sg.h>
 
@@ -7284,10 +7285,10 @@
 	 * are guaranteed to be < 4G.
 	 */
 	if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) &&
-	    !pci_set_dma_mask(ha->pcidev, 0xffffffffffffffffULL)) {
+	    !pci_set_dma_mask(ha->pcidev, DMA_64BIT_MASK)) {
 		(ha)->flags |= IPS_HA_ENH_SG;
 	} else {
-		if (pci_set_dma_mask(ha->pcidev, 0xffffffffULL) != 0) {
+		if (pci_set_dma_mask(ha->pcidev, DMA_32BIT_MASK) != 0) {
 			printk(KERN_WARNING "Unable to set DMA Mask\n");
 			return ips_abort_init(ha, index);
 		}
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 7b82ff0..2068b66 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -3200,8 +3200,8 @@
 		 * Data-Out PDU's within R2T-sequence can be quite big;
 		 * using mempool
 		 */
-		ctask->datapool = mempool_create(ISCSI_DTASK_DEFAULT_MAX,
-			 mempool_alloc_slab, mempool_free_slab, taskcache);
+		ctask->datapool = mempool_create_slab_pool(ISCSI_DTASK_DEFAULT_MAX,
+							   taskcache);
 		if (ctask->datapool == NULL) {
 			kfifo_free(ctask->r2tqueue);
 			iscsi_pool_free(&ctask->r2tpool, (void**)ctask->r2ts);
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
index 459a4da..eb7bd31 100644
--- a/drivers/scsi/lasi700.c
+++ b/drivers/scsi/lasi700.c
@@ -112,7 +112,7 @@
 
 	hostdata->dev = &dev->dev;
 	dma_set_mask(&dev->dev, DMA_32BIT_MASK);
-	hostdata->base = ioremap(base, 0x100);
+	hostdata->base = ioremap_nocache(base, 0x100);
 	hostdata->differential = 0;
 
 	if (dev->id.sversion == LASI_700_SVERSION) {
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
index 95d81d8..835dff0 100644
--- a/drivers/scsi/libata-bmdma.c
+++ b/drivers/scsi/libata-bmdma.c
@@ -703,6 +703,7 @@
 	struct ata_probe_ent *probe_ent =
 		ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
 	int p = 0;
+	unsigned long bmdma;
 
 	if (!probe_ent)
 		return NULL;
@@ -716,7 +717,12 @@
 		probe_ent->port[p].altstatus_addr =
 		probe_ent->port[p].ctl_addr =
 			pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
-		probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4);
+		bmdma = pci_resource_start(pdev, 4);
+		if (bmdma) {
+			if (inb(bmdma + 2) & 0x80)
+				probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+			probe_ent->port[p].bmdma_addr = bmdma;
+		}
 		ata_std_ports(&probe_ent->port[p]);
 		p++;
 	}
@@ -726,7 +732,13 @@
 		probe_ent->port[p].altstatus_addr =
 		probe_ent->port[p].ctl_addr =
 			pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
-		probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8;
+		bmdma = pci_resource_start(pdev, 4);
+		if (bmdma) {
+			bmdma += 8;
+			if(inb(bmdma + 2) & 0x80)
+			probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+			probe_ent->port[p].bmdma_addr = bmdma;
+		}
 		ata_std_ports(&probe_ent->port[p]);
 		p++;
 	}
@@ -740,6 +752,7 @@
 				struct ata_port_info *port, int port_num)
 {
 	struct ata_probe_ent *probe_ent;
+	unsigned long bmdma;
 
 	probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port);
 	if (!probe_ent)
@@ -766,8 +779,13 @@
 			break;
 	}
 
-	probe_ent->port[0].bmdma_addr =
-		pci_resource_start(pdev, 4) + 8 * port_num;
+	bmdma = pci_resource_start(pdev, 4);
+	if (bmdma != 0) {
+		bmdma += 8 * port_num;
+		probe_ent->port[0].bmdma_addr = bmdma;
+		if (inb(bmdma + 2) & 0x80)
+			probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+	}
 	ata_std_ports(&probe_ent->port[0]);
 
 	return probe_ent;
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index d279666..e63c1ff 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -62,7 +62,9 @@
 #include "libata.h"
 
 static unsigned int ata_dev_init_params(struct ata_port *ap,
-					struct ata_device *dev);
+					struct ata_device *dev,
+					u16 heads,
+					u16 sectors);
 static void ata_set_mode(struct ata_port *ap);
 static unsigned int ata_dev_set_xfermode(struct ata_port *ap,
 					 struct ata_device *dev);
@@ -276,7 +278,7 @@
 }
 
 static const struct ata_xfer_ent {
-	unsigned int shift, bits;
+	int shift, bits;
 	u8 base;
 } ata_xfer_tbl[] = {
 	{ ATA_SHIFT_PIO, ATA_BITS_PIO, XFER_PIO_0 },
@@ -987,9 +989,7 @@
 	qc->private_data = &wait;
 	qc->complete_fn = ata_qc_complete_internal;
 
-	qc->err_mask = ata_qc_issue(qc);
-	if (qc->err_mask)
-		ata_qc_complete(qc);
+	ata_qc_issue(qc);
 
 	spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
@@ -1081,9 +1081,8 @@
  *
  *	Read ID data from the specified device.  ATA_CMD_ID_ATA is
  *	performed on ATA devices and ATA_CMD_ID_ATAPI on ATAPI
- *	devices.  This function also takes care of EDD signature
- *	misreporting (to be removed once EDD support is gone) and
- *	issues ATA_CMD_INIT_DEV_PARAMS for pre-ATA4 drives.
+ *	devices.  This function also issues ATA_CMD_INIT_DEV_PARAMS
+ *	for pre-ATA4 drives.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep)
@@ -1095,7 +1094,6 @@
 			   unsigned int *p_class, int post_reset, u16 **p_id)
 {
 	unsigned int class = *p_class;
-	unsigned int using_edd;
 	struct ata_taskfile tf;
 	unsigned int err_mask = 0;
 	u16 *id;
@@ -1104,12 +1102,6 @@
 
 	DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno);
 
-	if (ap->ops->probe_reset ||
-	    ap->flags & (ATA_FLAG_SRST | ATA_FLAG_SATA_RESET))
-		using_edd = 0;
-	else
-		using_edd = 1;
-
 	ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
 
 	id = kmalloc(sizeof(id[0]) * ATA_ID_WORDS, GFP_KERNEL);
@@ -1139,39 +1131,16 @@
 
 	err_mask = ata_exec_internal(ap, dev, &tf, DMA_FROM_DEVICE,
 				     id, sizeof(id[0]) * ATA_ID_WORDS);
-
 	if (err_mask) {
 		rc = -EIO;
 		reason = "I/O error";
-
-		if (err_mask & ~AC_ERR_DEV)
-			goto err_out;
-
-		/*
-		 * arg!  EDD works for all test cases, but seems to return
-		 * the ATA signature for some ATAPI devices.  Until the
-		 * reason for this is found and fixed, we fix up the mess
-		 * here.  If IDENTIFY DEVICE returns command aborted
-		 * (as ATAPI devices do), then we issue an
-		 * IDENTIFY PACKET DEVICE.
-		 *
-		 * ATA software reset (SRST, the default) does not appear
-		 * to have this problem.
-		 */
-		if ((using_edd) && (class == ATA_DEV_ATA)) {
-			u8 err = tf.feature;
-			if (err & ATA_ABORTED) {
-				class = ATA_DEV_ATAPI;
-				goto retry;
-			}
-		}
 		goto err_out;
 	}
 
 	swap_buf_le16(id, ATA_ID_WORDS);
 
 	/* sanity check */
-	if ((class == ATA_DEV_ATA) != ata_id_is_ata(id)) {
+	if ((class == ATA_DEV_ATA) != (ata_id_is_ata(id) | ata_id_is_cfa(id))) {
 		rc = -EINVAL;
 		reason = "device reports illegal type";
 		goto err_out;
@@ -1187,7 +1156,7 @@
 		 * Some drives were very specific about that exact sequence.
 		 */
 		if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
-			err_mask = ata_dev_init_params(ap, dev);
+			err_mask = ata_dev_init_params(ap, dev, id[3], id[6]);
 			if (err_mask) {
 				rc = -EIO;
 				reason = "INIT_DEV_PARAMS failed";
@@ -1440,7 +1409,11 @@
 	if (!found)
 		goto err_out_disable;
 
-	ata_set_mode(ap);
+	if (ap->ops->set_mode)
+		ap->ops->set_mode(ap);
+	else
+		ata_set_mode(ap);
+
 	if (ap->flags & ATA_FLAG_PORT_DISABLED)
 		goto err_out_disable;
 
@@ -1845,7 +1818,7 @@
  */
 static void ata_set_mode(struct ata_port *ap)
 {
-	int i, rc;
+	int i, rc, used_dma = 0;
 
 	/* step 1: calculate xfer_mask */
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
@@ -1863,6 +1836,9 @@
 		dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
 		dev->pio_mode = ata_xfer_mask2mode(pio_mask);
 		dev->dma_mode = ata_xfer_mask2mode(dma_mask);
+
+		if (dev->dma_mode)
+			used_dma = 1;
 	}
 
 	/* step 2: always set host PIO timings */
@@ -1884,6 +1860,17 @@
 			goto err_out;
 	}
 
+	/*
+	 *	Record simplex status. If we selected DMA then the other
+	 *	host channels are not permitted to do so.
+	 */
+
+	if (used_dma && (ap->host_set->flags & ATA_HOST_SIMPLEX))
+		ap->host_set->simplex_claimed = 1;
+
+	/*
+	 *	Chip specific finalisation
+	 */
 	if (ap->ops->post_set_mode)
 		ap->ops->post_set_mode(ap);
 
@@ -2005,45 +1992,6 @@
 		ap->ops->dev_select(ap, 0);
 }
 
-/**
- *	ata_bus_edd - Issue EXECUTE DEVICE DIAGNOSTIC command.
- *	@ap: Port to reset and probe
- *
- *	Use the EXECUTE DEVICE DIAGNOSTIC command to reset and
- *	probe the bus.  Not often used these days.
- *
- *	LOCKING:
- *	PCI/etc. bus probe sem.
- *	Obtains host_set lock.
- *
- */
-
-static unsigned int ata_bus_edd(struct ata_port *ap)
-{
-	struct ata_taskfile tf;
-	unsigned long flags;
-
-	/* set up execute-device-diag (bus reset) taskfile */
-	/* also, take interrupts to a known state (disabled) */
-	DPRINTK("execute-device-diag\n");
-	ata_tf_init(ap, &tf, 0);
-	tf.ctl |= ATA_NIEN;
-	tf.command = ATA_CMD_EDD;
-	tf.protocol = ATA_PROT_NODATA;
-
-	/* do bus reset */
-	spin_lock_irqsave(&ap->host_set->lock, flags);
-	ata_tf_to_host(ap, &tf);
-	spin_unlock_irqrestore(&ap->host_set->lock, flags);
-
-	/* spec says at least 2ms.  but who knows with those
-	 * crazy ATAPI devices...
-	 */
-	msleep(150);
-
-	return ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
-}
-
 static unsigned int ata_bus_softreset(struct ata_port *ap,
 				      unsigned int devmask)
 {
@@ -2078,13 +2026,12 @@
 	 */
 	msleep(150);
 
-
 	/* Before we perform post reset processing we want to see if
-	   the bus shows 0xFF because the odd clown forgets the D7 pulldown
-	   resistor */
-
+	 * the bus shows 0xFF because the odd clown forgets the D7
+	 * pulldown resistor.
+	 */
 	if (ata_check_status(ap) == 0xFF)
-		return 1;	/* Positive is failure for some reason */
+		return AC_ERR_OTHER;
 
 	ata_bus_post_reset(ap, devmask);
 
@@ -2116,7 +2063,7 @@
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
 	u8 err;
-	unsigned int dev0, dev1 = 0, rc = 0, devmask = 0;
+	unsigned int dev0, dev1 = 0, devmask = 0;
 
 	DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no);
 
@@ -2139,18 +2086,8 @@
 
 	/* issue bus reset */
 	if (ap->flags & ATA_FLAG_SRST)
-		rc = ata_bus_softreset(ap, devmask);
-	else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) {
-		/* set up device control */
-		if (ap->flags & ATA_FLAG_MMIO)
-			writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
-		else
-			outb(ap->ctl, ioaddr->ctl_addr);
-		rc = ata_bus_edd(ap);
-	}
-
-	if (rc)
-		goto err_out;
+		if (ata_bus_softreset(ap, devmask))
+			goto err_out;
 
 	/*
 	 * determine by signature whether we have ATA or ATAPI devices
@@ -2223,9 +2160,9 @@
  *	so makes reset sequence different from the original
  *	->phy_reset implementation and Jeff nervous.  :-P
  */
-extern void ata_std_probeinit(struct ata_port *ap)
+void ata_std_probeinit(struct ata_port *ap)
 {
-	if (ap->flags & ATA_FLAG_SATA && ap->ops->scr_read) {
+	if ((ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read) {
 		sata_phy_resume(ap);
 		if (sata_dev_present(ap))
 			ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
@@ -2714,18 +2651,23 @@
  *	known limits including host controller limits, device
  *	blacklist, etc...
  *
+ *	FIXME: The current implementation limits all transfer modes to
+ *	the fastest of the lowested device on the port.  This is not
+ *	required on most controllers.
+ *
  *	LOCKING:
  *	None.
  */
 static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev)
 {
+	struct ata_host_set *hs = ap->host_set;
 	unsigned long xfer_mask;
 	int i;
 
 	xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
 				      ap->udma_mask);
 
-	/* use port-wide xfermask for now */
+	/* FIXME: Use port-wide xfermask for now */
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		struct ata_device *d = &ap->device[i];
 		if (!ata_dev_present(d))
@@ -2735,12 +2677,23 @@
 		xfer_mask &= ata_id_xfermask(d->id);
 		if (ata_dma_blacklisted(d))
 			xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+		/* Apply cable rule here. Don't apply it early because when
+		   we handle hot plug the cable type can itself change */
+		if (ap->cbl == ATA_CBL_PATA40)
+			xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
 	}
 
 	if (ata_dma_blacklisted(dev))
 		printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, "
 		       "disabling DMA\n", ap->id, dev->devno);
 
+	if (hs->flags & ATA_HOST_SIMPLEX) {
+		if (hs->simplex_claimed)
+			xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+	}
+	if (ap->ops->mode_filter)
+		xfer_mask = ap->ops->mode_filter(ap, dev, xfer_mask);
+
 	ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask,
 			    &dev->udma_mask);
 }
@@ -2795,16 +2748,16 @@
  */
 
 static unsigned int ata_dev_init_params(struct ata_port *ap,
-					struct ata_device *dev)
+					struct ata_device *dev,
+					u16 heads,
+					u16 sectors)
 {
 	struct ata_taskfile tf;
 	unsigned int err_mask;
-	u16 sectors = dev->id[6];
-	u16 heads   = dev->id[3];
 
 	/* Number of sectors per track 1-255. Number of heads 1-16 */
 	if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16)
-		return 0;
+		return AC_ERR_INVALID;
 
 	/* set up init dev params taskfile */
 	DPRINTK("init dev params \n");
@@ -4042,15 +3995,14 @@
  *
  *	LOCKING:
  *	spin_lock_irqsave(host_set lock)
- *
- *	RETURNS:
- *	Zero on success, AC_ERR_* mask on failure
  */
-
-unsigned int ata_qc_issue(struct ata_queued_cmd *qc)
+void ata_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 
+	qc->ap->active_tag = qc->tag;
+	qc->flags |= ATA_QCFLAG_ACTIVE;
+
 	if (ata_should_dma_map(qc)) {
 		if (qc->flags & ATA_QCFLAG_SG) {
 			if (ata_sg_setup(qc))
@@ -4065,17 +4017,18 @@
 
 	ap->ops->qc_prep(qc);
 
-	qc->ap->active_tag = qc->tag;
-	qc->flags |= ATA_QCFLAG_ACTIVE;
-
-	return ap->ops->qc_issue(qc);
+	qc->err_mask |= ap->ops->qc_issue(qc);
+	if (unlikely(qc->err_mask))
+		goto err;
+	return;
 
 sg_err:
 	qc->flags &= ~ATA_QCFLAG_DMAMAP;
-	return AC_ERR_SYSTEM;
+	qc->err_mask |= AC_ERR_SYSTEM;
+err:
+	ata_qc_complete(qc);
 }
 
-
 /**
  *	ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
  *	@qc: command to issue to device
@@ -4536,6 +4489,14 @@
 	int rc;
 
 	DPRINTK("ENTER\n");
+
+	if (!ent->port_ops->probe_reset &&
+	    !(ent->host_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
+		printk(KERN_ERR "ata%u: no reset mechanism available\n",
+		       port_no);
+		return NULL;
+	}
+
 	host = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
 	if (!host)
 		return NULL;
@@ -4596,6 +4557,7 @@
 	host_set->mmio_base = ent->mmio_base;
 	host_set->private_data = ent->private_data;
 	host_set->ops = ent->port_ops;
+	host_set->flags = ent->host_set_flags;
 
 	/* register each port bound to this device */
 	for (i = 0; i < ent->n_ports; i++) {
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 628191b..53f5b0d 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1431,9 +1431,7 @@
 		goto early_finish;
 
 	/* select device, send command to hardware */
-	qc->err_mask = ata_qc_issue(qc);
-	if (qc->err_mask)
-		ata_qc_complete(qc);
+	ata_qc_issue(qc);
 
 	VPRINTK("EXIT\n");
 	return;
@@ -2199,9 +2197,7 @@
 
 	qc->complete_fn = atapi_sense_complete;
 
-	qc->err_mask = ata_qc_issue(qc);
-	if (qc->err_mask)
-		ata_qc_complete(qc);
+	ata_qc_issue(qc);
 
 	DPRINTK("EXIT\n");
 }
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index 65f52be..1c755b1 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -47,7 +47,7 @@
 extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc);
 extern void ata_port_flush_task(struct ata_port *ap);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
-extern unsigned int ata_qc_issue(struct ata_queued_cmd *qc);
+extern void ata_qc_issue(struct ata_queued_cmd *qc);
 extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
 extern void ata_dev_select(struct ata_port *ap, unsigned int device,
                            unsigned int wait, unsigned int can_sleep);
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 352df47..0701765 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -38,18 +38,6 @@
 #define LPFC_MBUF_POOL_SIZE     64      /* max elements in MBUF safety pool */
 #define LPFC_MEM_POOL_SIZE      64      /* max elem in non-DMA safety pool */
 
-static void *
-lpfc_pool_kmalloc(gfp_t gfp_flags, void *data)
-{
-	return kmalloc((unsigned long)data, gfp_flags);
-}
-
-static void
-lpfc_pool_kfree(void *obj, void *data)
-{
-	kfree(obj);
-}
-
 int
 lpfc_mem_alloc(struct lpfc_hba * phba)
 {
@@ -79,15 +67,13 @@
 		pool->current_count++;
 	}
 
-	phba->mbox_mem_pool = mempool_create(LPFC_MEM_POOL_SIZE,
-				lpfc_pool_kmalloc, lpfc_pool_kfree,
-				(void *)(unsigned long)sizeof(LPFC_MBOXQ_t));
+	phba->mbox_mem_pool = mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE,
+							 sizeof(LPFC_MBOXQ_t));
 	if (!phba->mbox_mem_pool)
 		goto fail_free_mbuf_pool;
 
-	phba->nlp_mem_pool = mempool_create(LPFC_MEM_POOL_SIZE,
-			lpfc_pool_kmalloc, lpfc_pool_kfree,
-			(void *)(unsigned long)sizeof(struct lpfc_nodelist));
+	phba->nlp_mem_pool = mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE,
+						sizeof(struct lpfc_nodelist));
 	if (!phba->nlp_mem_pool)
 		goto fail_free_mbox_pool;
 
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 7144674..80b68a2 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -45,6 +45,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/dma-mapping.h>
 #include <scsi/scsicam.h>
 
 #include "scsi.h"
@@ -2094,7 +2095,7 @@
 
 	memcpy(*pdev, adapter->dev, sizeof(struct pci_dev));
 
-	if( pci_set_dma_mask(*pdev, 0xffffffff) != 0 ) {
+	if( pci_set_dma_mask(*pdev, DMA_32BIT_MASK) != 0 ) {
 		kfree(*pdev);
 		return -1;
 	}
@@ -4859,10 +4860,10 @@
 
 	/* Set the Mode of addressing to 64 bit if we can */
 	if ((adapter->flag & BOARD_64BIT) && (sizeof(dma_addr_t) == 8)) {
-		pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+		pci_set_dma_mask(pdev, DMA_64BIT_MASK);
 		adapter->has_64bit_addr = 1;
 	} else  {
-		pci_set_dma_mask(pdev, 0xffffffff);
+		pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		adapter->has_64bit_addr = 0;
 	}
 		
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index d6d2125..f852421 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1748,7 +1748,7 @@
 
 static void set_mesh_power(struct mesh_state *ms, int state)
 {
-	if (_machine != _MACH_Pmac)
+	if (!machine_is(powermac))
 		return;
 	if (state) {
 		pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 1);
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index a279ebb..30ee0ef 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -38,6 +38,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ctype.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/dma.h>
 #include <asm/system.h>
@@ -2776,7 +2777,7 @@
 	/*
 	 * setup DMA 
 	 */
-	if (pci_set_dma_mask(PCIDEV, 0xffffffffUL) != 0) {
+	if (pci_set_dma_mask(PCIDEV, DMA_32BIT_MASK) != 0) {
 		nsp32_msg (KERN_ERR, "failed to set PCI DMA mask");
 		goto scsi_unregister;
 	}
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 66ea47a..e3bd4bc 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -49,6 +49,7 @@
 #include <linux/blkdev.h>
 #include <linux/moduleparam.h>
 #include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <asm/uaccess.h>
 #include <asm/dma.h>
 #include <asm/system.h>
@@ -856,7 +857,7 @@
 		    ) && result >= 0)
 		{
 #if DEBUG			
-			if (debugging || jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC)
+			if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC))
 				printk (OSST_DEB_MSG
 					"%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
 					name, curr, curr+minlast, STp->first_frame_position,
@@ -867,7 +868,7 @@
 			return 0;
 		}
 #if DEBUG
-		if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC && notyetprinted)
+		if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted)
 		{
 			printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
 				name, curr, curr+minlast, STp->first_frame_position,
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 05347ee..fee843f 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -18,6 +18,7 @@
 #include <linux/parport.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <asm/io.h>
 
 #include <scsi/scsi.h>
@@ -726,7 +727,7 @@
 				retv--;
 
 			if (retv) {
-				if ((jiffies - dev->jstart) > (1 * HZ)) {
+				if (time_after(jiffies, dev->jstart + (1 * HZ))) {
 					printk
 					    ("ppa: Parallel port cable is unplugged!!\n");
 					ppa_fail(dev, DID_BUS_BUSY);
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index e023024..5a48e55 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -350,6 +350,7 @@
 #include <linux/pci_ids.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -4321,7 +4322,7 @@
 
 #ifdef QLA_64BIT_PTR
 	if (pci_set_dma_mask(ha->pdev, (dma_addr_t) ~ 0ULL)) {
-		if (pci_set_dma_mask(ha->pdev, 0xffffffff)) {
+		if (pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK)) {
 			printk(KERN_WARNING "scsi(%li): Unable to set a "
 			       "suitable DMA mask - aborting\n", ha->host_no);
 			error = -ENODEV;
@@ -4331,7 +4332,7 @@
 		dprintk(2, "scsi(%li): 64 Bit PCI Addressing Enabled\n",
 			ha->host_no);
 #else
-	if (pci_set_dma_mask(ha->pdev, 0xffffffff)) {
+	if (pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK)) {
 		printk(KERN_WARNING "scsi(%li): Unable to set a "
 		       "suitable DMA mask - aborting\n", ha->host_no);
 		error = -ENODEV;
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 029bbf4..017729c 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2154,8 +2154,7 @@
 	int      rval;
 
 	rval = QLA_SUCCESS;
-	ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,
-	    mempool_free_slab, srb_cachep);
+	ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep);
 	if (ha->srb_mempool == NULL) {
 		qla_printk(KERN_INFO, ha, "Unable to allocate SRB mempool.\n");
 		rval = QLA_FUNCTION_FAILED;
diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c
index 94ef3f0..52b224a 100644
--- a/drivers/scsi/qlogicfc.c
+++ b/drivers/scsi/qlogicfc.c
@@ -61,6 +61,8 @@
 #include <linux/unistd.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/jiffies.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include "scsi.h"
@@ -737,8 +739,8 @@
 				continue;
 
 			/* Try to configure DMA attributes. */
-			if (pci_set_dma_mask(pdev, 0xffffffffffffffffULL) &&
-			    pci_set_dma_mask(pdev, 0xffffffffULL))
+			if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) &&
+			    pci_set_dma_mask(pdev, DMA_32BIT_MASK))
 					continue;
 
 		        host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata));
@@ -1325,7 +1327,7 @@
 		cmd->control_flags = cpu_to_le16(CFLAG_READ);
 
 	if (Cmnd->device->tagged_supported) {
-		if ((jiffies - hostdata->tag_ages[Cmnd->device->id]) > (2 * ISP_TIMEOUT)) {
+		if (time_after(jiffies, hostdata->tag_ages[Cmnd->device->id] + (2 * ISP_TIMEOUT))) {
 			cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG);
 			hostdata->tag_ages[Cmnd->device->id] = jiffies;
 		} else
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 1fd5fc6..c7e78dc 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -24,6 +24,7 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/jiffies.h>
 
 #include <asm/byteorder.h>
 
@@ -1017,7 +1018,7 @@
 	if (Cmnd->device->tagged_supported) {
 		if (qpti->cmd_count[Cmnd->device->id] == 0)
 			qpti->tag_ages[Cmnd->device->id] = jiffies;
-		if ((jiffies - qpti->tag_ages[Cmnd->device->id]) > (5*HZ)) {
+		if (time_after(jiffies, qpti->tag_ages[Cmnd->device->id] + (5*HZ))) {
 			cmd->control_flags = CFLAG_ORDERED_TAG;
 			qpti->tag_ages[Cmnd->device->id] = jiffies;
 		} else
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index 275ed9b..fa901fd 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -1010,7 +1010,7 @@
 
 			pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff);
 			pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16);
-			pp->sg_tbl[i].flags_size = cpu_to_le32(len);
+			pp->sg_tbl[i].flags_size = cpu_to_le32(len & 0xffff);
 
 			sg_len -= len;
 			addr += len;
@@ -1350,7 +1350,6 @@
 {
 	void __iomem *mmio = host_set->mmio_base;
 	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
-	struct ata_port *ap;
 	struct ata_queued_cmd *qc;
 	u32 hc_irq_cause;
 	int shift, port, port0, hard_port, handled;
@@ -1373,25 +1372,32 @@
 
 	for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
 		u8 ata_status = 0;
-		ap = host_set->ports[port];
+		struct ata_port *ap = host_set->ports[port];
+		struct mv_port_priv *pp = ap->private_data;
+
 		hard_port = port & MV_PORT_MASK;	/* range 0-3 */
 		handled = 0;	/* ensure ata_status is set if handled++ */
 
-		if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) {
-			/* new CRPB on the queue; just one at a time until NCQ
-			 */
-			ata_status = mv_get_crpb_status(ap);
-			handled++;
-		} else if ((DEV_IRQ << hard_port) & hc_irq_cause) {
-			/* received ATA IRQ; read the status reg to clear INTRQ
-			 */
-			ata_status = readb((void __iomem *)
+		/* Note that DEV_IRQ might happen spuriously during EDMA,
+		 * and should be ignored in such cases.  We could mask it,
+		 * but it's pretty rare and may not be worth the overhead.
+		 */ 
+		if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
+			/* EDMA: check for response queue interrupt */
+			if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) {
+				ata_status = mv_get_crpb_status(ap);
+				handled = 1;
+			}
+		} else {
+			/* PIO: check for device (drive) interrupt */
+			if ((DEV_IRQ << hard_port) & hc_irq_cause) {
+				ata_status = readb((void __iomem *)
 					   ap->ioaddr.status_addr);
-			handled++;
+				handled = 1;
+			}
 		}
 
-		if (ap &&
-		    (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR)))
+		if (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))
 			continue;
 
 		err_mask = ac_err_mask(ata_status);
@@ -1403,12 +1409,12 @@
 		if ((PORT0_ERR << shift) & relevant) {
 			mv_err_intr(ap);
 			err_mask |= AC_ERR_OTHER;
-			handled++;
+			handled = 1;
 		}
 
-		if (handled && ap) {
+		if (handled) {
 			qc = ata_qc_from_tag(ap, ap->active_tag);
-			if (NULL != qc) {
+			if (qc && (qc->flags & ATA_QCFLAG_ACTIVE)) {
 				VPRINTK("port %u IRQ found for qc, "
 					"ata_status 0x%x\n", port,ata_status);
 				/* mark qc status appropriately */
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index ede158d..8f010a3 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1787,9 +1787,8 @@
 					sgp->name);
 		}
 
-		sgp->pool = mempool_create(SG_MEMPOOL_SIZE,
-				mempool_alloc_slab, mempool_free_slab,
-				sgp->slab);
+		sgp->pool = mempool_create_slab_pool(SG_MEMPOOL_SIZE,
+						     sgp->slab);
 		if (!sgp->pool) {
 			printk(KERN_ERR "SCSI: can't init sg mempool %s\n",
 					sgp->name);
diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c
index b131432..a6cfbb3 100644
--- a/drivers/scsi/zalon.c
+++ b/drivers/scsi/zalon.c
@@ -88,7 +88,7 @@
 	struct gsc_irq gsc_irq;
 	u32 zalon_vers;
 	int error = -ENODEV;
-	void __iomem *zalon = ioremap(dev->hpa.start, 4096);
+	void __iomem *zalon = ioremap_nocache(dev->hpa.start, 4096);
 	void __iomem *io_port = zalon + GSC_SCSI_ZALON_OFFSET;
 	static int unit = 0;
 	struct Scsi_Host *host;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 5996d3c..674b15c 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1528,7 +1528,7 @@
 
 	/*
 	 * Clear the FIFO buffers and disable them.
-	 * (they will be reeanbled in set_termios())
+	 * (they will be reenabled in set_termios())
 	 */
 	serial8250_clear_fifos(up);
 
diff --git a/drivers/serial/8250_au1x00.c b/drivers/serial/8250_au1x00.c
index 8d8d7a7..3d1bfd0 100644
--- a/drivers/serial/8250_au1x00.c
+++ b/drivers/serial/8250_au1x00.c
@@ -51,7 +51,7 @@
 #elif defined(CONFIG_SOC_AU1100)
 	PORT(UART0_ADDR, AU1100_UART0_INT),
 	PORT(UART1_ADDR, AU1100_UART1_INT),
-	PORT(UART2_ADDR, AU1100_UART2_INT),
+	/* The internal UART2 does not exist on the AU1100 processor. */
 	PORT(UART3_ADDR, AU1100_UART3_INT),
 #elif defined(CONFIG_SOC_AU1550)
 	PORT(UART0_ADDR, AU1550_UART0_INT),
diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c
index 8b49479..913c71c 100644
--- a/drivers/serial/8250_gsc.c
+++ b/drivers/serial/8250_gsc.c
@@ -52,13 +52,14 @@
 		address += 0x800;
 	}
 
-	memset(&port, 0, sizeof(struct uart_port));
-	port.mapbase = address;
-	port.irq = dev->irq;
-	port.iotype = UPIO_MEM;
-	port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
-	port.uartclk = LASI_BASE_BAUD * 16;
-	port.dev = &dev->dev;
+	memset(&port, 0, sizeof(port));
+	port.iotype	= UPIO_MEM;
+	port.uartclk	= LASI_BASE_BAUD * 16;
+	port.mapbase	= address;
+	port.membase	= ioremap_nocache(address, 16);
+	port.irq	= dev->irq;
+	port.flags	= UPF_BOOT_AUTOCONF;
+	port.dev	= &dev->dev;
 
 	err = serial8250_register_port(&port);
 	if (err < 0) {
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index ceb3697..fe0d8b8 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -620,22 +620,6 @@
 	depends on SERIAL_SH_SCI=y
 	select SERIAL_CORE_CONSOLE
 
-config SERIAL_AU1X00
-	bool "Enable Au1x00 UART Support"
-	depends on MIPS && SOC_AU1X00
-	select SERIAL_CORE
-	help
-	  If you have an Alchemy AU1X00 processor (MIPS based) and you want
-	  to use serial ports, say Y.  Otherwise, say N.
-
-config SERIAL_AU1X00_CONSOLE
-	bool "Enable Au1x00 serial console"
-	depends on SERIAL_AU1X00
-	select SERIAL_CORE_CONSOLE
-	help
-	  If you have an Alchemy AU1X00 processor (MIPS based) and you want
-	  to use a console on a serial port, say Y.  Otherwise, say N.
-
 config SERIAL_CORE
 	tristate
 
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index a3a4323..d2b4c21 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -41,7 +41,6 @@
 obj-$(CONFIG_V850E_UART) += v850e_uart.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
 obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
-obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o
 obj-$(CONFIG_SERIAL_DZ) += dz.o
 obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
 obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index 127d6cd..1631414 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -51,8 +51,6 @@
 #include <linux/amba/serial.h>
 
 #include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/hardware.h>
 
 #define UART_NR		2
 
@@ -65,26 +63,16 @@
 #define UART_RX_DATA(s)		(((s) & UART01x_FR_RXFE) == 0)
 #define UART_TX_READY(s)	(((s) & UART01x_FR_TXFF) == 0)
 
-#define UART_DUMMY_RSR_RX	/*256*/0
+#define UART_DUMMY_RSR_RX	256
 #define UART_PORT_SIZE		64
 
 /*
- * On the Integrator platform, the port RTS and DTR are provided by
- * bits in the following SC_CTRLS register bits:
- *        RTS  DTR
- *  UART0  7    6
- *  UART1  5    4
- */
-#define SC_CTRLC	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
-#define SC_CTRLS	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
-
-/*
  * We wrap our port structure around the generic uart_port.
  */
 struct uart_amba_port {
 	struct uart_port	port;
-	unsigned int		dtr_mask;
-	unsigned int		rts_mask;
+	struct amba_device	*dev;
+	struct amba_pl010_data	*data;
 	unsigned int		old_status;
 };
 
@@ -300,20 +288,9 @@
 static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
-	unsigned int ctrls = 0, ctrlc = 0;
 
-	if (mctrl & TIOCM_RTS)
-		ctrlc |= uap->rts_mask;
-	else
-		ctrls |= uap->rts_mask;
-
-	if (mctrl & TIOCM_DTR)
-		ctrlc |= uap->dtr_mask;
-	else
-		ctrls |= uap->dtr_mask;
-
-	__raw_writel(ctrls, SC_CTRLS);
-	__raw_writel(ctrlc, SC_CTRLC);
+	if (uap->data)
+		uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl);
 }
 
 static void pl010_break_ctl(struct uart_port *port, int break_state)
@@ -539,38 +516,7 @@
 	.verify_port	= pl010_verify_port,
 };
 
-static struct uart_amba_port amba_ports[UART_NR] = {
-	{
-		.port	= {
-			.membase	= (void *)IO_ADDRESS(INTEGRATOR_UART0_BASE),
-			.mapbase	= INTEGRATOR_UART0_BASE,
-			.iotype		= UPIO_MEM,
-			.irq		= IRQ_UARTINT0,
-			.uartclk	= 14745600,
-			.fifosize	= 16,
-			.ops		= &amba_pl010_pops,
-			.flags		= UPF_BOOT_AUTOCONF,
-			.line		= 0,
-		},
-		.dtr_mask	= 1 << 5,
-		.rts_mask	= 1 << 4,
-	},
-	{
-		.port	= {
-			.membase	= (void *)IO_ADDRESS(INTEGRATOR_UART1_BASE),
-			.mapbase	= INTEGRATOR_UART1_BASE,
-			.iotype		= UPIO_MEM,
-			.irq		= IRQ_UARTINT1,
-			.uartclk	= 14745600,
-			.fifosize	= 16,
-			.ops		= &amba_pl010_pops,
-			.flags		= UPF_BOOT_AUTOCONF,
-			.line		= 1,
-		},
-		.dtr_mask	= 1 << 7,
-		.rts_mask	= 1 << 6,
-	}
-};
+static struct uart_amba_port *amba_ports[UART_NR];
 
 #ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE
 
@@ -588,7 +534,7 @@
 static void
 pl010_console_write(struct console *co, const char *s, unsigned int count)
 {
-	struct uart_port *port = &amba_ports[co->index].port;
+	struct uart_port *port = &amba_ports[co->index]->port;
 	unsigned int status, old_cr;
 
 	/*
@@ -651,7 +597,7 @@
 	 */
 	if (co->index >= UART_NR)
 		co->index = 0;
-	port = &amba_ports[co->index].port;
+	port = &amba_ports[co->index]->port;
 
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -672,24 +618,6 @@
 	.data		= &amba_reg,
 };
 
-static int __init amba_console_init(void)
-{
-	/*
-	 * All port initializations are done statically
-	 */
-	register_console(&amba_console);
-	return 0;
-}
-console_initcall(amba_console_init);
-
-static int __init amba_late_console_init(void)
-{
-	if (!(amba_console.flags & CON_ENABLED))
-		register_console(&amba_console);
-	return 0;
-}
-late_initcall(amba_late_console_init);
-
 #define AMBA_CONSOLE	&amba_console
 #else
 #define AMBA_CONSOLE	NULL
@@ -707,30 +635,76 @@
 
 static int pl010_probe(struct amba_device *dev, void *id)
 {
-	int i;
+	struct uart_amba_port *port;
+	void __iomem *base;
+	int i, ret;
 
-	for (i = 0; i < UART_NR; i++) {
-		if (amba_ports[i].port.mapbase != dev->res.start)
-			continue;
+	for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
+		if (amba_ports[i] == NULL)
+			break;
 
-		amba_ports[i].port.dev = &dev->dev;
-		uart_add_one_port(&amba_reg, &amba_ports[i].port);
-		amba_set_drvdata(dev, &amba_ports[i]);
-		break;
+	if (i == ARRAY_SIZE(amba_ports)) {
+		ret = -EBUSY;
+		goto out;
 	}
 
-	return 0;
+	port = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+	if (!port) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	base = ioremap(dev->res.start, PAGE_SIZE);
+	if (!base) {
+		ret = -ENOMEM;
+		goto free;
+	}
+
+	port->port.dev = &dev->dev;
+	port->port.mapbase = dev->res.start;
+	port->port.membase = base;
+	port->port.iotype = UPIO_MEM;
+	port->port.irq = dev->irq[0];
+	port->port.uartclk = 14745600;
+	port->port.fifosize = 16;
+	port->port.ops = &amba_pl010_pops;
+	port->port.flags = UPF_BOOT_AUTOCONF;
+	port->port.line = i;
+	port->dev = dev;
+	port->data = dev->dev.platform_data;
+
+	amba_ports[i] = port;
+
+	amba_set_drvdata(dev, port);
+	ret = uart_add_one_port(&amba_reg, &port->port);
+	if (ret) {
+		amba_set_drvdata(dev, NULL);
+		amba_ports[i] = NULL;
+		iounmap(base);
+ free:
+		kfree(port);
+	}
+
+ out:
+	return ret;
 }
 
 static int pl010_remove(struct amba_device *dev)
 {
-	struct uart_amba_port *uap = amba_get_drvdata(dev);
-
-	if (uap)
-		uart_remove_one_port(&amba_reg, &uap->port);
+	struct uart_amba_port *port = amba_get_drvdata(dev);
+	int i;
 
 	amba_set_drvdata(dev, NULL);
 
+	uart_remove_one_port(&amba_reg, &port->port);
+
+	for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
+		if (amba_ports[i] == port)
+			amba_ports[i] = NULL;
+
+	iounmap(port->port.membase);
+	kfree(port);
+
 	return 0;
 }
 
diff --git a/drivers/serial/au1x00_uart.c b/drivers/serial/au1x00_uart.c
deleted file mode 100644
index 948880a..0000000
--- a/drivers/serial/au1x00_uart.c
+++ /dev/null
@@ -1,1287 +0,0 @@
-/*
- *  Driver for 8250/16550-type serial ports
- *
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- *  Copyright (C) 2001 Russell King.
- *
- * 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.
- *
- * A note about mapbase / membase
- *
- *  mapbase is the physical address of the IO port.  Currently, we don't
- *  support this very well, and it may well be dropped from this driver
- *  in future.  As such, mapbase should be NULL.
- *
- *  membase is an 'ioremapped' cookie.  This is compatible with the old
- *  serial.c driver, and is currently the preferred form.
- */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/delay.h>
-
-#include <asm/serial.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mach-au1x00/au1000.h>
-
-#if defined(CONFIG_SERIAL_AU1X00_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-#include "8250.h"
-
-/*
- * Debugging.
- */
-#if 0
-#define DEBUG_AUTOCONF(fmt...)	printk(fmt)
-#else
-#define DEBUG_AUTOCONF(fmt...)	do { } while (0)
-#endif
-
-#if 0
-#define DEBUG_INTR(fmt...)	printk(fmt)
-#else
-#define DEBUG_INTR(fmt...)	do { } while (0)
-#endif
-
-#define PASS_LIMIT	256
-
-/*
- * We default to IRQ0 for the "no irq" hack.   Some
- * machine types want others as well - they're free
- * to redefine this in their header file.
- */
-#define is_real_interrupt(irq)	((irq) != 0)
-
-static struct old_serial_port old_serial_port[] = {
-	{	.baud_base = 0,
-		.iomem_base = (u8 *)UART0_ADDR,
-		.irq = AU1000_UART0_INT,
-		.flags = STD_COM_FLAGS,
-		.iomem_reg_shift = 2,
-	}, {
-		.baud_base = 0,
-		.iomem_base = (u8 *)UART1_ADDR,
-		.irq = AU1000_UART1_INT,
-		.flags = STD_COM_FLAGS,
-		.iomem_reg_shift = 2
-	}, {
-		.baud_base = 0,
-		.iomem_base = (u8 *)UART2_ADDR,
-		.irq = AU1000_UART2_INT,
-		.flags = STD_COM_FLAGS,
-		.iomem_reg_shift = 2
-	}, {
-		.baud_base = 0,
-		.iomem_base = (u8 *)UART3_ADDR,
-		.irq = AU1000_UART3_INT,
-		.flags = STD_COM_FLAGS,
-		.iomem_reg_shift = 2
-	}
-};
-
-#define UART_NR	ARRAY_SIZE(old_serial_port)
-
-struct uart_8250_port {
-	struct uart_port	port;
-	struct timer_list	timer;		/* "no irq" timer */
-	struct list_head	list;		/* ports on this IRQ */
-	unsigned short		rev;
-	unsigned char		acr;
-	unsigned char		ier;
-	unsigned char		lcr;
-	unsigned char		mcr_mask;	/* mask of user bits */
-	unsigned char		mcr_force;	/* mask of forced bits */
-	unsigned char		lsr_break_flag;
-
-	/*
-	 * We provide a per-port pm hook.
-	 */
-	void			(*pm)(struct uart_port *port,
-				      unsigned int state, unsigned int old);
-};
-
-struct irq_info {
-	spinlock_t		lock;
-	struct list_head	*head;
-};
-
-static struct irq_info irq_lists[NR_IRQS];
-
-/*
- * Here we define the default xmit fifo size used for each type of UART.
- */
-static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
-	{ "unknown",	1,	0 },
-	{ "8250",	1,	0 },
-	{ "16450",	1,	0 },
-	{ "16550",	1,	0 },
-	/* PORT_16550A */
-	{ "AU1X00_UART",16,	UART_CLEAR_FIFO | UART_USE_FIFO },
-};
-
-static unsigned int serial_in(struct uart_8250_port *up, int offset)
-{
-	return au_readl((unsigned long)up->port.membase + offset);
-}
-
-static void serial_out(struct uart_8250_port *up, int offset, int value)
-{
-	au_writel(value, (unsigned long)up->port.membase + offset);
-}
-
-#define serial_inp(up, offset)		serial_in(up, offset)
-#define serial_outp(up, offset, value)	serial_out(up, offset, value)
-
-/*
- * This routine is called by rs_init() to initialize a specific serial
- * port.  It determines what type of UART chip this serial port is
- * using: 8250, 16450, 16550, 16550A.  The important question is
- * whether or not this UART is a 16550A or not, since this will
- * determine whether or not we can use its FIFO features or not.
- */
-static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
-{
-	unsigned char save_lcr, save_mcr;
-	unsigned long flags;
-
-	if (!up->port.iobase && !up->port.mapbase && !up->port.membase)
-		return;
-
-	DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%08lx): ",
-			up->port.line, up->port.iobase, up->port.membase);
-
-	/*
-	 * We really do need global IRQs disabled here - we're going to
-	 * be frobbing the chips IRQ enable register to see if it exists.
-	 */
-	spin_lock_irqsave(&up->port.lock, flags);
-//	save_flags(flags); cli();
-
-	save_mcr = serial_in(up, UART_MCR);
-	save_lcr = serial_in(up, UART_LCR);
-
-	up->port.type = PORT_16550A;
-	serial_outp(up, UART_LCR, save_lcr);
-
-	up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
-
-	if (up->port.type == PORT_UNKNOWN)
-		goto out;
-
-	/*
-	 * Reset the UART.
-	 */
-	serial_outp(up, UART_MCR, save_mcr);
-	serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
-				     UART_FCR_CLEAR_RCVR |
-				     UART_FCR_CLEAR_XMIT));
-	serial_outp(up, UART_FCR, 0);
-	(void)serial_in(up, UART_RX);
-	serial_outp(up, UART_IER, 0);
-
- out:	
-	spin_unlock_irqrestore(&up->port.lock, flags);
-//	restore_flags(flags);
-	DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
-}
-
-static void serial8250_stop_tx(struct uart_port *port)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-
-	if (up->ier & UART_IER_THRI) {
-		up->ier &= ~UART_IER_THRI;
-		serial_out(up, UART_IER, up->ier);
-	}
-}
-
-static void serial8250_start_tx(struct uart_port *port)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-
-	if (!(up->ier & UART_IER_THRI)) {
-		up->ier |= UART_IER_THRI;
-		serial_out(up, UART_IER, up->ier);
-	}
-}
-
-static void serial8250_stop_rx(struct uart_port *port)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-
-	up->ier &= ~UART_IER_RLSI;
-	up->port.read_status_mask &= ~UART_LSR_DR;
-	serial_out(up, UART_IER, up->ier);
-}
-
-static void serial8250_enable_ms(struct uart_port *port)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-
-	up->ier |= UART_IER_MSI;
-	serial_out(up, UART_IER, up->ier);
-}
-
-static void
-receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
-{
-	struct tty_struct *tty = up->port.info->tty;
-	unsigned char ch, flag;
-	int max_count = 256;
-
-	do {
-		ch = serial_inp(up, UART_RX);
-		flag = TTY_NORMAL;
-		up->port.icount.rx++;
-
-		if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
-				       UART_LSR_FE | UART_LSR_OE))) {
-			/*
-			 * For statistics only
-			 */
-			if (*status & UART_LSR_BI) {
-				*status &= ~(UART_LSR_FE | UART_LSR_PE);
-				up->port.icount.brk++;
-				/*
-				 * We do the SysRQ and SAK checking
-				 * here because otherwise the break
-				 * may get masked by ignore_status_mask
-				 * or read_status_mask.
-				 */
-				if (uart_handle_break(&up->port))
-					goto ignore_char;
-			} else if (*status & UART_LSR_PE)
-				up->port.icount.parity++;
-			else if (*status & UART_LSR_FE)
-				up->port.icount.frame++;
-			if (*status & UART_LSR_OE)
-				up->port.icount.overrun++;
-
-			/*
-			 * Mask off conditions which should be ingored.
-			 */
-			*status &= up->port.read_status_mask;
-
-#ifdef CONFIG_SERIAL_AU1X00_CONSOLE
-			if (up->port.line == up->port.cons->index) {
-				/* Recover the break flag from console xmit */
-				*status |= up->lsr_break_flag;
-				up->lsr_break_flag = 0;
-			}
-#endif
-			if (*status & UART_LSR_BI) {
-				DEBUG_INTR("handling break....");
-				flag = TTY_BREAK;
-			} else if (*status & UART_LSR_PE)
-				flag = TTY_PARITY;
-			else if (*status & UART_LSR_FE)
-				flag = TTY_FRAME;
-		}
-		if (uart_handle_sysrq_char(&up->port, ch, regs))
-			goto ignore_char;
-		if ((*status & up->port.ignore_status_mask) == 0)
-			tty_insert_flip_char(tty, ch, flag);
-		if (*status & UART_LSR_OE)
-			/*
-			 * Overrun is special, since it's reported
-			 * immediately, and doesn't affect the current
-			 * character.
-			 */
-			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-		}
-	ignore_char:
-		*status = serial_inp(up, UART_LSR);
-	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
-	spin_unlock(&up->port.lock);
-	tty_flip_buffer_push(tty);
-	spin_lock(&up->port.lock);
-}
-
-static void transmit_chars(struct uart_8250_port *up)
-{
-	struct circ_buf *xmit = &up->port.info->xmit;
-	int count;
-
-	if (up->port.x_char) {
-		serial_outp(up, UART_TX, up->port.x_char);
-		up->port.icount.tx++;
-		up->port.x_char = 0;
-		return;
-	}
-	if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
-		serial8250_stop_tx(&up->port);
-		return;
-	}
-
-	count = up->port.fifosize;
-	do {
-		serial_out(up, UART_TX, xmit->buf[xmit->tail]);
-		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-		up->port.icount.tx++;
-		if (uart_circ_empty(xmit))
-			break;
-	} while (--count > 0);
-
-	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-		uart_write_wakeup(&up->port);
-
-	DEBUG_INTR("THRE...");
-
-	if (uart_circ_empty(xmit))
-		serial8250_stop_tx(&up->port);
-}
-
-static void check_modem_status(struct uart_8250_port *up)
-{
-	int status;
-
-	status = serial_in(up, UART_MSR);
-
-	if ((status & UART_MSR_ANY_DELTA) == 0)
-		return;
-
-	if (status & UART_MSR_TERI)
-		up->port.icount.rng++;
-	if (status & UART_MSR_DDSR)
-		up->port.icount.dsr++;
-	if (status & UART_MSR_DDCD)
-		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
-	if (status & UART_MSR_DCTS)
-		uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
-
-	wake_up_interruptible(&up->port.info->delta_msr_wait);
-}
-
-/*
- * This handles the interrupt from one port.
- */
-static inline void
-serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
-{
-	unsigned int status = serial_inp(up, UART_LSR);
-
-	DEBUG_INTR("status = %x...", status);
-
-	if (status & UART_LSR_DR)
-		receive_chars(up, &status, regs);
-	check_modem_status(up);
-	if (status & UART_LSR_THRE)
-		transmit_chars(up);
-}
-
-/*
- * This is the serial driver's interrupt routine.
- *
- * Arjan thinks the old way was overly complex, so it got simplified.
- * Alan disagrees, saying that need the complexity to handle the weird
- * nature of ISA shared interrupts.  (This is a special exception.)
- *
- * In order to handle ISA shared interrupts properly, we need to check
- * that all ports have been serviced, and therefore the ISA interrupt
- * line has been de-asserted.
- *
- * This means we need to loop through all ports. checking that they
- * don't have an interrupt pending.
- */
-static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct irq_info *i = dev_id;
-	struct list_head *l, *end = NULL;
-	int pass_counter = 0;
-
-	DEBUG_INTR("serial8250_interrupt(%d)...", irq);
-
-	spin_lock(&i->lock);
-
-	l = i->head;
-	do {
-		struct uart_8250_port *up;
-		unsigned int iir;
-
-		up = list_entry(l, struct uart_8250_port, list);
-
-		iir = serial_in(up, UART_IIR);
-		if (!(iir & UART_IIR_NO_INT)) {
-			spin_lock(&up->port.lock);
-			serial8250_handle_port(up, regs);
-			spin_unlock(&up->port.lock);
-
-			end = NULL;
-		} else if (end == NULL)
-			end = l;
-
-		l = l->next;
-
-		if (l == i->head && pass_counter++ > PASS_LIMIT) {
-			/* If we hit this, we're dead. */
-			printk(KERN_ERR "serial8250: too much work for "
-				"irq%d\n", irq);
-			break;
-		}
-	} while (l != end);
-
-	spin_unlock(&i->lock);
-
-	DEBUG_INTR("end.\n");
-	/* FIXME! Was it really ours? */
-	return IRQ_HANDLED;
-}
-
-/*
- * To support ISA shared interrupts, we need to have one interrupt
- * handler that ensures that the IRQ line has been deasserted
- * before returning.  Failing to do this will result in the IRQ
- * line being stuck active, and, since ISA irqs are edge triggered,
- * no more IRQs will be seen.
- */
-static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
-{
-	spin_lock_irq(&i->lock);
-
-	if (!list_empty(i->head)) {
-		if (i->head == &up->list)
-			i->head = i->head->next;
-		list_del(&up->list);
-	} else {
-		BUG_ON(i->head != &up->list);
-		i->head = NULL;
-	}
-
-	spin_unlock_irq(&i->lock);
-}
-
-static int serial_link_irq_chain(struct uart_8250_port *up)
-{
-	struct irq_info *i = irq_lists + up->port.irq;
-	int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? SA_SHIRQ : 0;
-
-	spin_lock_irq(&i->lock);
-
-	if (i->head) {
-		list_add(&up->list, i->head);
-		spin_unlock_irq(&i->lock);
-
-		ret = 0;
-	} else {
-		INIT_LIST_HEAD(&up->list);
-		i->head = &up->list;
-		spin_unlock_irq(&i->lock);
-
-		ret = request_irq(up->port.irq, serial8250_interrupt,
-				  irq_flags, "serial", i);
-		if (ret < 0)
-			serial_do_unlink(i, up);
-	}
-
-	return ret;
-}
-
-static void serial_unlink_irq_chain(struct uart_8250_port *up)
-{
-	struct irq_info *i = irq_lists + up->port.irq;
-
-	BUG_ON(i->head == NULL);
-
-	if (list_empty(i->head))
-		free_irq(up->port.irq, i);
-
-	serial_do_unlink(i, up);
-}
-
-/*
- * This function is used to handle ports that do not have an
- * interrupt.  This doesn't work very well for 16450's, but gives
- * barely passable results for a 16550A.  (Although at the expense
- * of much CPU overhead).
- */
-static void serial8250_timeout(unsigned long data)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)data;
-	unsigned int timeout;
-	unsigned int iir;
-
-	iir = serial_in(up, UART_IIR);
-	if (!(iir & UART_IIR_NO_INT)) {
-		spin_lock(&up->port.lock);
-		serial8250_handle_port(up, NULL);
-		spin_unlock(&up->port.lock);
-	}
-
-	timeout = up->port.timeout;
-	timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
-	mod_timer(&up->timer, jiffies + timeout);
-}
-
-static unsigned int serial8250_tx_empty(struct uart_port *port)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-	unsigned long flags;
-	unsigned int ret;
-
-	spin_lock_irqsave(&up->port.lock, flags);
-	ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-	spin_unlock_irqrestore(&up->port.lock, flags);
-
-	return ret;
-}
-
-static unsigned int serial8250_get_mctrl(struct uart_port *port)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-	unsigned char status;
-	unsigned int ret;
-
-	status = serial_in(up, UART_MSR);
-
-	ret = 0;
-	if (status & UART_MSR_DCD)
-		ret |= TIOCM_CAR;
-	if (status & UART_MSR_RI)
-		ret |= TIOCM_RNG;
-	if (status & UART_MSR_DSR)
-		ret |= TIOCM_DSR;
-	if (status & UART_MSR_CTS)
-		ret |= TIOCM_CTS;
-	return ret;
-}
-
-static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-	unsigned char mcr = 0;
-
-	if (mctrl & TIOCM_RTS)
-		mcr |= UART_MCR_RTS;
-	if (mctrl & TIOCM_DTR)
-		mcr |= UART_MCR_DTR;
-	if (mctrl & TIOCM_OUT1)
-		mcr |= UART_MCR_OUT1;
-	if (mctrl & TIOCM_OUT2)
-		mcr |= UART_MCR_OUT2;
-	if (mctrl & TIOCM_LOOP)
-		mcr |= UART_MCR_LOOP;
-
-	mcr = (mcr & up->mcr_mask) | up->mcr_force;
-
-	serial_out(up, UART_MCR, mcr);
-}
-
-static void serial8250_break_ctl(struct uart_port *port, int break_state)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-	unsigned long flags;
-
-	spin_lock_irqsave(&up->port.lock, flags);
-	if (break_state == -1)
-		up->lcr |= UART_LCR_SBC;
-	else
-		up->lcr &= ~UART_LCR_SBC;
-	serial_out(up, UART_LCR, up->lcr);
-	spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static int serial8250_startup(struct uart_port *port)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-	unsigned long flags;
-	int retval;
-
-	/*
-	 * Clear the FIFO buffers and disable them.
-	 * (they will be reeanbled in set_termios())
-	 */
-	if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
-		serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-		serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-				UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-		serial_outp(up, UART_FCR, 0);
-	}
-
-	/*
-	 * Clear the interrupt registers.
-	 */
-	(void) serial_inp(up, UART_LSR);
-	(void) serial_inp(up, UART_RX);
-	(void) serial_inp(up, UART_IIR);
-	(void) serial_inp(up, UART_MSR);
-
-	/*
-	 * At this point, there's no way the LSR could still be 0xff;
-	 * if it is, then bail out, because there's likely no UART
-	 * here.
-	 */
-	if (!(up->port.flags & UPF_BUGGY_UART) &&
-	    (serial_inp(up, UART_LSR) == 0xff)) {
-		printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
-		return -ENODEV;
-	}
-
-	retval = serial_link_irq_chain(up);
-		if (retval)
-			return retval;
-
-	/*
-	 * Now, initialize the UART
-	 */
-	serial_outp(up, UART_LCR, UART_LCR_WLEN8);
-
-	spin_lock_irqsave(&up->port.lock, flags);
-	if (up->port.flags & UPF_FOURPORT) {
-		if (!is_real_interrupt(up->port.irq))
-			up->port.mctrl |= TIOCM_OUT1;
-	} else
-		/*
-		 * Most PC uarts need OUT2 raised to enable interrupts.
-		 */
-		if (is_real_interrupt(up->port.irq))
-			up->port.mctrl |= TIOCM_OUT2;
-
-	serial8250_set_mctrl(&up->port, up->port.mctrl);
-	spin_unlock_irqrestore(&up->port.lock, flags);
-
-	/*
-	 * Finally, enable interrupts.  Note: Modem status interrupts
-	 * are set via set_termios(), which will be occurring imminently
-	 * anyway, so we don't enable them here.
-	 */
-	up->ier = UART_IER_RLSI | UART_IER_RDI;
-	serial_outp(up, UART_IER, up->ier);
-
-	if (up->port.flags & UPF_FOURPORT) {
-		unsigned int icp;
-		/*
-		 * Enable interrupts on the AST Fourport board
-		 */
-		icp = (up->port.iobase & 0xfe0) | 0x01f;
-		outb_p(0x80, icp);
-		(void) inb_p(icp);
-	}
-
-	/*
-	 * And clear the interrupt registers again for luck.
-	 */
-	(void) serial_inp(up, UART_LSR);
-	(void) serial_inp(up, UART_RX);
-	(void) serial_inp(up, UART_IIR);
-	(void) serial_inp(up, UART_MSR);
-
-	return 0;
-}
-
-static void serial8250_shutdown(struct uart_port *port)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-	unsigned long flags;
-
-	/*
-	 * Disable interrupts from this port
-	 */
-	up->ier = 0;
-	serial_outp(up, UART_IER, 0);
-
-	spin_lock_irqsave(&up->port.lock, flags);
-	if (up->port.flags & UPF_FOURPORT) {
-		/* reset interrupts on the AST Fourport board */
-		inb((up->port.iobase & 0xfe0) | 0x1f);
-		up->port.mctrl |= TIOCM_OUT1;
-	} else
-		up->port.mctrl &= ~TIOCM_OUT2;
-
-	serial8250_set_mctrl(&up->port, up->port.mctrl);
-	spin_unlock_irqrestore(&up->port.lock, flags);
-
-	/*
-	 * Disable break condition and FIFOs
-	 */
-	serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
-	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-				  UART_FCR_CLEAR_RCVR |
-				  UART_FCR_CLEAR_XMIT);
-	serial_outp(up, UART_FCR, 0);
-
-	/*
-	 * Read data port to reset things, and then unlink from
-	 * the IRQ chain.
-	 */
-	(void) serial_in(up, UART_RX);
-
-	if (!is_real_interrupt(up->port.irq))
-		del_timer_sync(&up->timer);
-	else
-		serial_unlink_irq_chain(up);
-}
-
-static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
-{
-	unsigned int quot;
-
-	/*
-	 * Handle magic divisors for baud rates above baud_base on
-	 * SMSC SuperIO chips.
-	 */
-	if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
-	    baud == (port->uartclk/4))
-		quot = 0x8001;
-	else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
-		 baud == (port->uartclk/8))
-		quot = 0x8002;
-	else
-		quot = uart_get_divisor(port, baud);
-
-	return quot;
-}
-
-static void
-serial8250_set_termios(struct uart_port *port, struct termios *termios,
-		       struct termios *old)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-	unsigned char cval, fcr = 0;
-	unsigned long flags;
-	unsigned int baud, quot;
-
-	switch (termios->c_cflag & CSIZE) {
-	case CS5:
-		cval = UART_LCR_WLEN5;
-		break;
-	case CS6:
-		cval = UART_LCR_WLEN6;
-		break;
-	case CS7:
-		cval = UART_LCR_WLEN7;
-		break;
-	default:
-	case CS8:
-		cval = UART_LCR_WLEN8;
-		break;
-	}
-
-	if (termios->c_cflag & CSTOPB)
-		cval |= UART_LCR_STOP;
-	if (termios->c_cflag & PARENB)
-		cval |= UART_LCR_PARITY;
-	if (!(termios->c_cflag & PARODD))
-		cval |= UART_LCR_EPAR;
-#ifdef CMSPAR
-	if (termios->c_cflag & CMSPAR)
-		cval |= UART_LCR_SPAR;
-#endif
-
-	/*
-	 * Ask the core to calculate the divisor for us.
-	 */
-	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
-	quot = serial8250_get_divisor(port, baud);
-	quot = 0x35; /* FIXME */
-
-	/*
-	 * Work around a bug in the Oxford Semiconductor 952 rev B
-	 * chip which causes it to seriously miscalculate baud rates
-	 * when DLL is 0.
-	 */
-	if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 &&
-	    up->rev == 0x5201)
-		quot ++;
-
-	if (uart_config[up->port.type].flags & UART_USE_FIFO) {
-		if (baud < 2400)
-			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_1;
-		else
-			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_8;
-	}
-
-	/*
-	 * Ok, we're now changing the port state.  Do it with
-	 * interrupts disabled.
-	 */
-	spin_lock_irqsave(&up->port.lock, flags);
-
-	/*
-	 * Update the per-port timeout.
-	 */
-	uart_update_timeout(port, termios->c_cflag, baud);
-
-	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-	if (termios->c_iflag & INPCK)
-		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-	if (termios->c_iflag & (BRKINT | PARMRK))
-		up->port.read_status_mask |= UART_LSR_BI;
-
-	/*
-	 * Characteres to ignore
-	 */
-	up->port.ignore_status_mask = 0;
-	if (termios->c_iflag & IGNPAR)
-		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-	if (termios->c_iflag & IGNBRK) {
-		up->port.ignore_status_mask |= UART_LSR_BI;
-		/*
-		 * If we're ignoring parity and break indicators,
-		 * ignore overruns too (for real raw support).
-		 */
-		if (termios->c_iflag & IGNPAR)
-			up->port.ignore_status_mask |= UART_LSR_OE;
-	}
-
-	/*
-	 * ignore all characters if CREAD is not set
-	 */
-	if ((termios->c_cflag & CREAD) == 0)
-		up->port.ignore_status_mask |= UART_LSR_DR;
-
-	/*
-	 * CTS flow control flag and modem status interrupts
-	 */
-	up->ier &= ~UART_IER_MSI;
-	if (UART_ENABLE_MS(&up->port, termios->c_cflag))
-		up->ier |= UART_IER_MSI;
-
-	serial_out(up, UART_IER, up->ier);
-	serial_outp(up, 0x28, quot & 0xffff);
-	up->lcr = cval;					/* Save LCR */
-	if (up->port.type != PORT_16750) {
-		if (fcr & UART_FCR_ENABLE_FIFO) {
-			/* emulated UARTs (Lucent Venus 167x) need two steps */
-			serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-		}
-		serial_outp(up, UART_FCR, fcr);		/* set fcr */
-	}
-	spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void
-serial8250_pm(struct uart_port *port, unsigned int state,
-	      unsigned int oldstate)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-	if (state) {
-		/* sleep */
-		if (up->pm)
-			up->pm(port, state, oldstate);
-	} else {
-		/* wake */
-		if (up->pm)
-			up->pm(port, state, oldstate);
-	}
-}
-
-/*
- * Resource handling.  This is complicated by the fact that resources
- * depend on the port type.  Maybe we should be claiming the standard
- * 8250 ports, and then trying to get other resources as necessary?
- */
-static int
-serial8250_request_std_resource(struct uart_8250_port *up, struct resource **res)
-{
-	unsigned int size = 8 << up->port.regshift;
-	int ret = 0;
-
-	switch (up->port.iotype) {
-	case UPIO_MEM:
-		if (up->port.mapbase) {
-			*res = request_mem_region(up->port.mapbase, size, "serial");
-			if (!*res)
-				ret = -EBUSY;
-		}
-		break;
-
-	case UPIO_HUB6:
-	case UPIO_PORT:
-		*res = request_region(up->port.iobase, size, "serial");
-		if (!*res)
-			ret = -EBUSY;
-		break;
-	}
-	return ret;
-}
-
-
-static void serial8250_release_port(struct uart_port *port)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-	unsigned long start, offset = 0, size = 0;
-
-	size <<= up->port.regshift;
-
-	switch (up->port.iotype) {
-	case UPIO_MEM:
-		if (up->port.mapbase) {
-			/*
-			 * Unmap the area.
-			 */
-			iounmap(up->port.membase);
-			up->port.membase = NULL;
-
-			start = up->port.mapbase;
-
-			if (size)
-				release_mem_region(start + offset, size);
-			release_mem_region(start, 8 << up->port.regshift);
-		}
-		break;
-
-	case UPIO_HUB6:
-	case UPIO_PORT:
-		start = up->port.iobase;
-
-		if (size)
-			release_region(start + offset, size);
-		release_region(start + offset, 8 << up->port.regshift);
-		break;
-
-	default:
-		break;
-	}
-}
-
-static int serial8250_request_port(struct uart_port *port)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-	struct resource *res = NULL, *res_rsa = NULL;
-	int ret = 0;
-
-	ret = serial8250_request_std_resource(up, &res);
-
-	/*
-	 * If we have a mapbase, then request that as well.
-	 */
-	if (ret == 0 && up->port.flags & UPF_IOREMAP) {
-		int size = res->end - res->start + 1;
-
-		up->port.membase = ioremap(up->port.mapbase, size);
-		if (!up->port.membase)
-			ret = -ENOMEM;
-	}
-
-	if (ret < 0) {
-		if (res_rsa)
-			release_resource(res_rsa);
-		if (res)
-			release_resource(res);
-	}
-	return ret;
-}
-
-static void serial8250_config_port(struct uart_port *port, int flags)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-	struct resource *res_std = NULL, *res_rsa = NULL;
-	int probeflags = PROBE_ANY;
-
-	probeflags &= ~PROBE_RSA;
-
-	if (flags & UART_CONFIG_TYPE)
-		autoconfig(up, probeflags);
-
-	/*
-	 * If the port wasn't an RSA port, release the resource.
-	 */
-	if (up->port.type != PORT_RSA && res_rsa)
-		release_resource(res_rsa);
-
-	if (up->port.type == PORT_UNKNOWN && res_std)
-		release_resource(res_std);
-}
-
-static int
-serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-	if (ser->irq >= NR_IRQS || ser->irq < 0 ||
-	    ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
-	    ser->type > PORT_MAX_8250 || ser->type == PORT_CIRRUS ||
-	    ser->type == PORT_STARTECH)
-		return -EINVAL;
-	return 0;
-}
-
-static const char *
-serial8250_type(struct uart_port *port)
-{
-	int type = port->type;
-
-	if (type >= ARRAY_SIZE(uart_config))
-		type = 0;
-	return uart_config[type].name;
-}
-
-static struct uart_ops serial8250_pops = {
-	.tx_empty	= serial8250_tx_empty,
-	.set_mctrl	= serial8250_set_mctrl,
-	.get_mctrl	= serial8250_get_mctrl,
-	.stop_tx	= serial8250_stop_tx,
-	.start_tx	= serial8250_start_tx,
-	.stop_rx	= serial8250_stop_rx,
-	.enable_ms	= serial8250_enable_ms,
-	.break_ctl	= serial8250_break_ctl,
-	.startup	= serial8250_startup,
-	.shutdown	= serial8250_shutdown,
-	.set_termios	= serial8250_set_termios,
-	.pm		= serial8250_pm,
-	.type		= serial8250_type,
-	.release_port	= serial8250_release_port,
-	.request_port	= serial8250_request_port,
-	.config_port	= serial8250_config_port,
-	.verify_port	= serial8250_verify_port,
-};
-
-static struct uart_8250_port serial8250_ports[UART_NR];
-
-static void __init serial8250_isa_init_ports(void)
-{
-	struct uart_8250_port *up;
-	static int first = 1;
-	int i;
-
-	if (!first)
-		return;
-	first = 0;
-
-	for (i = 0, up = serial8250_ports; i < ARRAY_SIZE(old_serial_port);
-	     i++, up++) {
-		up->port.iobase   = old_serial_port[i].port;
-		up->port.irq      = old_serial_port[i].irq;
-		up->port.uartclk  = get_au1x00_uart_baud_base();
-		up->port.flags    = old_serial_port[i].flags;
-		up->port.hub6     = old_serial_port[i].hub6;
-		up->port.membase  = old_serial_port[i].iomem_base;
-		up->port.iotype   = old_serial_port[i].io_type;
-		up->port.regshift = old_serial_port[i].iomem_reg_shift;
-		up->port.ops      = &serial8250_pops;
-	}
-}
-
-static void __init serial8250_register_ports(struct uart_driver *drv)
-{
-	int i;
-
-	serial8250_isa_init_ports();
-
-	for (i = 0; i < UART_NR; i++) {
-		struct uart_8250_port *up = &serial8250_ports[i];
-
-		up->port.line = i;
-		up->port.ops = &serial8250_pops;
-		init_timer(&up->timer);
-		up->timer.function = serial8250_timeout;
-
-		/*
-		 * ALPHA_KLUDGE_MCR needs to be killed.
-		 */
-		up->mcr_mask = ~ALPHA_KLUDGE_MCR;
-		up->mcr_force = ALPHA_KLUDGE_MCR;
-
-		uart_add_one_port(drv, &up->port);
-	}
-}
-
-#ifdef CONFIG_SERIAL_AU1X00_CONSOLE
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-/*
- *	Wait for transmitter & holding register to empty
- */
-static inline void wait_for_xmitr(struct uart_8250_port *up)
-{
-	unsigned int status, tmout = 10000;
-
-	/* Wait up to 10ms for the character(s) to be sent. */
-	do {
-		status = serial_in(up, UART_LSR);
-
-		if (status & UART_LSR_BI)
-			up->lsr_break_flag = UART_LSR_BI;
-
-		if (--tmout == 0)
-			break;
-		udelay(1);
-	} while ((status & BOTH_EMPTY) != BOTH_EMPTY);
-
-	/* Wait up to 1s for flow control if necessary */
-	if (up->port.flags & UPF_CONS_FLOW) {
-		tmout = 1000000;
-		while (--tmout &&
-		       ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
-			udelay(1);
-	}
-}
-
-static void au1x00_console_putchar(struct uart_port *port, int ch)
-{
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-
-	wait_for_xmitr(up);
-	serial_out(up, UART_TX, ch);
-}
-
-/*
- *	Print a string to the serial port trying not to disturb
- *	any possible real use of the port...
- *
- *	The console_lock must be held when we get here.
- */
-static void
-serial8250_console_write(struct console *co, const char *s, unsigned int count)
-{
-	struct uart_8250_port *up = &serial8250_ports[co->index];
-	unsigned int ier;
-
-	/*
-	 *	First save the UER then disable the interrupts
-	 */
-	ier = serial_in(up, UART_IER);
-	serial_out(up, UART_IER, 0);
-
-	uart_console_write(&up->port, s, count, au1x00_console_putchar);
-
-	/*
-	 *	Finally, wait for transmitter to become empty
-	 *	and restore the IER
-	 */
-	wait_for_xmitr(up);
-	serial_out(up, UART_IER, ier);
-}
-
-static int __init serial8250_console_setup(struct console *co, char *options)
-{
-	struct uart_port *port;
-	int baud = 9600;
-	int bits = 8;
-	int parity = 'n';
-	int flow = 'n';
-
-	/*
-	 * Check whether an invalid uart number has been specified, and
-	 * if so, search for the first available port that does have
-	 * console support.
-	 */
-	if (co->index >= UART_NR)
-		co->index = 0;
-	port = &serial8250_ports[co->index].port;
-
-	/*
-	 * Temporary fix.
-	 */
-	spin_lock_init(&port->lock);
-
-	if (options)
-		uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-	return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-extern struct uart_driver serial8250_reg;
-static struct console serial8250_console = {
-	.name		= "ttyS",
-	.write		= serial8250_console_write,
-	.device		= uart_console_device,
-	.setup		= serial8250_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-	.data		= &serial8250_reg,
-};
-
-static int __init serial8250_console_init(void)
-{
-	serial8250_isa_init_ports();
-	register_console(&serial8250_console);
-	return 0;
-}
-console_initcall(serial8250_console_init);
-
-#define SERIAL8250_CONSOLE	&serial8250_console
-#else
-#define SERIAL8250_CONSOLE	NULL
-#endif
-
-static struct uart_driver serial8250_reg = {
-	.owner			= THIS_MODULE,
-	.driver_name		= "serial",
-	.devfs_name		= "tts/",
-	.dev_name		= "ttyS",
-	.major			= TTY_MAJOR,
-	.minor			= 64,
-	.nr			= UART_NR,
-	.cons			= SERIAL8250_CONSOLE,
-};
-
-int __init early_serial_setup(struct uart_port *port)
-{
-	serial8250_isa_init_ports();
-	serial8250_ports[port->line].port	= *port;
-	serial8250_ports[port->line].port.ops	= &serial8250_pops;
-	return 0;
-}
-
-/**
- *	serial8250_suspend_port - suspend one serial port
- *	@line:  serial line number
- *      @level: the level of port suspension, as per uart_suspend_port
- *
- *	Suspend one serial port.
- */
-void serial8250_suspend_port(int line)
-{
-	uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port);
-}
-
-/**
- *	serial8250_resume_port - resume one serial port
- *	@line:  serial line number
- *      @level: the level of port resumption, as per uart_resume_port
- *
- *	Resume one serial port.
- */
-void serial8250_resume_port(int line)
-{
-	uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
-}
-
-static int __init serial8250_init(void)
-{
-	int ret, i;
-
-	printk(KERN_INFO "Serial: Au1x00 driver\n");
-
-	for (i = 0; i < NR_IRQS; i++)
-		spin_lock_init(&irq_lists[i].lock);
-
-	ret = uart_register_driver(&serial8250_reg);
-	if (ret >= 0)
-		serial8250_register_ports(&serial8250_reg);
-
-	return ret;
-}
-
-static void __exit serial8250_exit(void)
-{
-	int i;
-
-	for (i = 0; i < UART_NR; i++)
-		uart_remove_one_port(&serial8250_reg, &serial8250_ports[i].port);
-
-	uart_unregister_driver(&serial8250_reg);
-}
-
-module_init(serial8250_init);
-module_exit(serial8250_exit);
-
-EXPORT_SYMBOL(serial8250_suspend_port);
-EXPORT_SYMBOL(serial8250_resume_port);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Au1x00 serial driver\n");
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index 4d48b62..7d82370 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -142,12 +142,14 @@
 {
 	unsigned long lock_flags;
 	struct jsm_channel *channel = (struct jsm_channel *)port;
+	struct termios *termios;
 
 	spin_lock_irqsave(&port->lock, lock_flags);
-	if (ch == port->info->tty->termios->c_cc[VSTART])
+	termios = port->info->tty->termios;
+	if (ch == termios->c_cc[VSTART])
 		channel->ch_bd->bd_ops->send_start_character(channel);
 
-	if (ch == port->info->tty->termios->c_cc[VSTOP])
+	if (ch == termios->c_cc[VSTOP])
 		channel->ch_bd->bd_ops->send_stop_character(channel);
 	spin_unlock_irqrestore(&port->lock, lock_flags);
 }
@@ -178,6 +180,7 @@
 	struct jsm_board *brd;
 	int rc = 0;
 	struct jsm_channel *channel = (struct jsm_channel *)port;
+	struct termios *termios;
 
 	/* Get board pointer from our array of majors we have allocated */
 	brd = channel->ch_bd;
@@ -239,12 +242,13 @@
 	channel->ch_cached_lsr = 0;
 	channel->ch_stops_sent = 0;
 
-	channel->ch_c_cflag	= port->info->tty->termios->c_cflag;
-	channel->ch_c_iflag	= port->info->tty->termios->c_iflag;
-	channel->ch_c_oflag	= port->info->tty->termios->c_oflag;
-	channel->ch_c_lflag	= port->info->tty->termios->c_lflag;
-	channel->ch_startc = port->info->tty->termios->c_cc[VSTART];
-	channel->ch_stopc = port->info->tty->termios->c_cc[VSTOP];
+	termios = port->info->tty->termios;
+	channel->ch_c_cflag	= termios->c_cflag;
+	channel->ch_c_iflag	= termios->c_iflag;
+	channel->ch_c_oflag	= termios->c_oflag;
+	channel->ch_c_lflag	= termios->c_lflag;
+	channel->ch_startc	= termios->c_cc[VSTART];
+	channel->ch_stopc	= termios->c_cc[VSTOP];
 
 	/* Tell UART to init itself */
 	brd->bd_ops->uart_init(channel);
@@ -784,6 +788,7 @@
 
 void jsm_check_queue_flow_control(struct jsm_channel *ch)
 {
+	struct board_ops *bd_ops = ch->ch_bd->bd_ops;
 	int qleft = 0;
 
 	/* Store how much space we have left in the queue */
@@ -809,7 +814,7 @@
 		/* HWFLOW */
 		if (ch->ch_c_cflag & CRTSCTS) {
 			if(!(ch->ch_flags & CH_RECEIVER_OFF)) {
-				ch->ch_bd->bd_ops->disable_receiver(ch);
+				bd_ops->disable_receiver(ch);
 				ch->ch_flags |= (CH_RECEIVER_OFF);
 				jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
 					"Internal queue hit hilevel mark (%d)! Turning off interrupts.\n",
@@ -819,7 +824,7 @@
 		/* SWFLOW */
 		else if (ch->ch_c_iflag & IXOFF) {
 			if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
-				ch->ch_bd->bd_ops->send_stop_character(ch);
+				bd_ops->send_stop_character(ch);
 				ch->ch_stops_sent++;
 				jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
 					"Sending stop char! Times sent: %x\n", ch->ch_stops_sent);
@@ -846,7 +851,7 @@
 		/* HWFLOW */
 		if (ch->ch_c_cflag & CRTSCTS) {
 			if (ch->ch_flags & CH_RECEIVER_OFF) {
-				ch->ch_bd->bd_ops->enable_receiver(ch);
+				bd_ops->enable_receiver(ch);
 				ch->ch_flags &= ~(CH_RECEIVER_OFF);
 				jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
 					"Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n",
@@ -856,7 +861,7 @@
 		/* SWFLOW */
 		else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
 			ch->ch_stops_sent = 0;
-			ch->ch_bd->bd_ops->send_start_character(ch);
+			bd_ops->send_start_character(ch);
 			jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n");
 		}
 	}
diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c
index 868eaf4..64c0e89 100644
--- a/drivers/serial/mux.c
+++ b/drivers/serial/mux.c
@@ -51,7 +51,7 @@
 #define MUX_BREAK(status) ((status & 0xF000) == 0x2000)
 
 #define MUX_NR 256
-static unsigned int port_cnt = 0;
+static unsigned int port_cnt __read_mostly;
 static struct uart_port mux_ports[MUX_NR];
 
 static struct uart_driver mux_driver = {
@@ -461,7 +461,7 @@
 		port->iobase	= 0;
 		port->mapbase	= dev->hpa.start + MUX_OFFSET +
 						(i * MUX_LINE_OFFSET);
-		port->membase	= ioremap(port->mapbase, MUX_LINE_OFFSET);
+		port->membase	= ioremap_nocache(port->mapbase, MUX_LINE_OFFSET);
 		port->iotype	= UPIO_MEM;
 		port->type	= PORT_MUX;
 		port->irq	= NO_IRQ;
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index b848b7d..3bdee64 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -483,7 +483,7 @@
 
 	/*
 	 * Clear the FIFO buffers and disable them.
-	 * (they will be reeanbled in set_termios())
+	 * (they will be reenabled in set_termios())
 	 */
 	sio_set(up, TXX9_SIFCR,
 		TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE);
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 9fe2283..1c4396c 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -641,7 +641,7 @@
 
 	/*
 	 * Clear the FIFO buffers and disable them.
-	 * (they will be reeanbled in set_termios())
+	 * (they will be reenabled in set_termios())
 	 */
 	if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
 		serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c
index 3c987f4..e166fff 100644
--- a/drivers/telephony/phonedev.c
+++ b/drivers/telephony/phonedev.c
@@ -29,6 +29,7 @@
 #include <linux/kmod.h>
 #include <linux/sem.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/mutex.h>
 
 #define PHONE_NUM_DEVICES	256
 
@@ -37,7 +38,7 @@
  */
 
 static struct phone_device *phone_device[PHONE_NUM_DEVICES];
-static DECLARE_MUTEX(phone_lock);
+static DEFINE_MUTEX(phone_lock);
 
 /*
  *    Open a phone device.
@@ -48,19 +49,19 @@
 	unsigned int minor = iminor(inode);
 	int err = 0;
 	struct phone_device *p;
-	struct file_operations *old_fops, *new_fops = NULL;
+	const struct file_operations *old_fops, *new_fops = NULL;
 
 	if (minor >= PHONE_NUM_DEVICES)
 		return -ENODEV;
 
-	down(&phone_lock);
+	mutex_lock(&phone_lock);
 	p = phone_device[minor];
 	if (p)
 		new_fops = fops_get(p->f_op);
 	if (!new_fops) {
-		up(&phone_lock);
+		mutex_unlock(&phone_lock);
 		request_module("char-major-%d-%d", PHONE_MAJOR, minor);
-		down(&phone_lock);
+		mutex_lock(&phone_lock);
 		p = phone_device[minor];
 		if (p == NULL || (new_fops = fops_get(p->f_op)) == NULL)
 		{
@@ -78,7 +79,7 @@
 	}
 	fops_put(old_fops);
 end:
-	up(&phone_lock);
+	mutex_unlock(&phone_lock);
 	return err;
 }
 
@@ -100,18 +101,18 @@
 		end = unit + 1;  /* enter the loop at least one time */
 	}
 	
-	down(&phone_lock);
+	mutex_lock(&phone_lock);
 	for (i = base; i < end; i++) {
 		if (phone_device[i] == NULL) {
 			phone_device[i] = p;
 			p->minor = i;
 			devfs_mk_cdev(MKDEV(PHONE_MAJOR,i),
 				S_IFCHR|S_IRUSR|S_IWUSR, "phone/%d", i);
-			up(&phone_lock);
+			mutex_unlock(&phone_lock);
 			return 0;
 		}
 	}
-	up(&phone_lock);
+	mutex_unlock(&phone_lock);
 	return -ENFILE;
 }
 
@@ -121,12 +122,12 @@
 
 void phone_unregister_device(struct phone_device *pfd)
 {
-	down(&phone_lock);
+	mutex_lock(&phone_lock);
 	if (phone_device[pfd->minor] != pfd)
 		panic("phone: bad unregister");
 	devfs_remove("phone/%d", pfd->minor);
 	phone_device[pfd->minor] = NULL;
-	up(&phone_lock);
+	mutex_unlock(&phone_lock);
 }
 
 
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 37b1336..b263a54 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -24,15 +24,15 @@
 #include "usb.h"
 
 #define MAX_USB_MINORS	256
-static struct file_operations *usb_minors[MAX_USB_MINORS];
+static const struct file_operations *usb_minors[MAX_USB_MINORS];
 static DEFINE_SPINLOCK(minor_lock);
 
 static int usb_open(struct inode * inode, struct file * file)
 {
 	int minor = iminor(inode);
-	struct file_operations *c;
+	const struct file_operations *c;
 	int err = -ENODEV;
-	struct file_operations *old_fops, *new_fops = NULL;
+	const struct file_operations *old_fops, *new_fops = NULL;
 
 	spin_lock (&minor_lock);
 	c = usb_minors[minor];
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index e0afb5a..0d2193b 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -296,7 +296,7 @@
 
 #ifdef CONFIG_PPC_PMAC
 		/* Disable ASIC clocks for USB */
-		if (_machine == _MACH_Pmac) {
+		if (machine_is(powermac)) {
 			struct device_node	*of_node;
 
 			of_node = pci_device_to_OF_node (dev);
@@ -331,7 +331,7 @@
 
 #ifdef CONFIG_PPC_PMAC
 	/* Reenable ASIC clocks for USB */
-	if (_machine == _MACH_Pmac) {
+	if (machine_is(powermac)) {
 		struct device_node *of_node;
 
 		of_node = pci_device_to_OF_node (dev);
diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
index 4b55285..fe0ed54 100644
--- a/drivers/usb/core/notify.c
+++ b/drivers/usb/core/notify.c
@@ -16,57 +16,7 @@
 #include <linux/mutex.h>
 #include "usb.h"
 
-
-static struct notifier_block *usb_notifier_list;
-static DEFINE_MUTEX(usb_notifier_lock);
-
-static void usb_notifier_chain_register(struct notifier_block **list,
-					struct notifier_block *n)
-{
-	mutex_lock(&usb_notifier_lock);
-	while (*list) {
-		if (n->priority > (*list)->priority)
-			break;
-		list = &((*list)->next);
-	}
-	n->next = *list;
-	*list = n;
-	mutex_unlock(&usb_notifier_lock);
-}
-
-static void usb_notifier_chain_unregister(struct notifier_block **nl,
-				   struct notifier_block *n)
-{
-	mutex_lock(&usb_notifier_lock);
-	while ((*nl)!=NULL) {
-		if ((*nl)==n) {
-			*nl = n->next;
-			goto exit;
-		}
-		nl=&((*nl)->next);
-	}
-exit:
-	mutex_unlock(&usb_notifier_lock);
-}
-
-static int usb_notifier_call_chain(struct notifier_block **n,
-				   unsigned long val, void *v)
-{
-	int ret=NOTIFY_DONE;
-	struct notifier_block *nb = *n;
-
-	mutex_lock(&usb_notifier_lock);
-	while (nb) {
-		ret = nb->notifier_call(nb,val,v);
-		if (ret&NOTIFY_STOP_MASK) {
-			goto exit;
-		}
-		nb = nb->next;
-	}
-exit:
-	mutex_unlock(&usb_notifier_lock);
-	return ret;
-}
+static BLOCKING_NOTIFIER_HEAD(usb_notifier_list);
 
 /**
  * usb_register_notify - register a notifier callback whenever a usb change happens
@@ -76,7 +26,7 @@
  */
 void usb_register_notify(struct notifier_block *nb)
 {
-	usb_notifier_chain_register(&usb_notifier_list, nb);
+	blocking_notifier_chain_register(&usb_notifier_list, nb);
 }
 EXPORT_SYMBOL_GPL(usb_register_notify);
 
@@ -89,27 +39,28 @@
  */
 void usb_unregister_notify(struct notifier_block *nb)
 {
-	usb_notifier_chain_unregister(&usb_notifier_list, nb);
+	blocking_notifier_chain_unregister(&usb_notifier_list, nb);
 }
 EXPORT_SYMBOL_GPL(usb_unregister_notify);
 
 
 void usb_notify_add_device(struct usb_device *udev)
 {
-	usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev);
+	blocking_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev);
 }
 
 void usb_notify_remove_device(struct usb_device *udev)
 {
-	usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_REMOVE, udev);
+	blocking_notifier_call_chain(&usb_notifier_list,
+			USB_DEVICE_REMOVE, udev);
 }
 
 void usb_notify_add_bus(struct usb_bus *ubus)
 {
-	usb_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus);
+	blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus);
 }
 
 void usb_notify_remove_bus(struct usb_bus *ubus)
 {
-	usb_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus);
+	blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus);
 }
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index b44cfda..3f618ce 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -1581,7 +1581,7 @@
 
 static struct inode *
 gadgetfs_create_file (struct super_block *sb, char const *name,
-		void *data, struct file_operations *fops,
+		void *data, const struct file_operations *fops,
 		struct dentry **dentry_p);
 
 static int activate_ep_files (struct dev_data *dev)
@@ -1955,7 +1955,7 @@
 
 static struct inode *
 gadgetfs_make_inode (struct super_block *sb,
-		void *data, struct file_operations *fops,
+		void *data, const struct file_operations *fops,
 		int mode)
 {
 	struct inode *inode = new_inode (sb);
@@ -1979,7 +1979,7 @@
  */
 static struct inode *
 gadgetfs_create_file (struct super_block *sb, char const *name,
-		void *data, struct file_operations *fops,
+		void *data, const struct file_operations *fops,
 		struct dentry **dentry_p)
 {
 	struct dentry	*dentry;
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index 372527a..682bf22 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -158,7 +158,7 @@
 		"s3c2410_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n",
 		hcd, typeReq, wValue, wIndex, buf, wLength);
 
-	/* if we are only an humble host without any special capabilites
+	/* if we are only an humble host without any special capabilities
 	 * process the request straight away and exit */
 
 	if (info == NULL) {
diff --git a/drivers/usb/net/zaurus.c b/drivers/usb/net/zaurus.c
index 9c5ab25..f7ac9d6 100644
--- a/drivers/usb/net/zaurus.c
+++ b/drivers/usb/net/zaurus.c
@@ -217,7 +217,7 @@
 			 * with devices that use it and those that don't.
 			 */
 			if ((detail->bDetailData[1] & ~0x02) != 0x01) {
-				/* bmDataCapabilites == 0 would be fine too,
+				/* bmDataCapabilities == 0 would be fine too,
 				 * but framing is minidriver-coupled for now.
 				 */
 bad_detail:
diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c
index fe9b60c..9b1e4ed 100644
--- a/drivers/usb/net/zd1201.c
+++ b/drivers/usb/net/zd1201.c
@@ -1736,6 +1736,7 @@
 	.standard 		= (iw_handler *)zd1201_iw_handler,
 	.private 		= (iw_handler *)zd1201_private_handler,
 	.private_args 		= (struct iw_priv_args *) zd1201_private_args,
+	.get_wireless_stats	= zd1201_get_wireless_stats,
 };
 
 static int zd1201_probe(struct usb_interface *interface,
@@ -1796,7 +1797,6 @@
 	zd->dev->open = zd1201_net_open;
 	zd->dev->stop = zd1201_net_stop;
 	zd->dev->get_stats = zd1201_get_stats;
-	zd->dev->get_wireless_stats = zd1201_get_wireless_stats;
 	zd->dev->wireless_handlers =
 	    (struct iw_handler_def *)&zd1201_iw_handlers;
 	zd->dev->hard_start_xmit = zd1201_hard_start_xmit;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index fdebd60..f87c017 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -70,6 +70,22 @@
        depends on FB
        default n
 
+config FB_FIRMWARE_EDID
+       bool "Enable firmware EDID"
+       depends on FB
+       default y
+       ---help---
+         This enables access to the EDID transferred from the firmware.
+	 On the i386, this is from the Video BIOS. Enable this if DDC/I2C
+	 transfers do not work for your driver and if you are using
+	 nvidiafb, i810fb or savagefb.
+
+	 In general, choosing Y for this option is safe.  If you
+	 experience extremely long delays while booting before you get
+	 something on your display, try setting this to N.  Matrox cards in
+	 combination with certain motherboards and monitors are known to
+	 suffer from this problem.
+
 config FB_MODE_HELPERS
         bool "Enable Video Mode Handling Helpers"
         depends on FB
@@ -888,18 +904,6 @@
 	  There is no need for enabling 'Matrox multihead support' if you have
 	  only one Matrox card in the box.
 
-config FB_RADEON_OLD
-	tristate "ATI Radeon display support (Old driver)"
-	depends on FB && PCI
-	select FB_CFB_FILLRECT
-	select FB_CFB_COPYAREA
-	select FB_CFB_IMAGEBLIT
-	select FB_MACMODES if PPC
-	help
-	  Choose this option if you want to use an ATI Radeon graphics card as
-	  a framebuffer device.  There are both PCI and AGP versions.  You
-	  don't need to choose this to run the Radeon in plain VGA mode.
-
 config FB_RADEON
 	tristate "ATI Radeon display support"
 	depends on FB && PCI
@@ -1202,6 +1206,17 @@
 	bool "Au1100 LCD Driver"
 	depends on (FB = y) && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y
 
+config FB_AU1200
+	bool "Au1200 LCD Driver"
+	depends on FB && MIPS && SOC_AU1200
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This is the framebuffer driver for the AMD Au1200 SOC.  It can drive
+	  various panels and CRTs by passing in kernel cmd line option
+	  au1200fb:panel=<name>.
+
 source "drivers/video/geode/Kconfig"
 
 config FB_FFB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index aa434e7..23de3b2 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -39,7 +39,6 @@
 obj-$(CONFIG_FB_SAVAGE)		  += savage/
 obj-$(CONFIG_FB_GEODE)		  += geode/
 obj-$(CONFIG_FB_I810)             += vgastate.o
-obj-$(CONFIG_FB_RADEON_OLD)	  += radeonfb.o
 obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o vgastate.o
 obj-$(CONFIG_FB_VIRGE)            += virgefb.o
 obj-$(CONFIG_FB_3DFX)             += tdfxfb.o
@@ -86,6 +85,7 @@
 obj-$(CONFIG_FB_PXA)		  += pxafb.o
 obj-$(CONFIG_FB_W100)		  += w100fb.o
 obj-$(CONFIG_FB_AU1100)		  += au1100fb.o
+obj-$(CONFIG_FB_AU1200)		  += au1200fb.o
 obj-$(CONFIG_FB_PMAG_AA)	  += pmag-aa-fb.o
 obj-$(CONFIG_FB_PMAG_BA)	  += pmag-ba-fb.o
 obj-$(CONFIG_FB_PMAGB_B)	  += pmagb-b-fb.o
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
index 76448d6..98baecc 100644
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -1308,7 +1308,7 @@
 	/*
 	 * Try to select a suitable default mode
 	 */
-	for (i = 0; i < sizeof(modedb) / sizeof(*modedb); i++) {
+	for (i = 0; i < ARRAY_SIZE(modedb); i++) {
 		unsigned long hs;
 
 		hs = modedb[i].refresh *
@@ -1380,7 +1380,7 @@
 	 */
 	free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE);
 #endif
-	
+
 	fb_info.fix.smem_len = size;
 	current_par.palette_size   = VIDC_PALETTE_SIZE;
 
@@ -1391,7 +1391,7 @@
 	 */
 	do {
 		rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb,
-				 sizeof(modedb) / sizeof(*modedb),
+				 ARRAY_SIZE(modedb),
 				 &acornfb_default_mode, DEFAULT_BPP);
 		/*
 		 * If we found an exact match, all ok.
@@ -1408,7 +1408,7 @@
 			break;
 
 		rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb,
-				 sizeof(modedb) / sizeof(*modedb),
+				 ARRAY_SIZE(modedb),
 				 &acornfb_default_mode, DEFAULT_BPP);
 		if (rc)
 			break;
diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c
index c924d81..29f9f0d 100644
--- a/drivers/video/asiliantfb.c
+++ b/drivers/video/asiliantfb.c
@@ -353,8 +353,6 @@
 	unsigned char data;
 };
 
-#define N_ELTS(x)	(sizeof(x) / sizeof(x[0]))
-
 static struct chips_init_reg chips_init_sr[] =
 {
 	{0x00, 0x03},		/* Reset register */
@@ -460,22 +458,22 @@
 {
 	int i;
 
-	for (i = 0; i < N_ELTS(chips_init_xr); ++i)
+	for (i = 0; i < ARRAY_SIZE(chips_init_xr); ++i)
 		write_xr(chips_init_xr[i].addr, chips_init_xr[i].data);
 	write_xr(0x81, 0x12);
 	write_xr(0x82, 0x08);
 	write_xr(0x20, 0x00);
-	for (i = 0; i < N_ELTS(chips_init_sr); ++i)
+	for (i = 0; i < ARRAY_SIZE(chips_init_sr); ++i)
 		write_sr(chips_init_sr[i].addr, chips_init_sr[i].data);
-	for (i = 0; i < N_ELTS(chips_init_gr); ++i)
+	for (i = 0; i < ARRAY_SIZE(chips_init_gr); ++i)
 		write_gr(chips_init_gr[i].addr, chips_init_gr[i].data);
-	for (i = 0; i < N_ELTS(chips_init_ar); ++i)
+	for (i = 0; i < ARRAY_SIZE(chips_init_ar); ++i)
 		write_ar(chips_init_ar[i].addr, chips_init_ar[i].data);
 	/* Enable video output in attribute index register */
 	writeb(0x20, mmio_base + 0x780);
-	for (i = 0; i < N_ELTS(chips_init_cr); ++i)
+	for (i = 0; i < ARRAY_SIZE(chips_init_cr); ++i)
 		write_cr(chips_init_cr[i].addr, chips_init_cr[i].data);
-	for (i = 0; i < N_ELTS(chips_init_fr); ++i)
+	for (i = 0; i < ARRAY_SIZE(chips_init_fr); ++i)
 		write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
 }
 
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 620c9a9..f7bbff4 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -67,6 +67,7 @@
 #include <asm/io.h>
 
 #ifdef CONFIG_PPC_PMAC
+#include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
@@ -1725,9 +1726,9 @@
 	strcpy(video_card, "Rage128 XX ");
 	video_card[8] = ent->device >> 8;
 	video_card[9] = ent->device & 0xFF;
-	    
+
 	/* range check to make sure */
-	if (ent->driver_data < (sizeof(r128_family)/sizeof(char *)))
+	if (ent->driver_data < ARRAY_SIZE(r128_family))
 	    strncat(video_card, r128_family[ent->driver_data], sizeof(video_card));
 
 	printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev);
@@ -1748,7 +1749,7 @@
 
 	var = default_var;
 #ifdef CONFIG_PPC_PMAC
-	if (_machine == _MACH_Pmac) {
+	if (machine_is(powermac)) {
 		/* Indicate sleep capability */
 		if (par->chip_gen == rage_M3) {
 			pmac_call_feature(PMAC_FTR_DEVICE_CAN_WAKE, NULL, 0, 1);
@@ -2011,7 +2012,7 @@
 		return 0;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if ((_machine == _MACH_Pmac) && blank)
+	if (machine_is(powermac) && blank)
 		set_backlight_enable(0);
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
@@ -2029,7 +2030,7 @@
 		aty128_set_lcd_enable(par, par->lcd_on && !blank);
 	}
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if ((_machine == _MACH_Pmac) && !blank)
+	if (machine_is(powermac) && !blank)
 		set_backlight_enable(1);
 #endif /* CONFIG_PMAC_BACKLIGHT */
 	return 0;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 485be38..b39e72d 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -75,6 +75,7 @@
 #include "ati_ids.h"
 
 #ifdef __powerpc__
+#include <asm/machdep.h>
 #include <asm/prom.h>
 #include "../macmodes.h"
 #endif
@@ -434,7 +435,7 @@
 	const char *name;
 	int i;
 
-	for (i = sizeof(aty_chips) / sizeof(*aty_chips) - 1; i >= 0; i--)
+	for (i = ARRAY_SIZE(aty_chips) - 1; i >= 0; i--)
 		if (par->pci_id == aty_chips[i].pci_id)
 			break;
 
@@ -2168,10 +2169,10 @@
 
 	if (IS_XL(par->pci_id) || IS_MOBILITY(par->pci_id)) {
 		refresh_tbl = ragexl_tbl;
-		size = sizeof(ragexl_tbl)/sizeof(int);
+		size = ARRAY_SIZE(ragexl_tbl);
 	} else {
 		refresh_tbl = ragepro_tbl;
-		size = sizeof(ragepro_tbl)/sizeof(int);
+		size = ARRAY_SIZE(ragepro_tbl);
 	}
 
 	for (i=0; i < size; i++) {
@@ -2298,6 +2299,10 @@
 		case CLK_ATI18818_1:
 			par->pll_ops = &aty_pll_ati18818_1;
 			break;
+		case CLK_IBMRGB514:
+			par->pll_ops = &aty_pll_ibm514;
+			break;
+#if 0 /* dead code */
 		case CLK_STG1703:
 			par->pll_ops = &aty_pll_stg1703;
 			break;
@@ -2307,9 +2312,7 @@
 		case CLK_ATT20C408:
 			par->pll_ops = &aty_pll_att20c408;
 			break;
-		case CLK_IBMRGB514:
-			par->pll_ops = &aty_pll_ibm514;
-			break;
+#endif
 		default:
 			PRINTKI("aty_init: CLK type not implemented yet!");
 			par->pll_ops = &aty_pll_unsupported;
@@ -2516,7 +2519,7 @@
 
 	memset(&var, 0, sizeof(var));
 #ifdef CONFIG_PPC
-	if (_machine == _MACH_Pmac) {
+	if (machine_is(powermac)) {
 		/*
 		 *  FIXME: The NVRAM stuff should be put in a Mac-specific file, as it
 		 *         applies to all Mac video cards
@@ -2671,7 +2674,7 @@
 		return 0;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if ((_machine == _MACH_Pmac) && blank > FB_BLANK_NORMAL)
+	if (machine_is(powermac) && blank > FB_BLANK_NORMAL)
 		set_backlight_enable(0);
 #elif defined(CONFIG_FB_ATY_GENERIC_LCD)
 	if (par->lcd_table && blank > FB_BLANK_NORMAL &&
@@ -2703,7 +2706,7 @@
 	aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if ((_machine == _MACH_Pmac) && blank <= FB_BLANK_NORMAL)
+	if (machine_is(powermac) && blank <= FB_BLANK_NORMAL)
 		set_backlight_enable(1);
 #elif defined(CONFIG_FB_ATY_GENERIC_LCD)
 	if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
@@ -3397,7 +3400,7 @@
 	struct atyfb_par *par;
 	int i, rc = -ENOMEM;
 
-	for (i = sizeof(aty_chips) / sizeof(*aty_chips) - 1; i >= 0; i--)
+	for (i = ARRAY_SIZE(aty_chips); i >= 0; i--)
 		if (pdev->device == aty_chips[i].pci_id)
 			break;
 
diff --git a/drivers/video/aty/mach64_gx.c b/drivers/video/aty/mach64_gx.c
index 01fdff7..2045639 100644
--- a/drivers/video/aty/mach64_gx.c
+++ b/drivers/video/aty/mach64_gx.c
@@ -149,8 +149,7 @@
 	};
 	int i;
 
-	for (i = 0; i < sizeof(RGB514_clocks) / sizeof(*RGB514_clocks);
-	     i++)
+	for (i = 0; i < ARRAY_SIZE(RGB514_clocks); i++)
 		if (vclk_per <= RGB514_clocks[i].limit) {
 			pll->ibm514.m = RGB514_clocks[i].m;
 			pll->ibm514.n = RGB514_clocks[i].n;
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index c9f0c5a..9a6b5b3 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -1067,7 +1067,7 @@
 
 
 	if (regno > 255)
-		return 1;
+		return -EINVAL;
 
 	red >>= 8;
 	green >>= 8;
@@ -1086,9 +1086,9 @@
 			pindex = regno * 8;
 
 			if (rinfo->depth == 16 && regno > 63)
-				return 1;
+				return -EINVAL;
 			if (rinfo->depth == 15 && regno > 31)
-				return 1;
+				return -EINVAL;
 
 			/* For 565, the green component is mixed one order
 			 * below
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index 5886a2f..c709176 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -20,7 +20,7 @@
 #include <linux/agp_backend.h>
 
 #ifdef CONFIG_PPC_PMAC
-#include <asm/processor.h>
+#include <asm/machdep.h>
 #include <asm/prom.h>
 #include <asm/pmac_feature.h>
 #endif
@@ -2745,7 +2745,7 @@
 		rinfo->pm_mode |= radeon_pm_off;
 	}
 #if defined(CONFIG_PPC_PMAC)
-	if (_machine == _MACH_Pmac && rinfo->of_node) {
+	if (machine_is(powermac) && rinfo->of_node) {
 		if (rinfo->is_mobility && rinfo->pm_reg &&
 		    rinfo->family <= CHIP_FAMILY_RV250)
 			rinfo->pm_mode |= radeon_pm_d2;
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
new file mode 100644
index 0000000..b367de3
--- /dev/null
+++ b/drivers/video/au1200fb.c
@@ -0,0 +1,3844 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Au1200 LCD Driver.
+ *
+ * Copyright 2004-2005 AMD
+ * Author: AMD
+ *
+ * Based on:
+ * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
+ *  Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ *  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  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include "au1200fb.h"
+
+#ifdef CONFIG_PM
+#include <asm/mach-au1x00/au1xxx_pm.h>
+#endif
+
+#ifndef CONFIG_FB_AU1200_DEVS
+#define CONFIG_FB_AU1200_DEVS 4
+#endif
+
+#define DRIVER_NAME "au1200fb"
+#define DRIVER_DESC "LCD controller driver for AU1200 processors"
+
+#define DEBUG 1
+
+#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
+#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
+#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
+
+#if DEBUG
+#define print_dbg(f, arg...) printk(KERN_DEBUG __FILE__ ": " f "\n", ## arg)
+#else
+#define print_dbg(f, arg...) do {} while (0)
+#endif
+
+
+#define AU1200_LCD_FB_IOCTL 0x46FF
+
+#define AU1200_LCD_SET_SCREEN 1
+#define AU1200_LCD_GET_SCREEN 2
+#define AU1200_LCD_SET_WINDOW 3
+#define AU1200_LCD_GET_WINDOW 4
+#define AU1200_LCD_SET_PANEL  5
+#define AU1200_LCD_GET_PANEL  6
+
+#define SCREEN_SIZE		    (1<< 1)
+#define SCREEN_BACKCOLOR    (1<< 2)
+#define SCREEN_BRIGHTNESS   (1<< 3)
+#define SCREEN_COLORKEY     (1<< 4)
+#define SCREEN_MASK         (1<< 5)
+
+struct au1200_lcd_global_regs_t {
+	unsigned int flags;
+	unsigned int xsize;
+	unsigned int ysize;
+	unsigned int backcolor;
+	unsigned int brightness;
+	unsigned int colorkey;
+	unsigned int mask;
+	unsigned int panel_choice;
+	char panel_desc[80];
+
+};
+
+#define WIN_POSITION            (1<< 0)
+#define WIN_ALPHA_COLOR         (1<< 1)
+#define WIN_ALPHA_MODE          (1<< 2)
+#define WIN_PRIORITY            (1<< 3)
+#define WIN_CHANNEL             (1<< 4)
+#define WIN_BUFFER_FORMAT       (1<< 5)
+#define WIN_COLOR_ORDER         (1<< 6)
+#define WIN_PIXEL_ORDER         (1<< 7)
+#define WIN_SIZE                (1<< 8)
+#define WIN_COLORKEY_MODE       (1<< 9)
+#define WIN_DOUBLE_BUFFER_MODE  (1<< 10)
+#define WIN_RAM_ARRAY_MODE      (1<< 11)
+#define WIN_BUFFER_SCALE        (1<< 12)
+#define WIN_ENABLE	            (1<< 13)
+
+struct au1200_lcd_window_regs_t {
+	unsigned int flags;
+	unsigned int xpos;
+	unsigned int ypos;
+	unsigned int alpha_color;
+	unsigned int alpha_mode;
+	unsigned int priority;
+	unsigned int channel;
+	unsigned int buffer_format;
+	unsigned int color_order;
+	unsigned int pixel_order;
+	unsigned int xsize;
+	unsigned int ysize;
+	unsigned int colorkey_mode;
+	unsigned int double_buffer_mode;
+	unsigned int ram_array_mode;
+	unsigned int xscale;
+	unsigned int yscale;
+	unsigned int enable;
+};
+
+
+struct au1200_lcd_iodata_t {
+	unsigned int subcmd;
+	struct au1200_lcd_global_regs_t global;
+	struct au1200_lcd_window_regs_t window;
+};
+
+#if defined(__BIG_ENDIAN)
+#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11
+#else
+#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00
+#endif
+#define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565
+
+/* Private, per-framebuffer management information (independent of the panel itself) */
+struct au1200fb_device {
+	struct fb_info fb_info;			/* FB driver info record */
+
+	int					plane;
+	unsigned char* 		fb_mem;		/* FrameBuffer memory map */
+	unsigned int		fb_len;
+	dma_addr_t    		fb_phys;
+};
+
+static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS];
+/********************************************************************/
+
+/* LCD controller restrictions */
+#define AU1200_LCD_MAX_XRES	1280
+#define AU1200_LCD_MAX_YRES	1024
+#define AU1200_LCD_MAX_BPP	32
+#define AU1200_LCD_MAX_CLK	96000000 /* fixme: this needs to go away ? */
+#define AU1200_LCD_NBR_PALETTE_ENTRIES 256
+
+/* Default number of visible screen buffer to allocate */
+#define AU1200FB_NBR_VIDEO_BUFFERS 1
+
+/********************************************************************/
+
+static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR;
+static int window_index = 2; /* default is zero */
+static int panel_index = 2; /* default is zero */
+static struct window_settings *win;
+static struct panel_settings *panel;
+static int noblanking = 1;
+static int nohwcursor = 0;
+
+struct window_settings {
+	unsigned char name[64];
+	uint32 mode_backcolor;
+	uint32 mode_colorkey;
+	uint32 mode_colorkeymsk;
+	struct {
+		int xres;
+		int yres;
+		int xpos;
+		int ypos;
+		uint32 mode_winctrl1; /* winctrl1[FRM,CCO,PO,PIPE] */
+		uint32 mode_winenable;
+	} w[4];
+};
+
+#if defined(__BIG_ENDIAN)
+#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00
+#else
+#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
+#endif
+
+extern int board_au1200fb_panel_init (void);
+extern int board_au1200fb_panel_shutdown (void);
+
+#ifdef CONFIG_PM
+int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
+		au1xxx_request_t request, void *data);
+au1xxx_power_dev_t *LCD_pm_dev;
+#endif
+
+/*
+ * Default window configurations
+ */
+static struct window_settings windows[] = {
+	{ /* Index 0 */
+		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
+		/* mode_backcolor	*/ 0x006600ff,
+		/* mode_colorkey,msk*/ 0, 0,
+		{
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ LCD_WINENABLE_WEN0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 100, 100, 100, 100,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ LCD_WINENABLE_WEN1,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ 0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0,
+			},
+		},
+	},
+
+	{ /* Index 1 */
+		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
+		/* mode_backcolor	*/ 0x006600ff,
+		/* mode_colorkey,msk*/ 0, 0,
+		{
+			{
+			/* xres, yres, xpos, ypos */ 320, 240, 5, 5,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_24BPP |
+				LCD_WINCTRL1_PO_00,
+			/* mode_winenable*/ LCD_WINENABLE_WEN0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565
+				| LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ 0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 100, 100, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 200, 25, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0,
+			},
+		},
+	},
+	{ /* Index 2 */
+		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
+		/* mode_backcolor	*/ 0x006600ff,
+		/* mode_colorkey,msk*/ 0, 0,
+		{
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ LCD_WINENABLE_WEN0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ 0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_32BPP |
+				LCD_WINCTRL1_PO_00|LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0,
+			},
+		},
+	},
+	/* Need VGA 640 @ 24bpp, @ 32bpp */
+	/* Need VGA 800 @ 24bpp, @ 32bpp */
+	/* Need VGA 1024 @ 24bpp, @ 32bpp */
+};
+
+/*
+ * Controller configurations for various panels.
+ */
+
+struct panel_settings
+{
+	const char name[25];		/* Full name <vendor>_<model> */
+
+	struct 	fb_monspecs monspecs; 	/* FB monitor specs */
+
+	/* panel timings */
+	uint32 mode_screen;
+	uint32 mode_horztiming;
+	uint32 mode_verttiming;
+	uint32 mode_clkcontrol;
+	uint32 mode_pwmdiv;
+	uint32 mode_pwmhi;
+	uint32 mode_outmask;
+	uint32 mode_fifoctrl;
+	uint32 mode_toyclksrc;
+	uint32 mode_backlight;
+	uint32 mode_auxpll;
+	int (*device_init)(void);
+	int (*device_shutdown)(void);
+#define Xres min_xres
+#define Yres min_yres
+	u32	min_xres;		/* Minimum horizontal resolution */
+	u32	max_xres;		/* Maximum horizontal resolution */
+	u32 	min_yres;		/* Minimum vertical resolution */
+	u32 	max_yres;		/* Maximum vertical resolution */
+};
+
+/********************************************************************/
+/* fixme: Maybe a modedb for the CRT ? otherwise panels should be as-is */
+
+/* List of panels known to work with the AU1200 LCD controller.
+ * To add a new panel, enter the same specifications as the
+ * Generic_TFT one, and MAKE SURE that it doesn't conflicts
+ * with the controller restrictions. Restrictions are:
+ *
+ * STN color panels: max_bpp <= 12
+ * STN mono panels: max_bpp <= 4
+ * TFT panels: max_bpp <= 16
+ * max_xres <= 800
+ * max_yres <= 600
+ */
+static struct panel_settings known_lcd_panels[] =
+{
+	[0] = { /* QVGA 320x240 H:33.3kHz V:110Hz */
+		.name = "QVGA_320x240",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(320) |
+			LCD_SCREEN_SY_N(240),
+		.mode_horztiming	= 0x00c4623b,
+		.mode_verttiming	= 0x00502814,
+		.mode_clkcontrol	= 0x00020002, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		320, 320,
+		240, 240,
+	},
+
+	[1] = { /* VGA 640x480 H:30.3kHz V:58Hz */
+		.name = "VGA_640x480",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x13f9df80,
+		.mode_horztiming	= 0x003c5859,
+		.mode_verttiming	= 0x00741201,
+		.mode_clkcontrol	= 0x00020001, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		640, 480,
+		640, 480,
+	},
+
+	[2] = { /* SVGA 800x600 H:46.1kHz V:69Hz */
+		.name = "SVGA_800x600",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x18fa5780,
+		.mode_horztiming	= 0x00dc7e77,
+		.mode_verttiming	= 0x00584805,
+		.mode_clkcontrol	= 0x00020000, /* /2=48Mhz */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		800, 800,
+		600, 600,
+	},
+
+	[3] = { /* XVGA 1024x768 H:56.2kHz V:70Hz */
+		.name = "XVGA_1024x768",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x1ffaff80,
+		.mode_horztiming	= 0x007d0e57,
+		.mode_verttiming	= 0x00740a01,
+		.mode_clkcontrol	= 0x000A0000, /* /1 */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 6, /* 72MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		1024, 1024,
+		768, 768,
+	},
+
+	[4] = { /* XVGA XVGA 1280x1024 H:68.5kHz V:65Hz */
+		.name = "XVGA_1280x1024",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x27fbff80,
+		.mode_horztiming	= 0x00cdb2c7,
+		.mode_verttiming	= 0x00600002,
+		.mode_clkcontrol	= 0x000A0000, /* /1 */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 10, /* 120MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		1280, 1280,
+		1024, 1024,
+	},
+
+	[5] = { /* Samsung 1024x768 TFT */
+		.name = "Samsung_1024x768_TFT",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x1ffaff80,
+		.mode_horztiming	= 0x018cc677,
+		.mode_verttiming	= 0x00241217,
+		.mode_clkcontrol	= 0x00000000, /* SCB 0x1 /4=24Mhz */
+		.mode_pwmdiv		= 0x8000063f, /* SCB 0x0 */
+		.mode_pwmhi		= 0x03400000, /* SCB 0x0 */
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		1024, 1024,
+		768, 768,
+	},
+
+	[6] = { /* Toshiba 640x480 TFT */
+		.name = "Toshiba_640x480_TFT",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(640) |
+			LCD_SCREEN_SY_N(480),
+		.mode_horztiming	= LCD_HORZTIMING_HPW_N(96) |
+			LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(51),
+		.mode_verttiming	= LCD_VERTTIMING_VPW_N(2) |
+			LCD_VERTTIMING_VND1_N(11) | LCD_VERTTIMING_VND2_N(32),
+		.mode_clkcontrol	= 0x00000000, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x8000063f,
+		.mode_pwmhi		= 0x03400000,
+		.mode_outmask	= 0x00fcfcfc,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		640, 480,
+		640, 480,
+	},
+
+	[7] = { /* Sharp 320x240 TFT */
+		.name = "Sharp_320x240_TFT",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 12500,
+			.hfmax = 20000,
+			.vfmin = 38,
+			.vfmax = 81,
+			.dclkmin = 4500000,
+			.dclkmax = 6800000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(320) |
+			LCD_SCREEN_SY_N(240),
+		.mode_horztiming	= LCD_HORZTIMING_HPW_N(60) |
+			LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(2),
+		.mode_verttiming	= LCD_VERTTIMING_VPW_N(2) |
+			LCD_VERTTIMING_VND1_N(2) | LCD_VERTTIMING_VND2_N(5),
+		.mode_clkcontrol	= LCD_CLKCONTROL_PCD_N(7), /*16=6Mhz*/
+		.mode_pwmdiv		= 0x8000063f,
+		.mode_pwmhi		= 0x03400000,
+		.mode_outmask	= 0x00fcfcfc,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		320, 320,
+		240, 240,
+	},
+
+	[8] = { /* Toppoly TD070WGCB2 7" 856x480 TFT */
+		.name = "Toppoly_TD070WGCB2",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(856) |
+			LCD_SCREEN_SY_N(480),
+		.mode_horztiming	= LCD_HORZTIMING_HND2_N(43) |
+			LCD_HORZTIMING_HND1_N(43) | LCD_HORZTIMING_HPW_N(114),
+		.mode_verttiming	= LCD_VERTTIMING_VND2_N(20) |
+			LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4),
+		.mode_clkcontrol	= 0x00020001, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x8000063f,
+		.mode_pwmhi		= 0x03400000,
+		.mode_outmask	= 0x00fcfcfc,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		856, 856,
+		480, 480,
+	},
+};
+
+#define NUM_PANELS (ARRAY_SIZE(known_lcd_panels))
+
+/********************************************************************/
+
+#ifdef CONFIG_PM
+static int set_brightness(unsigned int brightness)
+{
+	unsigned int hi1, divider;
+
+	/* limit brightness pwm duty to >= 30/1600 */
+	if (brightness < 30) {
+		brightness = 30;
+	}
+	divider = (lcd->pwmdiv & 0x3FFFF) + 1;
+	hi1 = (lcd->pwmhi >> 16) + 1;
+	hi1 = (((brightness & 0xFF) + 1) * divider >> 8);
+	lcd->pwmhi &= 0xFFFF;
+	lcd->pwmhi |= (hi1 << 16);
+
+	return brightness;
+}
+#endif /* CONFIG_PM */
+
+static int winbpp (unsigned int winctrl1)
+{
+	int bits = 0;
+
+	/* how many bits are needed for each pixel format */
+	switch (winctrl1 & LCD_WINCTRL1_FRM) {
+	case LCD_WINCTRL1_FRM_1BPP:
+		bits = 1;
+		break;
+	case LCD_WINCTRL1_FRM_2BPP:
+		bits = 2;
+		break;
+	case LCD_WINCTRL1_FRM_4BPP:
+		bits = 4;
+		break;
+	case LCD_WINCTRL1_FRM_8BPP:
+		bits = 8;
+		break;
+	case LCD_WINCTRL1_FRM_12BPP:
+	case LCD_WINCTRL1_FRM_16BPP655:
+	case LCD_WINCTRL1_FRM_16BPP565:
+	case LCD_WINCTRL1_FRM_16BPP556:
+	case LCD_WINCTRL1_FRM_16BPPI1555:
+	case LCD_WINCTRL1_FRM_16BPPI5551:
+	case LCD_WINCTRL1_FRM_16BPPA1555:
+	case LCD_WINCTRL1_FRM_16BPPA5551:
+		bits = 16;
+		break;
+	case LCD_WINCTRL1_FRM_24BPP:
+	case LCD_WINCTRL1_FRM_32BPP:
+		bits = 32;
+		break;
+	}
+
+	return bits;
+}
+
+static int fbinfo2index (struct fb_info *fb_info)
+{
+	int i;
+
+	for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) {
+		if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info))
+			return i;
+	}
+	printk("au1200fb: ERROR: fbinfo2index failed!\n");
+	return -1;
+}
+
+static int au1200_setlocation (struct au1200fb_device *fbdev, int plane,
+	int xpos, int ypos)
+{
+	uint32 winctrl0, winctrl1, winenable, fb_offset = 0;
+	int xsz, ysz;
+
+	/* FIX!!! NOT CHECKING FOR COMPLETE OFFSCREEN YET */
+
+	winctrl0 = lcd->window[plane].winctrl0;
+	winctrl1 = lcd->window[plane].winctrl1;
+	winctrl0 &= (LCD_WINCTRL0_A | LCD_WINCTRL0_AEN);
+	winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY);
+
+	/* Check for off-screen adjustments */
+	xsz = win->w[plane].xres;
+	ysz = win->w[plane].yres;
+	if ((xpos + win->w[plane].xres) > panel->Xres) {
+		/* Off-screen to the right */
+		xsz = panel->Xres - xpos; /* off by 1 ??? */
+		/*printk("off screen right\n");*/
+	}
+
+	if ((ypos + win->w[plane].yres) > panel->Yres) {
+		/* Off-screen to the bottom */
+		ysz = panel->Yres - ypos; /* off by 1 ??? */
+		/*printk("off screen bottom\n");*/
+	}
+
+	if (xpos < 0) {
+		/* Off-screen to the left */
+		xsz = win->w[plane].xres + xpos;
+		fb_offset += (((0 - xpos) * winbpp(lcd->window[plane].winctrl1))/8);
+		xpos = 0;
+		/*printk("off screen left\n");*/
+	}
+
+	if (ypos < 0) {
+		/* Off-screen to the top */
+		ysz = win->w[plane].yres + ypos;
+		/* fixme: fb_offset += ((0-ypos)*fb_pars[plane].line_length); */
+		ypos = 0;
+		/*printk("off screen top\n");*/
+	}
+
+	/* record settings */
+	win->w[plane].xpos = xpos;
+	win->w[plane].ypos = ypos;
+
+	xsz -= 1;
+	ysz -= 1;
+	winctrl0 |= (xpos << 21);
+	winctrl0 |= (ypos << 10);
+	winctrl1 |= (xsz << 11);
+	winctrl1 |= (ysz << 0);
+
+	/* Disable the window while making changes, then restore WINEN */
+	winenable = lcd->winenable & (1 << plane);
+	au_sync();
+	lcd->winenable &= ~(1 << plane);
+	lcd->window[plane].winctrl0 = winctrl0;
+	lcd->window[plane].winctrl1 = winctrl1;
+	lcd->window[plane].winbuf0 =
+	lcd->window[plane].winbuf1 = fbdev->fb_phys;
+	lcd->window[plane].winbufctrl = 0; /* select winbuf0 */
+	lcd->winenable |= winenable;
+	au_sync();
+
+	return 0;
+}
+
+static void au1200_setpanel (struct panel_settings *newpanel)
+{
+	/*
+	 * Perform global setup/init of LCD controller
+	 */
+	uint32 winenable;
+
+	/* Make sure all windows disabled */
+	winenable = lcd->winenable;
+	lcd->winenable = 0;
+	au_sync();
+	/*
+	 * Ensure everything is disabled before reconfiguring
+	 */
+	if (lcd->screen & LCD_SCREEN_SEN) {
+		/* Wait for vertical sync period */
+		lcd->intstatus = LCD_INT_SS;
+		while ((lcd->intstatus & LCD_INT_SS) == 0) {
+			au_sync();
+		}
+
+		lcd->screen &= ~LCD_SCREEN_SEN;	/*disable the controller*/
+
+		do {
+			lcd->intstatus = lcd->intstatus; /*clear interrupts*/
+			au_sync();
+		/*wait for controller to shut down*/
+		} while ((lcd->intstatus & LCD_INT_SD) == 0);
+
+		/* Call shutdown of current panel (if up) */
+		/* this must occur last, because if an external clock is driving
+		    the controller, the clock cannot be turned off before first
+			shutting down the controller.
+		 */
+		if (panel->device_shutdown != NULL)
+			panel->device_shutdown();
+	}
+
+	/* Newpanel == NULL indicates a shutdown operation only */
+	if (newpanel == NULL)
+		return;
+
+	panel = newpanel;
+
+	printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres);
+
+	/*
+	 * Setup clocking if internal LCD clock source (assumes sys_auxpll valid)
+	 */
+	if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT))
+	{
+		uint32 sys_clksrc;
+		au_writel(panel->mode_auxpll, SYS_AUXPLL);
+		sys_clksrc = au_readl(SYS_CLKSRC) & ~0x0000001f;
+		sys_clksrc |= panel->mode_toyclksrc;
+		au_writel(sys_clksrc, SYS_CLKSRC);
+	}
+
+	/*
+	 * Configure panel timings
+	 */
+	lcd->screen = panel->mode_screen;
+	lcd->horztiming = panel->mode_horztiming;
+	lcd->verttiming = panel->mode_verttiming;
+	lcd->clkcontrol = panel->mode_clkcontrol;
+	lcd->pwmdiv = panel->mode_pwmdiv;
+	lcd->pwmhi = panel->mode_pwmhi;
+	lcd->outmask = panel->mode_outmask;
+	lcd->fifoctrl = panel->mode_fifoctrl;
+	au_sync();
+
+	/* fixme: Check window settings to make sure still valid
+	 * for new geometry */
+#if 0
+	au1200_setlocation(fbdev, 0, win->w[0].xpos, win->w[0].ypos);
+	au1200_setlocation(fbdev, 1, win->w[1].xpos, win->w[1].ypos);
+	au1200_setlocation(fbdev, 2, win->w[2].xpos, win->w[2].ypos);
+	au1200_setlocation(fbdev, 3, win->w[3].xpos, win->w[3].ypos);
+#endif
+	lcd->winenable = winenable;
+
+	/*
+	 * Re-enable screen now that it is configured
+	 */
+	lcd->screen |= LCD_SCREEN_SEN;
+	au_sync();
+
+	/* Call init of panel */
+	if (panel->device_init != NULL) panel->device_init();
+
+	/* FIX!!!! not appropriate on panel change!!! Global setup/init */
+	lcd->intenable = 0;
+	lcd->intstatus = ~0;
+	lcd->backcolor = win->mode_backcolor;
+
+	/* Setup Color Key - FIX!!! */
+	lcd->colorkey = win->mode_colorkey;
+	lcd->colorkeymsk = win->mode_colorkeymsk;
+
+	/* Setup HWCursor - FIX!!! Need to support this eventually */
+	lcd->hwc.cursorctrl = 0;
+	lcd->hwc.cursorpos = 0;
+	lcd->hwc.cursorcolor0 = 0;
+	lcd->hwc.cursorcolor1 = 0;
+	lcd->hwc.cursorcolor2 = 0;
+	lcd->hwc.cursorcolor3 = 0;
+
+
+#if 0
+#define D(X) printk("%25s: %08X\n", #X, X)
+	D(lcd->screen);
+	D(lcd->horztiming);
+	D(lcd->verttiming);
+	D(lcd->clkcontrol);
+	D(lcd->pwmdiv);
+	D(lcd->pwmhi);
+	D(lcd->outmask);
+	D(lcd->fifoctrl);
+	D(lcd->window[0].winctrl0);
+	D(lcd->window[0].winctrl1);
+	D(lcd->window[0].winctrl2);
+	D(lcd->window[0].winbuf0);
+	D(lcd->window[0].winbuf1);
+	D(lcd->window[0].winbufctrl);
+	D(lcd->window[1].winctrl0);
+	D(lcd->window[1].winctrl1);
+	D(lcd->window[1].winctrl2);
+	D(lcd->window[1].winbuf0);
+	D(lcd->window[1].winbuf1);
+	D(lcd->window[1].winbufctrl);
+	D(lcd->window[2].winctrl0);
+	D(lcd->window[2].winctrl1);
+	D(lcd->window[2].winctrl2);
+	D(lcd->window[2].winbuf0);
+	D(lcd->window[2].winbuf1);
+	D(lcd->window[2].winbufctrl);
+	D(lcd->window[3].winctrl0);
+	D(lcd->window[3].winctrl1);
+	D(lcd->window[3].winctrl2);
+	D(lcd->window[3].winbuf0);
+	D(lcd->window[3].winbuf1);
+	D(lcd->window[3].winbufctrl);
+	D(lcd->winenable);
+	D(lcd->intenable);
+	D(lcd->intstatus);
+	D(lcd->backcolor);
+	D(lcd->winenable);
+	D(lcd->colorkey);
+    D(lcd->colorkeymsk);
+	D(lcd->hwc.cursorctrl);
+	D(lcd->hwc.cursorpos);
+	D(lcd->hwc.cursorcolor0);
+	D(lcd->hwc.cursorcolor1);
+	D(lcd->hwc.cursorcolor2);
+	D(lcd->hwc.cursorcolor3);
+#endif
+}
+
+static void au1200_setmode(struct au1200fb_device *fbdev)
+{
+	int plane = fbdev->plane;
+	/* Window/plane setup */
+	lcd->window[plane].winctrl1 = ( 0
+		| LCD_WINCTRL1_PRI_N(plane)
+		| win->w[plane].mode_winctrl1 /* FRM,CCO,PO,PIPE */
+		) ;
+
+	au1200_setlocation(fbdev, plane, win->w[plane].xpos, win->w[plane].ypos);
+
+	lcd->window[plane].winctrl2 = ( 0
+		| LCD_WINCTRL2_CKMODE_00
+		| LCD_WINCTRL2_DBM
+		| LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length)
+		| LCD_WINCTRL2_SCX_1
+		| LCD_WINCTRL2_SCY_1
+		) ;
+	lcd->winenable |= win->w[plane].mode_winenable;
+	au_sync();
+}
+
+
+/* Inline helpers */
+
+/*#define panel_is_dual(panel)  ((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
+/*#define panel_is_active(panel)((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
+
+#define panel_is_color(panel) ((panel->mode_screen & LCD_SCREEN_PT) <= LCD_SCREEN_PT_CDSTN)
+
+/* Bitfields format supported by the controller. */
+static struct fb_bitfield rgb_bitfields[][4] = {
+  	/*     Red, 	   Green, 	 Blue, 	     Transp   */
+	[LCD_WINCTRL1_FRM_16BPP655 >> 25] =
+		{ { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPP565 >> 25] =
+		{ { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPP556 >> 25] =
+		{ { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPI1555 >> 25] =
+		{ { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPI5551 >> 25] =
+		{ { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPA1555 >> 25] =
+		{ { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPA5551 >> 25] =
+		{ { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } },
+
+	[LCD_WINCTRL1_FRM_24BPP >> 25] =
+		{ { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_32BPP >> 25] =
+		{ { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 0, 0 } },
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Helpers */
+
+static void au1200fb_update_fbinfo(struct fb_info *fbi)
+{
+	/* FIX!!!! This also needs to take the window pixel format into account!!! */
+
+	/* Update var-dependent FB info */
+	if (panel_is_color(panel)) {
+		if (fbi->var.bits_per_pixel <= 8) {
+			/* palettized */
+			fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+			fbi->fix.line_length = fbi->var.xres_virtual /
+				(8/fbi->var.bits_per_pixel);
+		} else {
+			/* non-palettized */
+			fbi->fix.visual = FB_VISUAL_TRUECOLOR;
+			fbi->fix.line_length = fbi->var.xres_virtual * (fbi->var.bits_per_pixel / 8);
+		}
+	} else {
+		/* mono FIX!!! mono 8 and 4 bits */
+		fbi->fix.visual = FB_VISUAL_MONO10;
+		fbi->fix.line_length = fbi->var.xres_virtual / 8;
+	}
+
+	fbi->screen_size = fbi->fix.line_length * fbi->var.yres_virtual;
+	print_dbg("line length: %d\n", fbi->fix.line_length);
+	print_dbg("bits_per_pixel: %d\n", fbi->var.bits_per_pixel);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* AU1200 framebuffer driver */
+
+/* fb_check_var
+ * Validate var settings with hardware restrictions and modify it if necessary
+ */
+static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
+	struct fb_info *fbi)
+{
+	struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
+	u32 pixclock;
+	int screen_size, plane;
+
+	plane = fbdev->plane;
+
+	/* Make sure that the mode respect all LCD controller and
+	 * panel restrictions. */
+	var->xres = win->w[plane].xres;
+	var->yres = win->w[plane].yres;
+
+	/* No need for virtual resolution support */
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;
+
+	var->bits_per_pixel = winbpp(win->w[plane].mode_winctrl1);
+
+	screen_size = var->xres_virtual * var->yres_virtual;
+	if (var->bits_per_pixel > 8) screen_size *= (var->bits_per_pixel / 8);
+	else screen_size /= (8/var->bits_per_pixel);
+
+	if (fbdev->fb_len < screen_size)
+		return -EINVAL; /* Virtual screen is to big, abort */
+
+	/* FIX!!!! what are the implicaitons of ignoring this for windows ??? */
+	/* The max LCD clock is fixed to 48MHz (value of AUX_CLK). The pixel
+	 * clock can only be obtain by dividing this value by an even integer.
+	 * Fallback to a slower pixel clock if necessary. */
+	pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin);
+	pixclock = min(pixclock, min(fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2));
+
+	if (AU1200_LCD_MAX_CLK % pixclock) {
+		int diff = AU1200_LCD_MAX_CLK % pixclock;
+		pixclock -= diff;
+	}
+
+	var->pixclock = KHZ2PICOS(pixclock/1000);
+#if 0
+	if (!panel_is_active(panel)) {
+		int pcd = AU1200_LCD_MAX_CLK / (pixclock * 2) - 1;
+
+		if (!panel_is_color(panel)
+			&& (panel->control_base & LCD_CONTROL_MPI) && (pcd < 3)) {
+			/* STN 8bit mono panel support is up to 6MHz pixclock */
+			var->pixclock = KHZ2PICOS(6000);
+		} else if (!pcd) {
+			/* Other STN panel support is up to 12MHz  */
+			var->pixclock = KHZ2PICOS(12000);
+		}
+	}
+#endif
+	/* Set bitfield accordingly */
+	switch (var->bits_per_pixel) {
+		case 16:
+		{
+			/* 16bpp True color.
+			 * These must be set to MATCH WINCTRL[FORM] */
+			int idx;
+			idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
+			var->red    = rgb_bitfields[idx][0];
+			var->green  = rgb_bitfields[idx][1];
+			var->blue   = rgb_bitfields[idx][2];
+			var->transp = rgb_bitfields[idx][3];
+			break;
+		}
+
+		case 32:
+		{
+			/* 32bpp True color.
+			 * These must be set to MATCH WINCTRL[FORM] */
+			int idx;
+			idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
+			var->red    = rgb_bitfields[idx][0];
+			var->green  = rgb_bitfields[idx][1];
+			var->blue   = rgb_bitfields[idx][2];
+			var->transp = rgb_bitfields[idx][3];
+			break;
+		}
+		default:
+			print_dbg("Unsupported depth %dbpp", var->bits_per_pixel);
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* fb_set_par
+ * Set hardware with var settings. This will enable the controller with a
+ * specific mode, normally validated with the fb_check_var method
+ */
+static int au1200fb_fb_set_par(struct fb_info *fbi)
+{
+	struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
+
+	au1200fb_update_fbinfo(fbi);
+	au1200_setmode(fbdev);
+
+	return 0;
+}
+
+/* fb_setcolreg
+ * Set color in LCD palette.
+ */
+static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+	unsigned blue, unsigned transp, struct fb_info *fbi)
+{
+	volatile u32 *palette = lcd->palette;
+	u32 value;
+
+	if (regno > (AU1200_LCD_NBR_PALETTE_ENTRIES - 1))
+		return -EINVAL;
+
+	if (fbi->var.grayscale) {
+		/* Convert color to grayscale */
+		red = green = blue =
+			(19595 * red + 38470 * green + 7471 * blue) >> 16;
+	}
+
+	if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) {
+		/* Place color in the pseudopalette */
+		if (regno > 16)
+			return -EINVAL;
+
+		palette = (u32*) fbi->pseudo_palette;
+
+		red   >>= (16 - fbi->var.red.length);
+		green >>= (16 - fbi->var.green.length);
+		blue  >>= (16 - fbi->var.blue.length);
+
+		value = (red   << fbi->var.red.offset) 	|
+			(green << fbi->var.green.offset)|
+			(blue  << fbi->var.blue.offset);
+		value &= 0xFFFF;
+
+	} else if (1 /*FIX!!! panel_is_active(fbdev->panel)*/) {
+		/* COLOR TFT PALLETTIZED (use RGB 565) */
+		value = (red & 0xF800)|((green >> 5) &
+				0x07E0)|((blue >> 11) & 0x001F);
+		value &= 0xFFFF;
+
+	} else if (0 /*panel_is_color(fbdev->panel)*/) {
+		/* COLOR STN MODE */
+		value = 0x1234;
+		value &= 0xFFF;
+	} else {
+		/* MONOCHROME MODE */
+		value = (green >> 12) & 0x000F;
+		value &= 0xF;
+	}
+
+	palette[regno] = value;
+
+	return 0;
+}
+
+/* fb_blank
+ * Blank the screen. Depending on the mode, the screen will be
+ * activated with the backlight color, or desactivated
+ */
+static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
+{
+	/* Short-circuit screen blanking */
+	if (noblanking)
+		return 0;
+
+	switch (blank_mode) {
+
+	case FB_BLANK_UNBLANK:
+	case FB_BLANK_NORMAL:
+		/* printk("turn on panel\n"); */
+		au1200_setpanel(panel);
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_POWERDOWN:
+		/* printk("turn off panel\n"); */
+		au1200_setpanel(NULL);
+		break;
+	default:
+		break;
+
+	}
+
+	/* FB_BLANK_NORMAL is a soft blank */
+	return (blank_mode == FB_BLANK_NORMAL) ? -EINVAL : 0;
+}
+
+/* fb_mmap
+ * Map video memory in user space. We don't use the generic fb_mmap
+ * method mainly to allow the use of the TLB streaming flag (CCA=6)
+ */
+static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+
+{
+	unsigned int len;
+	unsigned long start=0, off;
+	struct au1200fb_device *fbdev = (struct au1200fb_device *) info;
+
+#ifdef CONFIG_PM
+	au1xxx_pm_access(LCD_pm_dev);
+#endif
+
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
+		return -EINVAL;
+	}
+
+	start = fbdev->fb_phys & PAGE_MASK;
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len);
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	if ((vma->vm_end - vma->vm_start + off) > len) {
+		return -EINVAL;
+	}
+
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */
+
+	vma->vm_flags |= VM_IO;
+
+	return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+				  vma->vm_end - vma->vm_start,
+				  vma->vm_page_prot);
+
+	return 0;
+}
+
+static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
+{
+
+	unsigned int hi1, divider;
+
+	/* SCREEN_SIZE: user cannot reset size, must switch panel choice */
+
+	if (pdata->flags & SCREEN_BACKCOLOR)
+		lcd->backcolor = pdata->backcolor;
+
+	if (pdata->flags & SCREEN_BRIGHTNESS) {
+
+		// limit brightness pwm duty to >= 30/1600
+		if (pdata->brightness < 30) {
+			pdata->brightness = 30;
+		}
+		divider = (lcd->pwmdiv & 0x3FFFF) + 1;
+		hi1 = (lcd->pwmhi >> 16) + 1;
+		hi1 = (((pdata->brightness & 0xFF)+1) * divider >> 8);
+		lcd->pwmhi &= 0xFFFF;
+		lcd->pwmhi |= (hi1 << 16);
+	}
+
+	if (pdata->flags & SCREEN_COLORKEY)
+		lcd->colorkey = pdata->colorkey;
+
+	if (pdata->flags & SCREEN_MASK)
+		lcd->colorkeymsk = pdata->mask;
+	au_sync();
+}
+
+static void get_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
+{
+	unsigned int hi1, divider;
+
+	pdata->xsize = ((lcd->screen & LCD_SCREEN_SX) >> 19) + 1;
+	pdata->ysize = ((lcd->screen & LCD_SCREEN_SY) >> 8) + 1;
+
+	pdata->backcolor = lcd->backcolor;
+	pdata->colorkey = lcd->colorkey;
+	pdata->mask = lcd->colorkeymsk;
+
+	// brightness
+	hi1 = (lcd->pwmhi >> 16) + 1;
+	divider = (lcd->pwmdiv & 0x3FFFF) + 1;
+	pdata->brightness = ((hi1 << 8) / divider) - 1;
+	au_sync();
+}
+
+static void set_window(unsigned int plane,
+	struct au1200_lcd_window_regs_t *pdata)
+{
+	unsigned int val, bpp;
+
+	/* Window control register 0 */
+	if (pdata->flags & WIN_POSITION) {
+		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_OX |
+				LCD_WINCTRL0_OY);
+		val |= ((pdata->xpos << 21) & LCD_WINCTRL0_OX);
+		val |= ((pdata->ypos << 10) & LCD_WINCTRL0_OY);
+		lcd->window[plane].winctrl0 = val;
+	}
+	if (pdata->flags & WIN_ALPHA_COLOR) {
+		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_A);
+		val |= ((pdata->alpha_color << 2) & LCD_WINCTRL0_A);
+		lcd->window[plane].winctrl0 = val;
+	}
+	if (pdata->flags & WIN_ALPHA_MODE) {
+		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_AEN);
+		val |= ((pdata->alpha_mode << 1) & LCD_WINCTRL0_AEN);
+		lcd->window[plane].winctrl0 = val;
+	}
+
+	/* Window control register 1 */
+	if (pdata->flags & WIN_PRIORITY) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PRI);
+		val |= ((pdata->priority << 30) & LCD_WINCTRL1_PRI);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_CHANNEL) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PIPE);
+		val |= ((pdata->channel << 29) & LCD_WINCTRL1_PIPE);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_BUFFER_FORMAT) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_FRM);
+		val |= ((pdata->buffer_format << 25) & LCD_WINCTRL1_FRM);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_COLOR_ORDER) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_CCO);
+		val |= ((pdata->color_order << 24) & LCD_WINCTRL1_CCO);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_PIXEL_ORDER) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PO);
+		val |= ((pdata->pixel_order << 22) & LCD_WINCTRL1_PO);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_SIZE) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_SZX |
+				LCD_WINCTRL1_SZY);
+		val |= (((pdata->xsize << 11) - 1) & LCD_WINCTRL1_SZX);
+		val |= (((pdata->ysize) - 1) & LCD_WINCTRL1_SZY);
+		lcd->window[plane].winctrl1 = val;
+		/* program buffer line width */
+		bpp = winbpp(val) / 8;
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_BX);
+		val |= (((pdata->xsize * bpp) << 8) & LCD_WINCTRL2_BX);
+		lcd->window[plane].winctrl2 = val;
+	}
+
+	/* Window control register 2 */
+	if (pdata->flags & WIN_COLORKEY_MODE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_CKMODE);
+		val |= ((pdata->colorkey_mode << 24) & LCD_WINCTRL2_CKMODE);
+		lcd->window[plane].winctrl2 = val;
+	}
+	if (pdata->flags & WIN_DOUBLE_BUFFER_MODE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_DBM);
+		val |= ((pdata->double_buffer_mode << 23) & LCD_WINCTRL2_DBM);
+		lcd->window[plane].winctrl2 = val;
+	}
+	if (pdata->flags & WIN_RAM_ARRAY_MODE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_RAM);
+		val |= ((pdata->ram_array_mode << 21) & LCD_WINCTRL2_RAM);
+		lcd->window[plane].winctrl2 = val;
+	}
+
+	/* Buffer line width programmed with WIN_SIZE */
+
+	if (pdata->flags & WIN_BUFFER_SCALE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_SCX |
+				LCD_WINCTRL2_SCY);
+		val |= ((pdata->xsize << 11) & LCD_WINCTRL2_SCX);
+		val |= ((pdata->ysize) & LCD_WINCTRL2_SCY);
+		lcd->window[plane].winctrl2 = val;
+	}
+
+	if (pdata->flags & WIN_ENABLE) {
+		val = lcd->winenable;
+		val &= ~(1<<plane);
+		val |= (pdata->enable & 1) << plane;
+		lcd->winenable = val;
+	}
+	au_sync();
+}
+
+static void get_window(unsigned int plane,
+	struct au1200_lcd_window_regs_t *pdata)
+{
+	/* Window control register 0 */
+	pdata->xpos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OX) >> 21;
+	pdata->ypos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OY) >> 10;
+	pdata->alpha_color = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_A) >> 2;
+	pdata->alpha_mode = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_AEN) >> 1;
+
+	/* Window control register 1 */
+	pdata->priority = (lcd->window[plane].winctrl1& LCD_WINCTRL1_PRI) >> 30;
+	pdata->channel = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PIPE) >> 29;
+	pdata->buffer_format = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_FRM) >> 25;
+	pdata->color_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_CCO) >> 24;
+	pdata->pixel_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PO) >> 22;
+	pdata->xsize = ((lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11) + 1;
+	pdata->ysize = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZY) + 1;
+
+	/* Window control register 2 */
+	pdata->colorkey_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_CKMODE) >> 24;
+	pdata->double_buffer_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_DBM) >> 23;
+	pdata->ram_array_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_RAM) >> 21;
+
+	pdata->enable = (lcd->winenable >> plane) & 1;
+	au_sync();
+}
+
+static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
+                          unsigned long arg)
+{
+	int plane;
+	int val;
+
+#ifdef CONFIG_PM
+	au1xxx_pm_access(LCD_pm_dev);
+#endif
+
+	plane = fbinfo2index(info);
+	print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane);
+
+	if (cmd == AU1200_LCD_FB_IOCTL) {
+		struct au1200_lcd_iodata_t iodata;
+
+		if (copy_from_user(&iodata, (void __user *) arg, sizeof(iodata)))
+			return -EFAULT;
+
+		print_dbg("FB IOCTL called\n");
+
+		switch (iodata.subcmd) {
+		case AU1200_LCD_SET_SCREEN:
+			print_dbg("AU1200_LCD_SET_SCREEN\n");
+			set_global(cmd, &iodata.global);
+			break;
+
+		case AU1200_LCD_GET_SCREEN:
+			print_dbg("AU1200_LCD_GET_SCREEN\n");
+			get_global(cmd, &iodata.global);
+			break;
+
+		case AU1200_LCD_SET_WINDOW:
+			print_dbg("AU1200_LCD_SET_WINDOW\n");
+			set_window(plane, &iodata.window);
+			break;
+
+		case AU1200_LCD_GET_WINDOW:
+			print_dbg("AU1200_LCD_GET_WINDOW\n");
+			get_window(plane, &iodata.window);
+			break;
+
+		case AU1200_LCD_SET_PANEL:
+			print_dbg("AU1200_LCD_SET_PANEL\n");
+			if ((iodata.global.panel_choice >= 0) &&
+					(iodata.global.panel_choice <
+					 NUM_PANELS))
+			{
+				struct panel_settings *newpanel;
+				panel_index = iodata.global.panel_choice;
+				newpanel = &known_lcd_panels[panel_index];
+				au1200_setpanel(newpanel);
+			}
+			break;
+
+		case AU1200_LCD_GET_PANEL:
+			print_dbg("AU1200_LCD_GET_PANEL\n");
+			iodata.global.panel_choice = panel_index;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+
+		val = copy_to_user((void __user *) arg, &iodata, sizeof(iodata));
+		if (val) {
+			print_dbg("error: could not copy %d bytes\n", val);
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+
+static struct fb_ops au1200fb_fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= au1200fb_fb_check_var,
+	.fb_set_par	= au1200fb_fb_set_par,
+	.fb_setcolreg	= au1200fb_fb_setcolreg,
+	.fb_blank	= au1200fb_fb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_sync	= NULL,
+	.fb_ioctl	= au1200fb_ioctl,
+	.fb_mmap	= au1200fb_fb_mmap,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id, struct pt_regs *regs)
+{
+	/* Nothing to do for now, just clear any pending interrupt */
+	lcd->intstatus = lcd->intstatus;
+	au_sync();
+
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* AU1200 LCD device probe helpers */
+
+static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
+{
+	struct fb_info *fbi = &fbdev->fb_info;
+	int bpp;
+
+	memset(fbi, 0, sizeof(struct fb_info));
+	fbi->fbops = &au1200fb_fb_ops;
+
+	bpp = winbpp(win->w[fbdev->plane].mode_winctrl1);
+
+	/* Copy monitor specs from panel data */
+	/* fixme: we're setting up LCD controller windows, so these dont give a
+	damn as to what the monitor specs are (the panel itself does, but that
+	isnt done here...so maybe need a generic catchall monitor setting??? */
+	memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs));
+
+	/* We first try the user mode passed in argument. If that failed,
+	 * or if no one has been specified, we default to the first mode of the
+	 * panel list. Note that after this call, var data will be set */
+	if (!fb_find_mode(&fbi->var,
+			  fbi,
+			  NULL, /* drv_info.opt_mode, */
+			  fbi->monspecs.modedb,
+			  fbi->monspecs.modedb_len,
+			  fbi->monspecs.modedb,
+			  bpp)) {
+
+		print_err("Cannot find valid mode for panel %s", panel->name);
+		return -EFAULT;
+	}
+
+	fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+	if (!fbi->pseudo_palette) {
+		return -ENOMEM;
+	}
+	memset(fbi->pseudo_palette, 0, sizeof(u32) * 16);
+
+	if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
+		print_err("Fail to allocate colormap (%d entries)",
+			   AU1200_LCD_NBR_PALETTE_ENTRIES);
+		kfree(fbi->pseudo_palette);
+		return -EFAULT;
+	}
+
+	strncpy(fbi->fix.id, "AU1200", sizeof(fbi->fix.id));
+	fbi->fix.smem_start = fbdev->fb_phys;
+	fbi->fix.smem_len = fbdev->fb_len;
+	fbi->fix.type = FB_TYPE_PACKED_PIXELS;
+	fbi->fix.xpanstep = 0;
+	fbi->fix.ypanstep = 0;
+	fbi->fix.mmio_start = 0;
+	fbi->fix.mmio_len = 0;
+	fbi->fix.accel = FB_ACCEL_NONE;
+
+	fbi->screen_base = (char __iomem *) fbdev->fb_mem;
+
+	au1200fb_update_fbinfo(fbi);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* AU1200 LCD controller device driver */
+
+static int au1200fb_drv_probe(struct device *dev)
+{
+	struct au1200fb_device *fbdev;
+	unsigned long page;
+	int bpp, plane, ret;
+
+	if (!dev)
+		return -EINVAL;
+
+	for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) {
+		bpp = winbpp(win->w[plane].mode_winctrl1);
+		if (win->w[plane].xres == 0)
+			win->w[plane].xres = panel->Xres;
+		if (win->w[plane].yres == 0)
+			win->w[plane].yres = panel->Yres;
+
+		fbdev = &_au1200fb_devices[plane];
+		memset(fbdev, 0, sizeof(struct au1200fb_device));
+		fbdev->plane = plane;
+
+		/* Allocate the framebuffer to the maximum screen size */
+		fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8;
+
+		fbdev->fb_mem = dma_alloc_noncoherent(dev,
+				PAGE_ALIGN(fbdev->fb_len),
+				&fbdev->fb_phys, GFP_KERNEL);
+		if (!fbdev->fb_mem) {
+			print_err("fail to allocate frambuffer (size: %dK))",
+				  fbdev->fb_len / 1024);
+			return -ENOMEM;
+		}
+
+		/*
+		 * Set page reserved so that mmap will work. This is necessary
+		 * since we'll be remapping normal memory.
+		 */
+		for (page = (unsigned long)fbdev->fb_phys;
+		     page < PAGE_ALIGN((unsigned long)fbdev->fb_phys +
+			     fbdev->fb_len);
+		     page += PAGE_SIZE) {
+			SetPageReserved(pfn_to_page(page >> PAGE_SHIFT)); /* LCD DMA is NOT coherent on Au1200 */
+		}
+		print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
+		print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
+
+		/* Init FB data */
+		if ((ret = au1200fb_init_fbinfo(fbdev)) < 0)
+			goto failed;
+
+		/* Register new framebuffer */
+		if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) {
+			print_err("cannot register new framebuffer");
+			goto failed;
+		}
+
+		au1200fb_fb_set_par(&fbdev->fb_info);
+
+#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
+		if (plane == 0)
+			if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) {
+				/* Start display and show logo on boot */
+				fb_set_cmap(&fbdev->fb_info.cmap,
+						&fbdev->fb_info);
+
+				fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR);
+			}
+#endif
+	}
+
+	/* Now hook interrupt too */
+	if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq,
+		 	  SA_INTERRUPT | SA_SHIRQ, "lcd", (void *)dev)) < 0) {
+		print_err("fail to request interrupt line %d (err: %d)",
+			  AU1200_LCD_INT, ret);
+		goto failed;
+	}
+
+	return 0;
+
+failed:
+	/* NOTE: This only does the current plane/window that failed; others are still active */
+	if (fbdev->fb_mem)
+		dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len),
+				fbdev->fb_mem, fbdev->fb_phys);
+	if (fbdev->fb_info.cmap.len != 0)
+		fb_dealloc_cmap(&fbdev->fb_info.cmap);
+	if (fbdev->fb_info.pseudo_palette)
+		kfree(fbdev->fb_info.pseudo_palette);
+	if (plane == 0)
+		free_irq(AU1200_LCD_INT, (void*)dev);
+	return ret;
+}
+
+static int au1200fb_drv_remove(struct device *dev)
+{
+	struct au1200fb_device *fbdev;
+	int plane;
+
+	if (!dev)
+		return -ENODEV;
+
+	/* Turn off the panel */
+	au1200_setpanel(NULL);
+
+	for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane)
+	{
+		fbdev = &_au1200fb_devices[plane];
+
+		/* Clean up all probe data */
+		unregister_framebuffer(&fbdev->fb_info);
+		if (fbdev->fb_mem)
+			dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len),
+					fbdev->fb_mem, fbdev->fb_phys);
+		if (fbdev->fb_info.cmap.len != 0)
+			fb_dealloc_cmap(&fbdev->fb_info.cmap);
+		if (fbdev->fb_info.pseudo_palette)
+			kfree(fbdev->fb_info.pseudo_palette);
+	}
+
+	free_irq(AU1200_LCD_INT, (void *)dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int au1200fb_drv_suspend(struct device *dev, u32 state, u32 level)
+{
+	/* TODO */
+	return 0;
+}
+
+static int au1200fb_drv_resume(struct device *dev, u32 level)
+{
+	/* TODO */
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct device_driver au1200fb_driver = {
+	.name		= "au1200-lcd",
+	.bus		= &platform_bus_type,
+	.probe		= au1200fb_drv_probe,
+	.remove		= au1200fb_drv_remove,
+#ifdef CONFIG_PM
+	.suspend	= au1200fb_drv_suspend,
+	.resume		= au1200fb_drv_resume,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Kernel driver */
+
+static void au1200fb_setup(void)
+{
+	char* options = NULL;
+	char* this_opt;
+	int num_panels = ARRAY_SIZE(known_lcd_panels);
+	int panel_idx = -1;
+
+	fb_get_options(DRIVER_NAME, &options);
+
+	if (options) {
+		while ((this_opt = strsep(&options,",")) != NULL) {
+			/* Panel option - can be panel name,
+			 * "bs" for board-switch, or number/index */
+			if (!strncmp(this_opt, "panel:", 6)) {
+				int i;
+				long int li;
+				char *endptr;
+				this_opt += 6;
+				/* First check for index, which allows
+				 * to short circuit this mess */
+				li = simple_strtol(this_opt, &endptr, 0);
+				if (*endptr == '\0') {
+					panel_idx = (int)li;
+				}
+				else if (strcmp(this_opt, "bs") == 0) {
+					extern int board_au1200fb_panel(void);
+					panel_idx = board_au1200fb_panel();
+				}
+
+				else
+				for (i = 0; i < num_panels; i++) {
+					if (!strcmp(this_opt, known_lcd_panels[i].name)) {
+						panel_idx = i;
+						break;
+					}
+				}
+
+				if ((panel_idx < 0) || (panel_idx >= num_panels)) {
+						print_warn("Panel %s not supported!", this_opt);
+				}
+				else
+					panel_index = panel_idx;
+			}
+
+			else if (strncmp(this_opt, "nohwcursor", 10) == 0) {
+				nohwcursor = 1;
+			}
+
+			/* Unsupported option */
+			else {
+				print_warn("Unsupported option \"%s\"", this_opt);
+			}
+		}
+	}
+}
+
+#ifdef CONFIG_PM
+static int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
+		au1xxx_request_t request, void *data) {
+	int retval = -1;
+	unsigned int d = 0;
+	unsigned int brightness = 0;
+
+	if (request == AU1XXX_PM_SLEEP) {
+		board_au1200fb_panel_shutdown();
+	}
+	else if (request == AU1XXX_PM_WAKEUP) {
+		if(dev->prev_state == SLEEP_STATE)
+		{
+			int plane;
+			au1200_setpanel(panel);
+			for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) 	{
+				struct au1200fb_device *fbdev;
+				fbdev = &_au1200fb_devices[plane];
+				au1200fb_fb_set_par(&fbdev->fb_info);
+			}
+		}
+
+		d = *((unsigned int*)data);
+		if(d <=10) brightness = 26;
+		else if(d<=20) brightness = 51;
+		else if(d<=30) brightness = 77;
+		else if(d<=40) brightness = 102;
+		else if(d<=50) brightness = 128;
+		else if(d<=60) brightness = 153;
+		else if(d<=70) brightness = 179;
+		else if(d<=80) brightness = 204;
+		else if(d<=90) brightness = 230;
+		else brightness = 255;
+		set_brightness(brightness);
+	} else if (request == AU1XXX_PM_GETSTATUS) {
+		return dev->cur_state;
+	} else if (request == AU1XXX_PM_ACCESS) {
+		if (dev->cur_state != SLEEP_STATE)
+			return retval;
+		else {
+			au1200_setpanel(panel);
+		}
+	} else if (request == AU1XXX_PM_IDLE) {
+	} else if (request == AU1XXX_PM_CLEANUP) {
+	}
+
+	return retval;
+}
+#endif
+
+static int __init au1200fb_init(void)
+{
+	print_info("" DRIVER_DESC "");
+
+	/* Setup driver with options */
+	au1200fb_setup();
+
+	/* Point to the panel selected */
+	panel = &known_lcd_panels[panel_index];
+	win = &windows[window_index];
+
+	printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
+	printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
+
+	/* Kickstart the panel, the framebuffers/windows come soon enough */
+	au1200_setpanel(panel);
+
+	#ifdef CONFIG_PM
+	LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL);
+	if ( LCD_pm_dev == NULL)
+		printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n");
+	else
+		printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n");
+	#endif
+
+	return driver_register(&au1200fb_driver);
+}
+
+static void __exit au1200fb_cleanup(void)
+{
+	driver_unregister(&au1200fb_driver);
+}
+
+module_init(au1200fb_init);
+module_exit(au1200fb_cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Au1200 LCD Driver.
+ *
+ * Copyright 2004-2005 AMD
+ * Author: AMD
+ *
+ * Based on:
+ * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
+ *  Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ *  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  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include "au1200fb.h"
+
+#ifdef CONFIG_PM
+#include <asm/mach-au1x00/au1xxx_pm.h>
+#endif
+
+#ifndef CONFIG_FB_AU1200_DEVS
+#define CONFIG_FB_AU1200_DEVS 4
+#endif
+
+#define DRIVER_NAME "au1200fb"
+#define DRIVER_DESC "LCD controller driver for AU1200 processors"
+
+#define DEBUG 1
+
+#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
+#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
+#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
+
+#if DEBUG
+#define print_dbg(f, arg...) printk(KERN_DEBUG __FILE__ ": " f "\n", ## arg)
+#else
+#define print_dbg(f, arg...) do {} while (0)
+#endif
+
+
+#define AU1200_LCD_FB_IOCTL 0x46FF
+
+#define AU1200_LCD_SET_SCREEN 1
+#define AU1200_LCD_GET_SCREEN 2
+#define AU1200_LCD_SET_WINDOW 3
+#define AU1200_LCD_GET_WINDOW 4
+#define AU1200_LCD_SET_PANEL  5
+#define AU1200_LCD_GET_PANEL  6
+
+#define SCREEN_SIZE		    (1<< 1)
+#define SCREEN_BACKCOLOR    (1<< 2)
+#define SCREEN_BRIGHTNESS   (1<< 3)
+#define SCREEN_COLORKEY     (1<< 4)
+#define SCREEN_MASK         (1<< 5)
+
+struct au1200_lcd_global_regs_t {
+	unsigned int flags;
+	unsigned int xsize;
+	unsigned int ysize;
+	unsigned int backcolor;
+	unsigned int brightness;
+	unsigned int colorkey;
+	unsigned int mask;
+	unsigned int panel_choice;
+	char panel_desc[80];
+
+};
+
+#define WIN_POSITION            (1<< 0)
+#define WIN_ALPHA_COLOR         (1<< 1)
+#define WIN_ALPHA_MODE          (1<< 2)
+#define WIN_PRIORITY            (1<< 3)
+#define WIN_CHANNEL             (1<< 4)
+#define WIN_BUFFER_FORMAT       (1<< 5)
+#define WIN_COLOR_ORDER         (1<< 6)
+#define WIN_PIXEL_ORDER         (1<< 7)
+#define WIN_SIZE                (1<< 8)
+#define WIN_COLORKEY_MODE       (1<< 9)
+#define WIN_DOUBLE_BUFFER_MODE  (1<< 10)
+#define WIN_RAM_ARRAY_MODE      (1<< 11)
+#define WIN_BUFFER_SCALE        (1<< 12)
+#define WIN_ENABLE	            (1<< 13)
+
+struct au1200_lcd_window_regs_t {
+	unsigned int flags;
+	unsigned int xpos;
+	unsigned int ypos;
+	unsigned int alpha_color;
+	unsigned int alpha_mode;
+	unsigned int priority;
+	unsigned int channel;
+	unsigned int buffer_format;
+	unsigned int color_order;
+	unsigned int pixel_order;
+	unsigned int xsize;
+	unsigned int ysize;
+	unsigned int colorkey_mode;
+	unsigned int double_buffer_mode;
+	unsigned int ram_array_mode;
+	unsigned int xscale;
+	unsigned int yscale;
+	unsigned int enable;
+};
+
+
+struct au1200_lcd_iodata_t {
+	unsigned int subcmd;
+	struct au1200_lcd_global_regs_t global;
+	struct au1200_lcd_window_regs_t window;
+};
+
+#if defined(__BIG_ENDIAN)
+#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11
+#else
+#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00
+#endif
+#define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565
+
+/* Private, per-framebuffer management information (independent of the panel itself) */
+struct au1200fb_device {
+	struct fb_info fb_info;			/* FB driver info record */
+
+	int					plane;
+	unsigned char* 		fb_mem;		/* FrameBuffer memory map */
+	unsigned int		fb_len;
+	dma_addr_t    		fb_phys;
+};
+
+static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS];
+/********************************************************************/
+
+/* LCD controller restrictions */
+#define AU1200_LCD_MAX_XRES	1280
+#define AU1200_LCD_MAX_YRES	1024
+#define AU1200_LCD_MAX_BPP	32
+#define AU1200_LCD_MAX_CLK	96000000 /* fixme: this needs to go away ? */
+#define AU1200_LCD_NBR_PALETTE_ENTRIES 256
+
+/* Default number of visible screen buffer to allocate */
+#define AU1200FB_NBR_VIDEO_BUFFERS 1
+
+/********************************************************************/
+
+static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR;
+static int window_index = 2; /* default is zero */
+static int panel_index = 2; /* default is zero */
+static struct window_settings *win;
+static struct panel_settings *panel;
+static int noblanking = 1;
+static int nohwcursor = 0;
+
+struct window_settings {
+	unsigned char name[64];
+	uint32 mode_backcolor;
+	uint32 mode_colorkey;
+	uint32 mode_colorkeymsk;
+	struct {
+		int xres;
+		int yres;
+		int xpos;
+		int ypos;
+		uint32 mode_winctrl1; /* winctrl1[FRM,CCO,PO,PIPE] */
+		uint32 mode_winenable;
+	} w[4];
+};
+
+#if defined(__BIG_ENDIAN)
+#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00
+#else
+#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
+#endif
+
+extern int board_au1200fb_panel_init (void);
+extern int board_au1200fb_panel_shutdown (void);
+
+#ifdef CONFIG_PM
+int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
+		au1xxx_request_t request, void *data);
+au1xxx_power_dev_t *LCD_pm_dev;
+#endif
+
+/*
+ * Default window configurations
+ */
+static struct window_settings windows[] = {
+	{ /* Index 0 */
+		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
+		/* mode_backcolor	*/ 0x006600ff,
+		/* mode_colorkey,msk*/ 0, 0,
+		{
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ LCD_WINENABLE_WEN0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 100, 100, 100, 100,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ LCD_WINENABLE_WEN1,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ 0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0,
+			},
+		},
+	},
+
+	{ /* Index 1 */
+		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
+		/* mode_backcolor	*/ 0x006600ff,
+		/* mode_colorkey,msk*/ 0, 0,
+		{
+			{
+			/* xres, yres, xpos, ypos */ 320, 240, 5, 5,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_24BPP |
+				LCD_WINCTRL1_PO_00,
+			/* mode_winenable*/ LCD_WINENABLE_WEN0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565
+				| LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ 0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 100, 100, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 200, 25, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0,
+			},
+		},
+	},
+	{ /* Index 2 */
+		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
+		/* mode_backcolor	*/ 0x006600ff,
+		/* mode_colorkey,msk*/ 0, 0,
+		{
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ LCD_WINENABLE_WEN0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP,
+			/* mode_winenable*/ 0,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_32BPP |
+				LCD_WINCTRL1_PO_00|LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
+			},
+			{
+			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
+			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
+				LCD_WINCTRL1_PO_16BPP |
+				LCD_WINCTRL1_PIPE,
+			/* mode_winenable*/ 0,
+			},
+		},
+	},
+	/* Need VGA 640 @ 24bpp, @ 32bpp */
+	/* Need VGA 800 @ 24bpp, @ 32bpp */
+	/* Need VGA 1024 @ 24bpp, @ 32bpp */
+};
+
+/*
+ * Controller configurations for various panels.
+ */
+
+struct panel_settings
+{
+	const char name[25];		/* Full name <vendor>_<model> */
+
+	struct 	fb_monspecs monspecs; 	/* FB monitor specs */
+
+	/* panel timings */
+	uint32 mode_screen;
+	uint32 mode_horztiming;
+	uint32 mode_verttiming;
+	uint32 mode_clkcontrol;
+	uint32 mode_pwmdiv;
+	uint32 mode_pwmhi;
+	uint32 mode_outmask;
+	uint32 mode_fifoctrl;
+	uint32 mode_toyclksrc;
+	uint32 mode_backlight;
+	uint32 mode_auxpll;
+	int (*device_init)(void);
+	int (*device_shutdown)(void);
+#define Xres min_xres
+#define Yres min_yres
+	u32	min_xres;		/* Minimum horizontal resolution */
+	u32	max_xres;		/* Maximum horizontal resolution */
+	u32 	min_yres;		/* Minimum vertical resolution */
+	u32 	max_yres;		/* Maximum vertical resolution */
+};
+
+/********************************************************************/
+/* fixme: Maybe a modedb for the CRT ? otherwise panels should be as-is */
+
+/* List of panels known to work with the AU1200 LCD controller.
+ * To add a new panel, enter the same specifications as the
+ * Generic_TFT one, and MAKE SURE that it doesn't conflicts
+ * with the controller restrictions. Restrictions are:
+ *
+ * STN color panels: max_bpp <= 12
+ * STN mono panels: max_bpp <= 4
+ * TFT panels: max_bpp <= 16
+ * max_xres <= 800
+ * max_yres <= 600
+ */
+static struct panel_settings known_lcd_panels[] =
+{
+	[0] = { /* QVGA 320x240 H:33.3kHz V:110Hz */
+		.name = "QVGA_320x240",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(320) |
+			LCD_SCREEN_SY_N(240),
+		.mode_horztiming	= 0x00c4623b,
+		.mode_verttiming	= 0x00502814,
+		.mode_clkcontrol	= 0x00020002, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		320, 320,
+		240, 240,
+	},
+
+	[1] = { /* VGA 640x480 H:30.3kHz V:58Hz */
+		.name = "VGA_640x480",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x13f9df80,
+		.mode_horztiming	= 0x003c5859,
+		.mode_verttiming	= 0x00741201,
+		.mode_clkcontrol	= 0x00020001, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		640, 480,
+		640, 480,
+	},
+
+	[2] = { /* SVGA 800x600 H:46.1kHz V:69Hz */
+		.name = "SVGA_800x600",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x18fa5780,
+		.mode_horztiming	= 0x00dc7e77,
+		.mode_verttiming	= 0x00584805,
+		.mode_clkcontrol	= 0x00020000, /* /2=48Mhz */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		800, 800,
+		600, 600,
+	},
+
+	[3] = { /* XVGA 1024x768 H:56.2kHz V:70Hz */
+		.name = "XVGA_1024x768",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x1ffaff80,
+		.mode_horztiming	= 0x007d0e57,
+		.mode_verttiming	= 0x00740a01,
+		.mode_clkcontrol	= 0x000A0000, /* /1 */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 6, /* 72MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		1024, 1024,
+		768, 768,
+	},
+
+	[4] = { /* XVGA XVGA 1280x1024 H:68.5kHz V:65Hz */
+		.name = "XVGA_1280x1024",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x27fbff80,
+		.mode_horztiming	= 0x00cdb2c7,
+		.mode_verttiming	= 0x00600002,
+		.mode_clkcontrol	= 0x000A0000, /* /1 */
+		.mode_pwmdiv		= 0x00000000,
+		.mode_pwmhi		= 0x00000000,
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 10, /* 120MHz AUXPLL */
+		.device_init		= NULL,
+		.device_shutdown	= NULL,
+		1280, 1280,
+		1024, 1024,
+	},
+
+	[5] = { /* Samsung 1024x768 TFT */
+		.name = "Samsung_1024x768_TFT",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= 0x1ffaff80,
+		.mode_horztiming	= 0x018cc677,
+		.mode_verttiming	= 0x00241217,
+		.mode_clkcontrol	= 0x00000000, /* SCB 0x1 /4=24Mhz */
+		.mode_pwmdiv		= 0x8000063f, /* SCB 0x0 */
+		.mode_pwmhi		= 0x03400000, /* SCB 0x0 */
+		.mode_outmask	= 0x00FFFFFF,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		1024, 1024,
+		768, 768,
+	},
+
+	[6] = { /* Toshiba 640x480 TFT */
+		.name = "Toshiba_640x480_TFT",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(640) |
+			LCD_SCREEN_SY_N(480),
+		.mode_horztiming	= LCD_HORZTIMING_HPW_N(96) |
+			LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(51),
+		.mode_verttiming	= LCD_VERTTIMING_VPW_N(2) |
+			LCD_VERTTIMING_VND1_N(11) | LCD_VERTTIMING_VND2_N(32),
+		.mode_clkcontrol	= 0x00000000, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x8000063f,
+		.mode_pwmhi		= 0x03400000,
+		.mode_outmask	= 0x00fcfcfc,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		640, 480,
+		640, 480,
+	},
+
+	[7] = { /* Sharp 320x240 TFT */
+		.name = "Sharp_320x240_TFT",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 12500,
+			.hfmax = 20000,
+			.vfmin = 38,
+			.vfmax = 81,
+			.dclkmin = 4500000,
+			.dclkmax = 6800000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(320) |
+			LCD_SCREEN_SY_N(240),
+		.mode_horztiming	= LCD_HORZTIMING_HPW_N(60) |
+			LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(2),
+		.mode_verttiming	= LCD_VERTTIMING_VPW_N(2) |
+			LCD_VERTTIMING_VND1_N(2) | LCD_VERTTIMING_VND2_N(5),
+		.mode_clkcontrol	= LCD_CLKCONTROL_PCD_N(7), /*16=6Mhz*/
+		.mode_pwmdiv		= 0x8000063f,
+		.mode_pwmhi		= 0x03400000,
+		.mode_outmask	= 0x00fcfcfc,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		320, 320,
+		240, 240,
+	},
+
+	[8] = { /* Toppoly TD070WGCB2 7" 856x480 TFT */
+		.name = "Toppoly_TD070WGCB2",
+		.monspecs = {
+			.modedb = NULL,
+			.modedb_len = 0,
+			.hfmin = 30000,
+			.hfmax = 70000,
+			.vfmin = 60,
+			.vfmax = 60,
+			.dclkmin = 6000000,
+			.dclkmax = 28000000,
+			.input = FB_DISP_RGB,
+		},
+		.mode_screen		= LCD_SCREEN_SX_N(856) |
+			LCD_SCREEN_SY_N(480),
+		.mode_horztiming	= LCD_HORZTIMING_HND2_N(43) |
+			LCD_HORZTIMING_HND1_N(43) | LCD_HORZTIMING_HPW_N(114),
+		.mode_verttiming	= LCD_VERTTIMING_VND2_N(20) |
+			LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4),
+		.mode_clkcontrol	= 0x00020001, /* /4=24Mhz */
+		.mode_pwmdiv		= 0x8000063f,
+		.mode_pwmhi		= 0x03400000,
+		.mode_outmask	= 0x00fcfcfc,
+		.mode_fifoctrl	= 0x2f2f2f2f,
+		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
+		.mode_backlight	= 0x00000000,
+		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.device_init		= board_au1200fb_panel_init,
+		.device_shutdown	= board_au1200fb_panel_shutdown,
+		856, 856,
+		480, 480,
+	},
+};
+
+#define NUM_PANELS (ARRAY_SIZE(known_lcd_panels))
+
+/********************************************************************/
+
+#ifdef CONFIG_PM
+static int set_brightness(unsigned int brightness)
+{
+	unsigned int hi1, divider;
+
+	/* limit brightness pwm duty to >= 30/1600 */
+	if (brightness < 30) {
+		brightness = 30;
+	}
+	divider = (lcd->pwmdiv & 0x3FFFF) + 1;
+	hi1 = (lcd->pwmhi >> 16) + 1;
+	hi1 = (((brightness & 0xFF) + 1) * divider >> 8);
+	lcd->pwmhi &= 0xFFFF;
+	lcd->pwmhi |= (hi1 << 16);
+
+	return brightness;
+}
+#endif /* CONFIG_PM */
+
+static int winbpp (unsigned int winctrl1)
+{
+	int bits = 0;
+
+	/* how many bits are needed for each pixel format */
+	switch (winctrl1 & LCD_WINCTRL1_FRM) {
+	case LCD_WINCTRL1_FRM_1BPP:
+		bits = 1;
+		break;
+	case LCD_WINCTRL1_FRM_2BPP:
+		bits = 2;
+		break;
+	case LCD_WINCTRL1_FRM_4BPP:
+		bits = 4;
+		break;
+	case LCD_WINCTRL1_FRM_8BPP:
+		bits = 8;
+		break;
+	case LCD_WINCTRL1_FRM_12BPP:
+	case LCD_WINCTRL1_FRM_16BPP655:
+	case LCD_WINCTRL1_FRM_16BPP565:
+	case LCD_WINCTRL1_FRM_16BPP556:
+	case LCD_WINCTRL1_FRM_16BPPI1555:
+	case LCD_WINCTRL1_FRM_16BPPI5551:
+	case LCD_WINCTRL1_FRM_16BPPA1555:
+	case LCD_WINCTRL1_FRM_16BPPA5551:
+		bits = 16;
+		break;
+	case LCD_WINCTRL1_FRM_24BPP:
+	case LCD_WINCTRL1_FRM_32BPP:
+		bits = 32;
+		break;
+	}
+
+	return bits;
+}
+
+static int fbinfo2index (struct fb_info *fb_info)
+{
+	int i;
+
+	for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) {
+		if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info))
+			return i;
+	}
+	printk("au1200fb: ERROR: fbinfo2index failed!\n");
+	return -1;
+}
+
+static int au1200_setlocation (struct au1200fb_device *fbdev, int plane,
+	int xpos, int ypos)
+{
+	uint32 winctrl0, winctrl1, winenable, fb_offset = 0;
+	int xsz, ysz;
+
+	/* FIX!!! NOT CHECKING FOR COMPLETE OFFSCREEN YET */
+
+	winctrl0 = lcd->window[plane].winctrl0;
+	winctrl1 = lcd->window[plane].winctrl1;
+	winctrl0 &= (LCD_WINCTRL0_A | LCD_WINCTRL0_AEN);
+	winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY);
+
+	/* Check for off-screen adjustments */
+	xsz = win->w[plane].xres;
+	ysz = win->w[plane].yres;
+	if ((xpos + win->w[plane].xres) > panel->Xres) {
+		/* Off-screen to the right */
+		xsz = panel->Xres - xpos; /* off by 1 ??? */
+		/*printk("off screen right\n");*/
+	}
+
+	if ((ypos + win->w[plane].yres) > panel->Yres) {
+		/* Off-screen to the bottom */
+		ysz = panel->Yres - ypos; /* off by 1 ??? */
+		/*printk("off screen bottom\n");*/
+	}
+
+	if (xpos < 0) {
+		/* Off-screen to the left */
+		xsz = win->w[plane].xres + xpos;
+		fb_offset += (((0 - xpos) * winbpp(lcd->window[plane].winctrl1))/8);
+		xpos = 0;
+		/*printk("off screen left\n");*/
+	}
+
+	if (ypos < 0) {
+		/* Off-screen to the top */
+		ysz = win->w[plane].yres + ypos;
+		/* fixme: fb_offset += ((0-ypos)*fb_pars[plane].line_length); */
+		ypos = 0;
+		/*printk("off screen top\n");*/
+	}
+
+	/* record settings */
+	win->w[plane].xpos = xpos;
+	win->w[plane].ypos = ypos;
+
+	xsz -= 1;
+	ysz -= 1;
+	winctrl0 |= (xpos << 21);
+	winctrl0 |= (ypos << 10);
+	winctrl1 |= (xsz << 11);
+	winctrl1 |= (ysz << 0);
+
+	/* Disable the window while making changes, then restore WINEN */
+	winenable = lcd->winenable & (1 << plane);
+	au_sync();
+	lcd->winenable &= ~(1 << plane);
+	lcd->window[plane].winctrl0 = winctrl0;
+	lcd->window[plane].winctrl1 = winctrl1;
+	lcd->window[plane].winbuf0 =
+	lcd->window[plane].winbuf1 = fbdev->fb_phys;
+	lcd->window[plane].winbufctrl = 0; /* select winbuf0 */
+	lcd->winenable |= winenable;
+	au_sync();
+
+	return 0;
+}
+
+static void au1200_setpanel (struct panel_settings *newpanel)
+{
+	/*
+	 * Perform global setup/init of LCD controller
+	 */
+	uint32 winenable;
+
+	/* Make sure all windows disabled */
+	winenable = lcd->winenable;
+	lcd->winenable = 0;
+	au_sync();
+	/*
+	 * Ensure everything is disabled before reconfiguring
+	 */
+	if (lcd->screen & LCD_SCREEN_SEN) {
+		/* Wait for vertical sync period */
+		lcd->intstatus = LCD_INT_SS;
+		while ((lcd->intstatus & LCD_INT_SS) == 0) {
+			au_sync();
+		}
+
+		lcd->screen &= ~LCD_SCREEN_SEN;	/*disable the controller*/
+
+		do {
+			lcd->intstatus = lcd->intstatus; /*clear interrupts*/
+			au_sync();
+		/*wait for controller to shut down*/
+		} while ((lcd->intstatus & LCD_INT_SD) == 0);
+
+		/* Call shutdown of current panel (if up) */
+		/* this must occur last, because if an external clock is driving
+		    the controller, the clock cannot be turned off before first
+			shutting down the controller.
+		 */
+		if (panel->device_shutdown != NULL)
+			panel->device_shutdown();
+	}
+
+	/* Newpanel == NULL indicates a shutdown operation only */
+	if (newpanel == NULL)
+		return;
+
+	panel = newpanel;
+
+	printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres);
+
+	/*
+	 * Setup clocking if internal LCD clock source (assumes sys_auxpll valid)
+	 */
+	if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT))
+	{
+		uint32 sys_clksrc;
+		au_writel(panel->mode_auxpll, SYS_AUXPLL);
+		sys_clksrc = au_readl(SYS_CLKSRC) & ~0x0000001f;
+		sys_clksrc |= panel->mode_toyclksrc;
+		au_writel(sys_clksrc, SYS_CLKSRC);
+	}
+
+	/*
+	 * Configure panel timings
+	 */
+	lcd->screen = panel->mode_screen;
+	lcd->horztiming = panel->mode_horztiming;
+	lcd->verttiming = panel->mode_verttiming;
+	lcd->clkcontrol = panel->mode_clkcontrol;
+	lcd->pwmdiv = panel->mode_pwmdiv;
+	lcd->pwmhi = panel->mode_pwmhi;
+	lcd->outmask = panel->mode_outmask;
+	lcd->fifoctrl = panel->mode_fifoctrl;
+	au_sync();
+
+	/* fixme: Check window settings to make sure still valid
+	 * for new geometry */
+#if 0
+	au1200_setlocation(fbdev, 0, win->w[0].xpos, win->w[0].ypos);
+	au1200_setlocation(fbdev, 1, win->w[1].xpos, win->w[1].ypos);
+	au1200_setlocation(fbdev, 2, win->w[2].xpos, win->w[2].ypos);
+	au1200_setlocation(fbdev, 3, win->w[3].xpos, win->w[3].ypos);
+#endif
+	lcd->winenable = winenable;
+
+	/*
+	 * Re-enable screen now that it is configured
+	 */
+	lcd->screen |= LCD_SCREEN_SEN;
+	au_sync();
+
+	/* Call init of panel */
+	if (panel->device_init != NULL) panel->device_init();
+
+	/* FIX!!!! not appropriate on panel change!!! Global setup/init */
+	lcd->intenable = 0;
+	lcd->intstatus = ~0;
+	lcd->backcolor = win->mode_backcolor;
+
+	/* Setup Color Key - FIX!!! */
+	lcd->colorkey = win->mode_colorkey;
+	lcd->colorkeymsk = win->mode_colorkeymsk;
+
+	/* Setup HWCursor - FIX!!! Need to support this eventually */
+	lcd->hwc.cursorctrl = 0;
+	lcd->hwc.cursorpos = 0;
+	lcd->hwc.cursorcolor0 = 0;
+	lcd->hwc.cursorcolor1 = 0;
+	lcd->hwc.cursorcolor2 = 0;
+	lcd->hwc.cursorcolor3 = 0;
+
+
+#if 0
+#define D(X) printk("%25s: %08X\n", #X, X)
+	D(lcd->screen);
+	D(lcd->horztiming);
+	D(lcd->verttiming);
+	D(lcd->clkcontrol);
+	D(lcd->pwmdiv);
+	D(lcd->pwmhi);
+	D(lcd->outmask);
+	D(lcd->fifoctrl);
+	D(lcd->window[0].winctrl0);
+	D(lcd->window[0].winctrl1);
+	D(lcd->window[0].winctrl2);
+	D(lcd->window[0].winbuf0);
+	D(lcd->window[0].winbuf1);
+	D(lcd->window[0].winbufctrl);
+	D(lcd->window[1].winctrl0);
+	D(lcd->window[1].winctrl1);
+	D(lcd->window[1].winctrl2);
+	D(lcd->window[1].winbuf0);
+	D(lcd->window[1].winbuf1);
+	D(lcd->window[1].winbufctrl);
+	D(lcd->window[2].winctrl0);
+	D(lcd->window[2].winctrl1);
+	D(lcd->window[2].winctrl2);
+	D(lcd->window[2].winbuf0);
+	D(lcd->window[2].winbuf1);
+	D(lcd->window[2].winbufctrl);
+	D(lcd->window[3].winctrl0);
+	D(lcd->window[3].winctrl1);
+	D(lcd->window[3].winctrl2);
+	D(lcd->window[3].winbuf0);
+	D(lcd->window[3].winbuf1);
+	D(lcd->window[3].winbufctrl);
+	D(lcd->winenable);
+	D(lcd->intenable);
+	D(lcd->intstatus);
+	D(lcd->backcolor);
+	D(lcd->winenable);
+	D(lcd->colorkey);
+    D(lcd->colorkeymsk);
+	D(lcd->hwc.cursorctrl);
+	D(lcd->hwc.cursorpos);
+	D(lcd->hwc.cursorcolor0);
+	D(lcd->hwc.cursorcolor1);
+	D(lcd->hwc.cursorcolor2);
+	D(lcd->hwc.cursorcolor3);
+#endif
+}
+
+static void au1200_setmode(struct au1200fb_device *fbdev)
+{
+	int plane = fbdev->plane;
+	/* Window/plane setup */
+	lcd->window[plane].winctrl1 = ( 0
+		| LCD_WINCTRL1_PRI_N(plane)
+		| win->w[plane].mode_winctrl1 /* FRM,CCO,PO,PIPE */
+		) ;
+
+	au1200_setlocation(fbdev, plane, win->w[plane].xpos, win->w[plane].ypos);
+
+	lcd->window[plane].winctrl2 = ( 0
+		| LCD_WINCTRL2_CKMODE_00
+		| LCD_WINCTRL2_DBM
+		| LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length)
+		| LCD_WINCTRL2_SCX_1
+		| LCD_WINCTRL2_SCY_1
+		) ;
+	lcd->winenable |= win->w[plane].mode_winenable;
+	au_sync();
+}
+
+
+/* Inline helpers */
+
+/*#define panel_is_dual(panel)  ((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
+/*#define panel_is_active(panel)((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
+
+#define panel_is_color(panel) ((panel->mode_screen & LCD_SCREEN_PT) <= LCD_SCREEN_PT_CDSTN)
+
+/* Bitfields format supported by the controller. */
+static struct fb_bitfield rgb_bitfields[][4] = {
+  	/*     Red, 	   Green, 	 Blue, 	     Transp   */
+	[LCD_WINCTRL1_FRM_16BPP655 >> 25] =
+		{ { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPP565 >> 25] =
+		{ { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPP556 >> 25] =
+		{ { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPI1555 >> 25] =
+		{ { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPI5551 >> 25] =
+		{ { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPA1555 >> 25] =
+		{ { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } },
+
+	[LCD_WINCTRL1_FRM_16BPPA5551 >> 25] =
+		{ { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } },
+
+	[LCD_WINCTRL1_FRM_24BPP >> 25] =
+		{ { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 0, 0, 0 } },
+
+	[LCD_WINCTRL1_FRM_32BPP >> 25] =
+		{ { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 0, 0 } },
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Helpers */
+
+static void au1200fb_update_fbinfo(struct fb_info *fbi)
+{
+	/* FIX!!!! This also needs to take the window pixel format into account!!! */
+
+	/* Update var-dependent FB info */
+	if (panel_is_color(panel)) {
+		if (fbi->var.bits_per_pixel <= 8) {
+			/* palettized */
+			fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+			fbi->fix.line_length = fbi->var.xres_virtual /
+				(8/fbi->var.bits_per_pixel);
+		} else {
+			/* non-palettized */
+			fbi->fix.visual = FB_VISUAL_TRUECOLOR;
+			fbi->fix.line_length = fbi->var.xres_virtual * (fbi->var.bits_per_pixel / 8);
+		}
+	} else {
+		/* mono FIX!!! mono 8 and 4 bits */
+		fbi->fix.visual = FB_VISUAL_MONO10;
+		fbi->fix.line_length = fbi->var.xres_virtual / 8;
+	}
+
+	fbi->screen_size = fbi->fix.line_length * fbi->var.yres_virtual;
+	print_dbg("line length: %d\n", fbi->fix.line_length);
+	print_dbg("bits_per_pixel: %d\n", fbi->var.bits_per_pixel);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* AU1200 framebuffer driver */
+
+/* fb_check_var
+ * Validate var settings with hardware restrictions and modify it if necessary
+ */
+static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
+	struct fb_info *fbi)
+{
+	struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
+	u32 pixclock;
+	int screen_size, plane;
+
+	plane = fbdev->plane;
+
+	/* Make sure that the mode respect all LCD controller and
+	 * panel restrictions. */
+	var->xres = win->w[plane].xres;
+	var->yres = win->w[plane].yres;
+
+	/* No need for virtual resolution support */
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;
+
+	var->bits_per_pixel = winbpp(win->w[plane].mode_winctrl1);
+
+	screen_size = var->xres_virtual * var->yres_virtual;
+	if (var->bits_per_pixel > 8) screen_size *= (var->bits_per_pixel / 8);
+	else screen_size /= (8/var->bits_per_pixel);
+
+	if (fbdev->fb_len < screen_size)
+		return -EINVAL; /* Virtual screen is to big, abort */
+
+	/* FIX!!!! what are the implicaitons of ignoring this for windows ??? */
+	/* The max LCD clock is fixed to 48MHz (value of AUX_CLK). The pixel
+	 * clock can only be obtain by dividing this value by an even integer.
+	 * Fallback to a slower pixel clock if necessary. */
+	pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin);
+	pixclock = min(pixclock, min(fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2));
+
+	if (AU1200_LCD_MAX_CLK % pixclock) {
+		int diff = AU1200_LCD_MAX_CLK % pixclock;
+		pixclock -= diff;
+	}
+
+	var->pixclock = KHZ2PICOS(pixclock/1000);
+#if 0
+	if (!panel_is_active(panel)) {
+		int pcd = AU1200_LCD_MAX_CLK / (pixclock * 2) - 1;
+
+		if (!panel_is_color(panel)
+			&& (panel->control_base & LCD_CONTROL_MPI) && (pcd < 3)) {
+			/* STN 8bit mono panel support is up to 6MHz pixclock */
+			var->pixclock = KHZ2PICOS(6000);
+		} else if (!pcd) {
+			/* Other STN panel support is up to 12MHz  */
+			var->pixclock = KHZ2PICOS(12000);
+		}
+	}
+#endif
+	/* Set bitfield accordingly */
+	switch (var->bits_per_pixel) {
+		case 16:
+		{
+			/* 16bpp True color.
+			 * These must be set to MATCH WINCTRL[FORM] */
+			int idx;
+			idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
+			var->red    = rgb_bitfields[idx][0];
+			var->green  = rgb_bitfields[idx][1];
+			var->blue   = rgb_bitfields[idx][2];
+			var->transp = rgb_bitfields[idx][3];
+			break;
+		}
+
+		case 32:
+		{
+			/* 32bpp True color.
+			 * These must be set to MATCH WINCTRL[FORM] */
+			int idx;
+			idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
+			var->red    = rgb_bitfields[idx][0];
+			var->green  = rgb_bitfields[idx][1];
+			var->blue   = rgb_bitfields[idx][2];
+			var->transp = rgb_bitfields[idx][3];
+			break;
+		}
+		default:
+			print_dbg("Unsupported depth %dbpp", var->bits_per_pixel);
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* fb_set_par
+ * Set hardware with var settings. This will enable the controller with a
+ * specific mode, normally validated with the fb_check_var method
+ */
+static int au1200fb_fb_set_par(struct fb_info *fbi)
+{
+	struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
+
+	au1200fb_update_fbinfo(fbi);
+	au1200_setmode(fbdev);
+
+	return 0;
+}
+
+/* fb_setcolreg
+ * Set color in LCD palette.
+ */
+static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+	unsigned blue, unsigned transp, struct fb_info *fbi)
+{
+	volatile u32 *palette = lcd->palette;
+	u32 value;
+
+	if (regno > (AU1200_LCD_NBR_PALETTE_ENTRIES - 1))
+		return -EINVAL;
+
+	if (fbi->var.grayscale) {
+		/* Convert color to grayscale */
+		red = green = blue =
+			(19595 * red + 38470 * green + 7471 * blue) >> 16;
+	}
+
+	if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) {
+		/* Place color in the pseudopalette */
+		if (regno > 16)
+			return -EINVAL;
+
+		palette = (u32*) fbi->pseudo_palette;
+
+		red   >>= (16 - fbi->var.red.length);
+		green >>= (16 - fbi->var.green.length);
+		blue  >>= (16 - fbi->var.blue.length);
+
+		value = (red   << fbi->var.red.offset) 	|
+			(green << fbi->var.green.offset)|
+			(blue  << fbi->var.blue.offset);
+		value &= 0xFFFF;
+
+	} else if (1 /*FIX!!! panel_is_active(fbdev->panel)*/) {
+		/* COLOR TFT PALLETTIZED (use RGB 565) */
+		value = (red & 0xF800)|((green >> 5) &
+				0x07E0)|((blue >> 11) & 0x001F);
+		value &= 0xFFFF;
+
+	} else if (0 /*panel_is_color(fbdev->panel)*/) {
+		/* COLOR STN MODE */
+		value = 0x1234;
+		value &= 0xFFF;
+	} else {
+		/* MONOCHROME MODE */
+		value = (green >> 12) & 0x000F;
+		value &= 0xF;
+	}
+
+	palette[regno] = value;
+
+	return 0;
+}
+
+/* fb_blank
+ * Blank the screen. Depending on the mode, the screen will be
+ * activated with the backlight color, or desactivated
+ */
+static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
+{
+	/* Short-circuit screen blanking */
+	if (noblanking)
+		return 0;
+
+	switch (blank_mode) {
+
+	case FB_BLANK_UNBLANK:
+	case FB_BLANK_NORMAL:
+		/* printk("turn on panel\n"); */
+		au1200_setpanel(panel);
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_POWERDOWN:
+		/* printk("turn off panel\n"); */
+		au1200_setpanel(NULL);
+		break;
+	default:
+		break;
+
+	}
+
+	/* FB_BLANK_NORMAL is a soft blank */
+	return (blank_mode == FB_BLANK_NORMAL) ? -EINVAL : 0;
+}
+
+/* fb_mmap
+ * Map video memory in user space. We don't use the generic fb_mmap
+ * method mainly to allow the use of the TLB streaming flag (CCA=6)
+ */
+static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+
+{
+	unsigned int len;
+	unsigned long start=0, off;
+	struct au1200fb_device *fbdev = (struct au1200fb_device *) info;
+
+#ifdef CONFIG_PM
+	au1xxx_pm_access(LCD_pm_dev);
+#endif
+
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
+		return -EINVAL;
+	}
+
+	start = fbdev->fb_phys & PAGE_MASK;
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len);
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	if ((vma->vm_end - vma->vm_start + off) > len) {
+		return -EINVAL;
+	}
+
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */
+
+	vma->vm_flags |= VM_IO;
+
+	return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+				  vma->vm_end - vma->vm_start,
+				  vma->vm_page_prot);
+
+	return 0;
+}
+
+static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
+{
+
+	unsigned int hi1, divider;
+
+	/* SCREEN_SIZE: user cannot reset size, must switch panel choice */
+
+	if (pdata->flags & SCREEN_BACKCOLOR)
+		lcd->backcolor = pdata->backcolor;
+
+	if (pdata->flags & SCREEN_BRIGHTNESS) {
+
+		// limit brightness pwm duty to >= 30/1600
+		if (pdata->brightness < 30) {
+			pdata->brightness = 30;
+		}
+		divider = (lcd->pwmdiv & 0x3FFFF) + 1;
+		hi1 = (lcd->pwmhi >> 16) + 1;
+		hi1 = (((pdata->brightness & 0xFF)+1) * divider >> 8);
+		lcd->pwmhi &= 0xFFFF;
+		lcd->pwmhi |= (hi1 << 16);
+	}
+
+	if (pdata->flags & SCREEN_COLORKEY)
+		lcd->colorkey = pdata->colorkey;
+
+	if (pdata->flags & SCREEN_MASK)
+		lcd->colorkeymsk = pdata->mask;
+	au_sync();
+}
+
+static void get_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
+{
+	unsigned int hi1, divider;
+
+	pdata->xsize = ((lcd->screen & LCD_SCREEN_SX) >> 19) + 1;
+	pdata->ysize = ((lcd->screen & LCD_SCREEN_SY) >> 8) + 1;
+
+	pdata->backcolor = lcd->backcolor;
+	pdata->colorkey = lcd->colorkey;
+	pdata->mask = lcd->colorkeymsk;
+
+	// brightness
+	hi1 = (lcd->pwmhi >> 16) + 1;
+	divider = (lcd->pwmdiv & 0x3FFFF) + 1;
+	pdata->brightness = ((hi1 << 8) / divider) - 1;
+	au_sync();
+}
+
+static void set_window(unsigned int plane,
+	struct au1200_lcd_window_regs_t *pdata)
+{
+	unsigned int val, bpp;
+
+	/* Window control register 0 */
+	if (pdata->flags & WIN_POSITION) {
+		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_OX |
+				LCD_WINCTRL0_OY);
+		val |= ((pdata->xpos << 21) & LCD_WINCTRL0_OX);
+		val |= ((pdata->ypos << 10) & LCD_WINCTRL0_OY);
+		lcd->window[plane].winctrl0 = val;
+	}
+	if (pdata->flags & WIN_ALPHA_COLOR) {
+		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_A);
+		val |= ((pdata->alpha_color << 2) & LCD_WINCTRL0_A);
+		lcd->window[plane].winctrl0 = val;
+	}
+	if (pdata->flags & WIN_ALPHA_MODE) {
+		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_AEN);
+		val |= ((pdata->alpha_mode << 1) & LCD_WINCTRL0_AEN);
+		lcd->window[plane].winctrl0 = val;
+	}
+
+	/* Window control register 1 */
+	if (pdata->flags & WIN_PRIORITY) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PRI);
+		val |= ((pdata->priority << 30) & LCD_WINCTRL1_PRI);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_CHANNEL) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PIPE);
+		val |= ((pdata->channel << 29) & LCD_WINCTRL1_PIPE);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_BUFFER_FORMAT) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_FRM);
+		val |= ((pdata->buffer_format << 25) & LCD_WINCTRL1_FRM);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_COLOR_ORDER) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_CCO);
+		val |= ((pdata->color_order << 24) & LCD_WINCTRL1_CCO);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_PIXEL_ORDER) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PO);
+		val |= ((pdata->pixel_order << 22) & LCD_WINCTRL1_PO);
+		lcd->window[plane].winctrl1 = val;
+	}
+	if (pdata->flags & WIN_SIZE) {
+		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_SZX |
+				LCD_WINCTRL1_SZY);
+		val |= (((pdata->xsize << 11) - 1) & LCD_WINCTRL1_SZX);
+		val |= (((pdata->ysize) - 1) & LCD_WINCTRL1_SZY);
+		lcd->window[plane].winctrl1 = val;
+		/* program buffer line width */
+		bpp = winbpp(val) / 8;
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_BX);
+		val |= (((pdata->xsize * bpp) << 8) & LCD_WINCTRL2_BX);
+		lcd->window[plane].winctrl2 = val;
+	}
+
+	/* Window control register 2 */
+	if (pdata->flags & WIN_COLORKEY_MODE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_CKMODE);
+		val |= ((pdata->colorkey_mode << 24) & LCD_WINCTRL2_CKMODE);
+		lcd->window[plane].winctrl2 = val;
+	}
+	if (pdata->flags & WIN_DOUBLE_BUFFER_MODE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_DBM);
+		val |= ((pdata->double_buffer_mode << 23) & LCD_WINCTRL2_DBM);
+		lcd->window[plane].winctrl2 = val;
+	}
+	if (pdata->flags & WIN_RAM_ARRAY_MODE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_RAM);
+		val |= ((pdata->ram_array_mode << 21) & LCD_WINCTRL2_RAM);
+		lcd->window[plane].winctrl2 = val;
+	}
+
+	/* Buffer line width programmed with WIN_SIZE */
+
+	if (pdata->flags & WIN_BUFFER_SCALE) {
+		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_SCX |
+				LCD_WINCTRL2_SCY);
+		val |= ((pdata->xsize << 11) & LCD_WINCTRL2_SCX);
+		val |= ((pdata->ysize) & LCD_WINCTRL2_SCY);
+		lcd->window[plane].winctrl2 = val;
+	}
+
+	if (pdata->flags & WIN_ENABLE) {
+		val = lcd->winenable;
+		val &= ~(1<<plane);
+		val |= (pdata->enable & 1) << plane;
+		lcd->winenable = val;
+	}
+	au_sync();
+}
+
+static void get_window(unsigned int plane,
+	struct au1200_lcd_window_regs_t *pdata)
+{
+	/* Window control register 0 */
+	pdata->xpos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OX) >> 21;
+	pdata->ypos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OY) >> 10;
+	pdata->alpha_color = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_A) >> 2;
+	pdata->alpha_mode = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_AEN) >> 1;
+
+	/* Window control register 1 */
+	pdata->priority = (lcd->window[plane].winctrl1& LCD_WINCTRL1_PRI) >> 30;
+	pdata->channel = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PIPE) >> 29;
+	pdata->buffer_format = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_FRM) >> 25;
+	pdata->color_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_CCO) >> 24;
+	pdata->pixel_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PO) >> 22;
+	pdata->xsize = ((lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11) + 1;
+	pdata->ysize = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZY) + 1;
+
+	/* Window control register 2 */
+	pdata->colorkey_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_CKMODE) >> 24;
+	pdata->double_buffer_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_DBM) >> 23;
+	pdata->ram_array_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_RAM) >> 21;
+
+	pdata->enable = (lcd->winenable >> plane) & 1;
+	au_sync();
+}
+
+static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
+                          unsigned long arg)
+{
+	int plane;
+	int val;
+
+#ifdef CONFIG_PM
+	au1xxx_pm_access(LCD_pm_dev);
+#endif
+
+	plane = fbinfo2index(info);
+	print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane);
+
+	if (cmd == AU1200_LCD_FB_IOCTL) {
+		struct au1200_lcd_iodata_t iodata;
+
+		if (copy_from_user(&iodata, (void __user *) arg, sizeof(iodata)))
+			return -EFAULT;
+
+		print_dbg("FB IOCTL called\n");
+
+		switch (iodata.subcmd) {
+		case AU1200_LCD_SET_SCREEN:
+			print_dbg("AU1200_LCD_SET_SCREEN\n");
+			set_global(cmd, &iodata.global);
+			break;
+
+		case AU1200_LCD_GET_SCREEN:
+			print_dbg("AU1200_LCD_GET_SCREEN\n");
+			get_global(cmd, &iodata.global);
+			break;
+
+		case AU1200_LCD_SET_WINDOW:
+			print_dbg("AU1200_LCD_SET_WINDOW\n");
+			set_window(plane, &iodata.window);
+			break;
+
+		case AU1200_LCD_GET_WINDOW:
+			print_dbg("AU1200_LCD_GET_WINDOW\n");
+			get_window(plane, &iodata.window);
+			break;
+
+		case AU1200_LCD_SET_PANEL:
+			print_dbg("AU1200_LCD_SET_PANEL\n");
+			if ((iodata.global.panel_choice >= 0) &&
+					(iodata.global.panel_choice <
+					 NUM_PANELS))
+			{
+				struct panel_settings *newpanel;
+				panel_index = iodata.global.panel_choice;
+				newpanel = &known_lcd_panels[panel_index];
+				au1200_setpanel(newpanel);
+			}
+			break;
+
+		case AU1200_LCD_GET_PANEL:
+			print_dbg("AU1200_LCD_GET_PANEL\n");
+			iodata.global.panel_choice = panel_index;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+
+		val = copy_to_user((void __user *) arg, &iodata, sizeof(iodata));
+		if (val) {
+			print_dbg("error: could not copy %d bytes\n", val);
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+
+static struct fb_ops au1200fb_fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= au1200fb_fb_check_var,
+	.fb_set_par	= au1200fb_fb_set_par,
+	.fb_setcolreg	= au1200fb_fb_setcolreg,
+	.fb_blank	= au1200fb_fb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_sync	= NULL,
+	.fb_ioctl	= au1200fb_ioctl,
+	.fb_mmap	= au1200fb_fb_mmap,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id, struct pt_regs *regs)
+{
+	/* Nothing to do for now, just clear any pending interrupt */
+	lcd->intstatus = lcd->intstatus;
+	au_sync();
+
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* AU1200 LCD device probe helpers */
+
+static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
+{
+	struct fb_info *fbi = &fbdev->fb_info;
+	int bpp;
+
+	memset(fbi, 0, sizeof(struct fb_info));
+	fbi->fbops = &au1200fb_fb_ops;
+
+	bpp = winbpp(win->w[fbdev->plane].mode_winctrl1);
+
+	/* Copy monitor specs from panel data */
+	/* fixme: we're setting up LCD controller windows, so these dont give a
+	damn as to what the monitor specs are (the panel itself does, but that
+	isnt done here...so maybe need a generic catchall monitor setting??? */
+	memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs));
+
+	/* We first try the user mode passed in argument. If that failed,
+	 * or if no one has been specified, we default to the first mode of the
+	 * panel list. Note that after this call, var data will be set */
+	if (!fb_find_mode(&fbi->var,
+			  fbi,
+			  NULL, /* drv_info.opt_mode, */
+			  fbi->monspecs.modedb,
+			  fbi->monspecs.modedb_len,
+			  fbi->monspecs.modedb,
+			  bpp)) {
+
+		print_err("Cannot find valid mode for panel %s", panel->name);
+		return -EFAULT;
+	}
+
+	fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+	if (!fbi->pseudo_palette) {
+		return -ENOMEM;
+	}
+	memset(fbi->pseudo_palette, 0, sizeof(u32) * 16);
+
+	if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
+		print_err("Fail to allocate colormap (%d entries)",
+			   AU1200_LCD_NBR_PALETTE_ENTRIES);
+		kfree(fbi->pseudo_palette);
+		return -EFAULT;
+	}
+
+	strncpy(fbi->fix.id, "AU1200", sizeof(fbi->fix.id));
+	fbi->fix.smem_start = fbdev->fb_phys;
+	fbi->fix.smem_len = fbdev->fb_len;
+	fbi->fix.type = FB_TYPE_PACKED_PIXELS;
+	fbi->fix.xpanstep = 0;
+	fbi->fix.ypanstep = 0;
+	fbi->fix.mmio_start = 0;
+	fbi->fix.mmio_len = 0;
+	fbi->fix.accel = FB_ACCEL_NONE;
+
+	fbi->screen_base = (char __iomem *) fbdev->fb_mem;
+
+	au1200fb_update_fbinfo(fbi);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* AU1200 LCD controller device driver */
+
+static int au1200fb_drv_probe(struct device *dev)
+{
+	struct au1200fb_device *fbdev;
+	unsigned long page;
+	int bpp, plane, ret;
+
+	if (!dev)
+		return -EINVAL;
+
+	for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) {
+		bpp = winbpp(win->w[plane].mode_winctrl1);
+		if (win->w[plane].xres == 0)
+			win->w[plane].xres = panel->Xres;
+		if (win->w[plane].yres == 0)
+			win->w[plane].yres = panel->Yres;
+
+		fbdev = &_au1200fb_devices[plane];
+		memset(fbdev, 0, sizeof(struct au1200fb_device));
+		fbdev->plane = plane;
+
+		/* Allocate the framebuffer to the maximum screen size */
+		fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8;
+
+		fbdev->fb_mem = dma_alloc_noncoherent(dev,
+				PAGE_ALIGN(fbdev->fb_len),
+				&fbdev->fb_phys, GFP_KERNEL);
+		if (!fbdev->fb_mem) {
+			print_err("fail to allocate frambuffer (size: %dK))",
+				  fbdev->fb_len / 1024);
+			return -ENOMEM;
+		}
+
+		/*
+		 * Set page reserved so that mmap will work. This is necessary
+		 * since we'll be remapping normal memory.
+		 */
+		for (page = (unsigned long)fbdev->fb_phys;
+		     page < PAGE_ALIGN((unsigned long)fbdev->fb_phys +
+			     fbdev->fb_len);
+		     page += PAGE_SIZE) {
+			SetPageReserved(pfn_to_page(page >> PAGE_SHIFT)); /* LCD DMA is NOT coherent on Au1200 */
+		}
+		print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
+		print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
+
+		/* Init FB data */
+		if ((ret = au1200fb_init_fbinfo(fbdev)) < 0)
+			goto failed;
+
+		/* Register new framebuffer */
+		if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) {
+			print_err("cannot register new framebuffer");
+			goto failed;
+		}
+
+		au1200fb_fb_set_par(&fbdev->fb_info);
+
+#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
+		if (plane == 0)
+			if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) {
+				/* Start display and show logo on boot */
+				fb_set_cmap(&fbdev->fb_info.cmap,
+						&fbdev->fb_info);
+
+				fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR);
+			}
+#endif
+	}
+
+	/* Now hook interrupt too */
+	if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq,
+		 	  SA_INTERRUPT | SA_SHIRQ, "lcd", (void *)dev)) < 0) {
+		print_err("fail to request interrupt line %d (err: %d)",
+			  AU1200_LCD_INT, ret);
+		goto failed;
+	}
+
+	return 0;
+
+failed:
+	/* NOTE: This only does the current plane/window that failed; others are still active */
+	if (fbdev->fb_mem)
+		dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len),
+				fbdev->fb_mem, fbdev->fb_phys);
+	if (fbdev->fb_info.cmap.len != 0)
+		fb_dealloc_cmap(&fbdev->fb_info.cmap);
+	if (fbdev->fb_info.pseudo_palette)
+		kfree(fbdev->fb_info.pseudo_palette);
+	if (plane == 0)
+		free_irq(AU1200_LCD_INT, (void*)dev);
+	return ret;
+}
+
+static int au1200fb_drv_remove(struct device *dev)
+{
+	struct au1200fb_device *fbdev;
+	int plane;
+
+	if (!dev)
+		return -ENODEV;
+
+	/* Turn off the panel */
+	au1200_setpanel(NULL);
+
+	for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane)
+	{
+		fbdev = &_au1200fb_devices[plane];
+
+		/* Clean up all probe data */
+		unregister_framebuffer(&fbdev->fb_info);
+		if (fbdev->fb_mem)
+			dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len),
+					fbdev->fb_mem, fbdev->fb_phys);
+		if (fbdev->fb_info.cmap.len != 0)
+			fb_dealloc_cmap(&fbdev->fb_info.cmap);
+		if (fbdev->fb_info.pseudo_palette)
+			kfree(fbdev->fb_info.pseudo_palette);
+	}
+
+	free_irq(AU1200_LCD_INT, (void *)dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int au1200fb_drv_suspend(struct device *dev, u32 state, u32 level)
+{
+	/* TODO */
+	return 0;
+}
+
+static int au1200fb_drv_resume(struct device *dev, u32 level)
+{
+	/* TODO */
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct device_driver au1200fb_driver = {
+	.name		= "au1200-lcd",
+	.bus		= &platform_bus_type,
+	.probe		= au1200fb_drv_probe,
+	.remove		= au1200fb_drv_remove,
+#ifdef CONFIG_PM
+	.suspend	= au1200fb_drv_suspend,
+	.resume		= au1200fb_drv_resume,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Kernel driver */
+
+static void au1200fb_setup(void)
+{
+	char* options = NULL;
+	char* this_opt;
+	int num_panels = ARRAY_SIZE(known_lcd_panels);
+	int panel_idx = -1;
+
+	fb_get_options(DRIVER_NAME, &options);
+
+	if (options) {
+		while ((this_opt = strsep(&options,",")) != NULL) {
+			/* Panel option - can be panel name,
+			 * "bs" for board-switch, or number/index */
+			if (!strncmp(this_opt, "panel:", 6)) {
+				int i;
+				long int li;
+				char *endptr;
+				this_opt += 6;
+				/* First check for index, which allows
+				 * to short circuit this mess */
+				li = simple_strtol(this_opt, &endptr, 0);
+				if (*endptr == '\0') {
+					panel_idx = (int)li;
+				}
+				else if (strcmp(this_opt, "bs") == 0) {
+					extern int board_au1200fb_panel(void);
+					panel_idx = board_au1200fb_panel();
+				}
+
+				else
+				for (i = 0; i < num_panels; i++) {
+					if (!strcmp(this_opt, known_lcd_panels[i].name)) {
+						panel_idx = i;
+						break;
+					}
+				}
+
+				if ((panel_idx < 0) || (panel_idx >= num_panels)) {
+						print_warn("Panel %s not supported!", this_opt);
+				}
+				else
+					panel_index = panel_idx;
+			}
+
+			else if (strncmp(this_opt, "nohwcursor", 10) == 0) {
+				nohwcursor = 1;
+			}
+
+			/* Unsupported option */
+			else {
+				print_warn("Unsupported option \"%s\"", this_opt);
+			}
+		}
+	}
+}
+
+#ifdef CONFIG_PM
+static int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
+		au1xxx_request_t request, void *data) {
+	int retval = -1;
+	unsigned int d = 0;
+	unsigned int brightness = 0;
+
+	if (request == AU1XXX_PM_SLEEP) {
+		board_au1200fb_panel_shutdown();
+	}
+	else if (request == AU1XXX_PM_WAKEUP) {
+		if(dev->prev_state == SLEEP_STATE)
+		{
+			int plane;
+			au1200_setpanel(panel);
+			for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) 	{
+				struct au1200fb_device *fbdev;
+				fbdev = &_au1200fb_devices[plane];
+				au1200fb_fb_set_par(&fbdev->fb_info);
+			}
+		}
+
+		d = *((unsigned int*)data);
+		if(d <=10) brightness = 26;
+		else if(d<=20) brightness = 51;
+		else if(d<=30) brightness = 77;
+		else if(d<=40) brightness = 102;
+		else if(d<=50) brightness = 128;
+		else if(d<=60) brightness = 153;
+		else if(d<=70) brightness = 179;
+		else if(d<=80) brightness = 204;
+		else if(d<=90) brightness = 230;
+		else brightness = 255;
+		set_brightness(brightness);
+	} else if (request == AU1XXX_PM_GETSTATUS) {
+		return dev->cur_state;
+	} else if (request == AU1XXX_PM_ACCESS) {
+		if (dev->cur_state != SLEEP_STATE)
+			return retval;
+		else {
+			au1200_setpanel(panel);
+		}
+	} else if (request == AU1XXX_PM_IDLE) {
+	} else if (request == AU1XXX_PM_CLEANUP) {
+	}
+
+	return retval;
+}
+#endif
+
+static int __init au1200fb_init(void)
+{
+	print_info("" DRIVER_DESC "");
+
+	/* Setup driver with options */
+	au1200fb_setup();
+
+	/* Point to the panel selected */
+	panel = &known_lcd_panels[panel_index];
+	win = &windows[window_index];
+
+	printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
+	printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
+
+	/* Kickstart the panel, the framebuffers/windows come soon enough */
+	au1200_setpanel(panel);
+
+	#ifdef CONFIG_PM
+	LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL);
+	if ( LCD_pm_dev == NULL)
+		printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n");
+	else
+		printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n");
+	#endif
+
+	return driver_register(&au1200fb_driver);
+}
+
+static void __exit au1200fb_cleanup(void)
+{
+	driver_unregister(&au1200fb_driver);
+}
+
+module_init(au1200fb_init);
+module_exit(au1200fb_cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/au1200fb.h b/drivers/video/au1200fb.h
new file mode 100644
index 0000000..e267271
--- /dev/null
+++ b/drivers/video/au1200fb.h
@@ -0,0 +1,572 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Hardware definitions for the Au1200 LCD controller
+ *
+ * Copyright 2004 AMD
+ * Author:	AMD
+ *
+ *  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  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _AU1200LCD_H
+#define _AU1200LCD_H
+
+/********************************************************************/
+#define AU1200_LCD_ADDR		0xB5000000
+
+#define uint8 unsigned char
+#define uint32 unsigned int
+
+struct au1200_lcd {
+	volatile uint32	reserved0;
+	volatile uint32	screen;
+	volatile uint32	backcolor;
+	volatile uint32	horztiming;
+	volatile uint32	verttiming;
+	volatile uint32	clkcontrol;
+	volatile uint32	pwmdiv;
+	volatile uint32	pwmhi;
+	volatile uint32	reserved1;
+	volatile uint32	winenable;
+	volatile uint32	colorkey;
+	volatile uint32	colorkeymsk;
+	struct
+	{
+		volatile uint32	cursorctrl;
+		volatile uint32	cursorpos;
+		volatile uint32	cursorcolor0;
+		volatile uint32	cursorcolor1;
+		volatile uint32	cursorcolor2;
+		uint32	cursorcolor3;
+	} hwc;
+	volatile uint32	intstatus;
+	volatile uint32	intenable;
+	volatile uint32	outmask;
+	volatile uint32	fifoctrl;
+	uint32	reserved2[(0x0100-0x0058)/4];
+	struct
+	{
+		volatile uint32	winctrl0;
+		volatile uint32	winctrl1;
+		volatile uint32	winctrl2;
+		volatile uint32	winbuf0;
+		volatile uint32	winbuf1;
+		volatile uint32	winbufctrl;
+		uint32	winreserved0;
+		uint32	winreserved1;
+	} window[4];
+
+	uint32	reserved3[(0x0400-0x0180)/4];
+
+	volatile uint32	palette[(0x0800-0x0400)/4];
+
+	volatile uint8	cursorpattern[256];
+};
+
+/* lcd_screen */
+#define LCD_SCREEN_SEN		(1<<31)
+#define LCD_SCREEN_SX		(0x07FF<<19)
+#define LCD_SCREEN_SY		(0x07FF<< 8)
+#define LCD_SCREEN_SWP		(1<<7)
+#define LCD_SCREEN_SWD		(1<<6)
+#define LCD_SCREEN_PT		(7<<0)
+#define LCD_SCREEN_PT_TFT	(0<<0)
+#define LCD_SCREEN_SX_N(WIDTH)	((WIDTH-1)<<19)
+#define LCD_SCREEN_SY_N(HEIGHT)	((HEIGHT-1)<<8)
+#define LCD_SCREEN_PT_CSTN	(1<<0)
+#define LCD_SCREEN_PT_CDSTN	(2<<0)
+#define LCD_SCREEN_PT_M8STN	(3<<0)
+#define LCD_SCREEN_PT_M4STN	(4<<0)
+
+/* lcd_backcolor */
+#define LCD_BACKCOLOR_SBGR		(0xFF<<16)
+#define LCD_BACKCOLOR_SBGG		(0xFF<<8)
+#define LCD_BACKCOLOR_SBGB		(0xFF<<0)
+#define LCD_BACKCOLOR_SBGR_N(N)	((N)<<16)
+#define LCD_BACKCOLOR_SBGG_N(N)	((N)<<8)
+#define LCD_BACKCOLOR_SBGB_N(N)	((N)<<0)
+
+/* lcd_winenable */
+#define LCD_WINENABLE_WEN3		(1<<3)
+#define LCD_WINENABLE_WEN2		(1<<2)
+#define LCD_WINENABLE_WEN1		(1<<1)
+#define LCD_WINENABLE_WEN0		(1<<0)
+
+/* lcd_colorkey */
+#define LCD_COLORKEY_CKR		(0xFF<<16)
+#define LCD_COLORKEY_CKG		(0xFF<<8)
+#define LCD_COLORKEY_CKB		(0xFF<<0)
+#define LCD_COLORKEY_CKR_N(N)	((N)<<16)
+#define LCD_COLORKEY_CKG_N(N)	((N)<<8)
+#define LCD_COLORKEY_CKB_N(N)	((N)<<0)
+
+/* lcd_colorkeymsk */
+#define LCD_COLORKEYMSK_CKMR		(0xFF<<16)
+#define LCD_COLORKEYMSK_CKMG		(0xFF<<8)
+#define LCD_COLORKEYMSK_CKMB		(0xFF<<0)
+#define LCD_COLORKEYMSK_CKMR_N(N)	((N)<<16)
+#define LCD_COLORKEYMSK_CKMG_N(N)	((N)<<8)
+#define LCD_COLORKEYMSK_CKMB_N(N)	((N)<<0)
+
+/* lcd windows control 0 */
+#define LCD_WINCTRL0_OX		(0x07FF<<21)
+#define LCD_WINCTRL0_OY		(0x07FF<<10)
+#define LCD_WINCTRL0_A		(0x00FF<<2)
+#define LCD_WINCTRL0_AEN	(1<<1)
+#define LCD_WINCTRL0_OX_N(N) ((N)<<21)
+#define LCD_WINCTRL0_OY_N(N) ((N)<<10)
+#define LCD_WINCTRL0_A_N(N) ((N)<<2)
+
+/* lcd windows control 1 */
+#define LCD_WINCTRL1_PRI	(3<<30)
+#define LCD_WINCTRL1_PIPE	(1<<29)
+#define LCD_WINCTRL1_FRM	(0xF<<25)
+#define LCD_WINCTRL1_CCO	(1<<24)
+#define LCD_WINCTRL1_PO		(3<<22)
+#define LCD_WINCTRL1_SZX	(0x07FF<<11)
+#define LCD_WINCTRL1_SZY	(0x07FF<<0)
+#define LCD_WINCTRL1_FRM_1BPP	(0<<25)
+#define LCD_WINCTRL1_FRM_2BPP	(1<<25)
+#define LCD_WINCTRL1_FRM_4BPP	(2<<25)
+#define LCD_WINCTRL1_FRM_8BPP	(3<<25)
+#define LCD_WINCTRL1_FRM_12BPP	(4<<25)
+#define LCD_WINCTRL1_FRM_16BPP655	(5<<25)
+#define LCD_WINCTRL1_FRM_16BPP565	(6<<25)
+#define LCD_WINCTRL1_FRM_16BPP556	(7<<25)
+#define LCD_WINCTRL1_FRM_16BPPI1555	(8<<25)
+#define LCD_WINCTRL1_FRM_16BPPI5551	(9<<25)
+#define LCD_WINCTRL1_FRM_16BPPA1555	(10<<25)
+#define LCD_WINCTRL1_FRM_16BPPA5551	(11<<25)
+#define LCD_WINCTRL1_FRM_24BPP		(12<<25)
+#define LCD_WINCTRL1_FRM_32BPP		(13<<25)
+#define LCD_WINCTRL1_PRI_N(N)	((N)<<30)
+#define LCD_WINCTRL1_PO_00		(0<<22)
+#define LCD_WINCTRL1_PO_01		(1<<22)
+#define LCD_WINCTRL1_PO_10		(2<<22)
+#define LCD_WINCTRL1_PO_11		(3<<22)
+#define LCD_WINCTRL1_SZX_N(N)	((N-1)<<11)
+#define LCD_WINCTRL1_SZY_N(N)	((N-1)<<0)
+
+/* lcd windows control 2 */
+#define LCD_WINCTRL2_CKMODE		(3<<24)
+#define LCD_WINCTRL2_DBM		(1<<23)
+#define LCD_WINCTRL2_RAM		(3<<21)
+#define LCD_WINCTRL2_BX			(0x1FFF<<8)
+#define LCD_WINCTRL2_SCX		(0xF<<4)
+#define LCD_WINCTRL2_SCY		(0xF<<0)
+#define LCD_WINCTRL2_CKMODE_00		(0<<24)
+#define LCD_WINCTRL2_CKMODE_01		(1<<24)
+#define LCD_WINCTRL2_CKMODE_10		(2<<24)
+#define LCD_WINCTRL2_CKMODE_11		(3<<24)
+#define LCD_WINCTRL2_RAM_NONE		(0<<21)
+#define LCD_WINCTRL2_RAM_PALETTE	(1<<21)
+#define LCD_WINCTRL2_RAM_GAMMA		(2<<21)
+#define LCD_WINCTRL2_RAM_BUFFER		(3<<21)
+#define LCD_WINCTRL2_BX_N(N)	((N)<<8)
+#define LCD_WINCTRL2_SCX_1		(0<<4)
+#define LCD_WINCTRL2_SCX_2		(1<<4)
+#define LCD_WINCTRL2_SCX_4		(2<<4)
+#define LCD_WINCTRL2_SCY_1		(0<<0)
+#define LCD_WINCTRL2_SCY_2		(1<<0)
+#define LCD_WINCTRL2_SCY_4		(2<<0)
+
+/* lcd windows buffer control */
+#define LCD_WINBUFCTRL_DB		(1<<1)
+#define LCD_WINBUFCTRL_DBN		(1<<0)
+
+/* lcd_intstatus, lcd_intenable */
+#define LCD_INT_IFO				(0xF<<14)
+#define LCD_INT_IFU				(0xF<<10)
+#define LCD_INT_OFO				(1<<9)
+#define LCD_INT_OFU				(1<<8)
+#define LCD_INT_WAIT			(1<<3)
+#define LCD_INT_SD				(1<<2)
+#define LCD_INT_SA				(1<<1)
+#define LCD_INT_SS				(1<<0)
+
+/* lcd_horztiming */
+#define LCD_HORZTIMING_HND2		(0x1FF<<18)
+#define LCD_HORZTIMING_HND1		(0x1FF<<9)
+#define LCD_HORZTIMING_HPW		(0x1FF<<0)
+#define LCD_HORZTIMING_HND2_N(N)(((N)-1)<<18)
+#define LCD_HORZTIMING_HND1_N(N)(((N)-1)<<9)
+#define LCD_HORZTIMING_HPW_N(N)	(((N)-1)<<0)
+
+/* lcd_verttiming */
+#define LCD_VERTTIMING_VND2		(0x1FF<<18)
+#define LCD_VERTTIMING_VND1		(0x1FF<<9)
+#define LCD_VERTTIMING_VPW		(0x1FF<<0)
+#define LCD_VERTTIMING_VND2_N(N)(((N)-1)<<18)
+#define LCD_VERTTIMING_VND1_N(N)(((N)-1)<<9)
+#define LCD_VERTTIMING_VPW_N(N)	(((N)-1)<<0)
+
+/* lcd_clkcontrol */
+#define LCD_CLKCONTROL_EXT		(1<<22)
+#define LCD_CLKCONTROL_DELAY	(3<<20)
+#define LCD_CLKCONTROL_CDD		(1<<19)
+#define LCD_CLKCONTROL_IB		(1<<18)
+#define LCD_CLKCONTROL_IC		(1<<17)
+#define LCD_CLKCONTROL_IH		(1<<16)
+#define LCD_CLKCONTROL_IV		(1<<15)
+#define LCD_CLKCONTROL_BF		(0x1F<<10)
+#define LCD_CLKCONTROL_PCD		(0x3FF<<0)
+#define LCD_CLKCONTROL_BF_N(N)	(((N)-1)<<10)
+#define LCD_CLKCONTROL_PCD_N(N)	((N)<<0)
+
+/* lcd_pwmdiv */
+#define LCD_PWMDIV_EN			(1<<31)
+#define LCD_PWMDIV_PWMDIV		(0x1FFFF<<0)
+#define LCD_PWMDIV_PWMDIV_N(N)	((N)<<0)
+
+/* lcd_pwmhi */
+#define LCD_PWMHI_PWMHI1		(0xFFFF<<16)
+#define LCD_PWMHI_PWMHI0		(0xFFFF<<0)
+#define LCD_PWMHI_PWMHI1_N(N)	((N)<<16)
+#define LCD_PWMHI_PWMHI0_N(N)	((N)<<0)
+
+/* lcd_hwccon */
+#define LCD_HWCCON_EN			(1<<0)
+
+/* lcd_cursorpos */
+#define LCD_CURSORPOS_HWCXOFF		(0x1F<<27)
+#define LCD_CURSORPOS_HWCXPOS		(0x07FF<<16)
+#define LCD_CURSORPOS_HWCYOFF		(0x1F<<11)
+#define LCD_CURSORPOS_HWCYPOS		(0x07FF<<0)
+#define LCD_CURSORPOS_HWCXOFF_N(N)	((N)<<27)
+#define LCD_CURSORPOS_HWCXPOS_N(N)	((N)<<16)
+#define LCD_CURSORPOS_HWCYOFF_N(N)	((N)<<11)
+#define LCD_CURSORPOS_HWCYPOS_N(N)	((N)<<0)
+
+/* lcd_cursorcolor */
+#define LCD_CURSORCOLOR_HWCA		(0xFF<<24)
+#define LCD_CURSORCOLOR_HWCR		(0xFF<<16)
+#define LCD_CURSORCOLOR_HWCG		(0xFF<<8)
+#define LCD_CURSORCOLOR_HWCB		(0xFF<<0)
+#define LCD_CURSORCOLOR_HWCA_N(N)	((N)<<24)
+#define LCD_CURSORCOLOR_HWCR_N(N)	((N)<<16)
+#define LCD_CURSORCOLOR_HWCG_N(N)	((N)<<8)
+#define LCD_CURSORCOLOR_HWCB_N(N)	((N)<<0)
+
+/* lcd_fifoctrl */
+#define LCD_FIFOCTRL_F3IF		(1<<29)
+#define LCD_FIFOCTRL_F3REQ		(0x1F<<24)
+#define LCD_FIFOCTRL_F2IF		(1<<29)
+#define LCD_FIFOCTRL_F2REQ		(0x1F<<16)
+#define LCD_FIFOCTRL_F1IF		(1<<29)
+#define LCD_FIFOCTRL_F1REQ		(0x1F<<8)
+#define LCD_FIFOCTRL_F0IF		(1<<29)
+#define LCD_FIFOCTRL_F0REQ		(0x1F<<0)
+#define LCD_FIFOCTRL_F3REQ_N(N)	((N-1)<<24)
+#define LCD_FIFOCTRL_F2REQ_N(N)	((N-1)<<16)
+#define LCD_FIFOCTRL_F1REQ_N(N)	((N-1)<<8)
+#define LCD_FIFOCTRL_F0REQ_N(N)	((N-1)<<0)
+
+/* lcd_outmask */
+#define LCD_OUTMASK_MASK		(0x00FFFFFF)
+
+/********************************************************************/
+#endif /* _AU1200LCD_H */
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Hardware definitions for the Au1200 LCD controller
+ *
+ * Copyright 2004 AMD
+ * Author:	AMD
+ *
+ *  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  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _AU1200LCD_H
+#define _AU1200LCD_H
+
+/********************************************************************/
+#define AU1200_LCD_ADDR		0xB5000000
+
+#define uint8 unsigned char
+#define uint32 unsigned int
+
+struct au1200_lcd {
+	volatile uint32	reserved0;
+	volatile uint32	screen;
+	volatile uint32	backcolor;
+	volatile uint32	horztiming;
+	volatile uint32	verttiming;
+	volatile uint32	clkcontrol;
+	volatile uint32	pwmdiv;
+	volatile uint32	pwmhi;
+	volatile uint32	reserved1;
+	volatile uint32	winenable;
+	volatile uint32	colorkey;
+	volatile uint32	colorkeymsk;
+	struct
+	{
+		volatile uint32	cursorctrl;
+		volatile uint32	cursorpos;
+		volatile uint32	cursorcolor0;
+		volatile uint32	cursorcolor1;
+		volatile uint32	cursorcolor2;
+		uint32	cursorcolor3;
+	} hwc;
+	volatile uint32	intstatus;
+	volatile uint32	intenable;
+	volatile uint32	outmask;
+	volatile uint32	fifoctrl;
+	uint32	reserved2[(0x0100-0x0058)/4];
+	struct
+	{
+		volatile uint32	winctrl0;
+		volatile uint32	winctrl1;
+		volatile uint32	winctrl2;
+		volatile uint32	winbuf0;
+		volatile uint32	winbuf1;
+		volatile uint32	winbufctrl;
+		uint32	winreserved0;
+		uint32	winreserved1;
+	} window[4];
+
+	uint32	reserved3[(0x0400-0x0180)/4];
+
+	volatile uint32	palette[(0x0800-0x0400)/4];
+
+	volatile uint8	cursorpattern[256];
+};
+
+/* lcd_screen */
+#define LCD_SCREEN_SEN		(1<<31)
+#define LCD_SCREEN_SX		(0x07FF<<19)
+#define LCD_SCREEN_SY		(0x07FF<< 8)
+#define LCD_SCREEN_SWP		(1<<7)
+#define LCD_SCREEN_SWD		(1<<6)
+#define LCD_SCREEN_PT		(7<<0)
+#define LCD_SCREEN_PT_TFT	(0<<0)
+#define LCD_SCREEN_SX_N(WIDTH)	((WIDTH-1)<<19)
+#define LCD_SCREEN_SY_N(HEIGHT)	((HEIGHT-1)<<8)
+#define LCD_SCREEN_PT_CSTN	(1<<0)
+#define LCD_SCREEN_PT_CDSTN	(2<<0)
+#define LCD_SCREEN_PT_M8STN	(3<<0)
+#define LCD_SCREEN_PT_M4STN	(4<<0)
+
+/* lcd_backcolor */
+#define LCD_BACKCOLOR_SBGR		(0xFF<<16)
+#define LCD_BACKCOLOR_SBGG		(0xFF<<8)
+#define LCD_BACKCOLOR_SBGB		(0xFF<<0)
+#define LCD_BACKCOLOR_SBGR_N(N)	((N)<<16)
+#define LCD_BACKCOLOR_SBGG_N(N)	((N)<<8)
+#define LCD_BACKCOLOR_SBGB_N(N)	((N)<<0)
+
+/* lcd_winenable */
+#define LCD_WINENABLE_WEN3		(1<<3)
+#define LCD_WINENABLE_WEN2		(1<<2)
+#define LCD_WINENABLE_WEN1		(1<<1)
+#define LCD_WINENABLE_WEN0		(1<<0)
+
+/* lcd_colorkey */
+#define LCD_COLORKEY_CKR		(0xFF<<16)
+#define LCD_COLORKEY_CKG		(0xFF<<8)
+#define LCD_COLORKEY_CKB		(0xFF<<0)
+#define LCD_COLORKEY_CKR_N(N)	((N)<<16)
+#define LCD_COLORKEY_CKG_N(N)	((N)<<8)
+#define LCD_COLORKEY_CKB_N(N)	((N)<<0)
+
+/* lcd_colorkeymsk */
+#define LCD_COLORKEYMSK_CKMR		(0xFF<<16)
+#define LCD_COLORKEYMSK_CKMG		(0xFF<<8)
+#define LCD_COLORKEYMSK_CKMB		(0xFF<<0)
+#define LCD_COLORKEYMSK_CKMR_N(N)	((N)<<16)
+#define LCD_COLORKEYMSK_CKMG_N(N)	((N)<<8)
+#define LCD_COLORKEYMSK_CKMB_N(N)	((N)<<0)
+
+/* lcd windows control 0 */
+#define LCD_WINCTRL0_OX		(0x07FF<<21)
+#define LCD_WINCTRL0_OY		(0x07FF<<10)
+#define LCD_WINCTRL0_A		(0x00FF<<2)
+#define LCD_WINCTRL0_AEN	(1<<1)
+#define LCD_WINCTRL0_OX_N(N) ((N)<<21)
+#define LCD_WINCTRL0_OY_N(N) ((N)<<10)
+#define LCD_WINCTRL0_A_N(N) ((N)<<2)
+
+/* lcd windows control 1 */
+#define LCD_WINCTRL1_PRI	(3<<30)
+#define LCD_WINCTRL1_PIPE	(1<<29)
+#define LCD_WINCTRL1_FRM	(0xF<<25)
+#define LCD_WINCTRL1_CCO	(1<<24)
+#define LCD_WINCTRL1_PO		(3<<22)
+#define LCD_WINCTRL1_SZX	(0x07FF<<11)
+#define LCD_WINCTRL1_SZY	(0x07FF<<0)
+#define LCD_WINCTRL1_FRM_1BPP	(0<<25)
+#define LCD_WINCTRL1_FRM_2BPP	(1<<25)
+#define LCD_WINCTRL1_FRM_4BPP	(2<<25)
+#define LCD_WINCTRL1_FRM_8BPP	(3<<25)
+#define LCD_WINCTRL1_FRM_12BPP	(4<<25)
+#define LCD_WINCTRL1_FRM_16BPP655	(5<<25)
+#define LCD_WINCTRL1_FRM_16BPP565	(6<<25)
+#define LCD_WINCTRL1_FRM_16BPP556	(7<<25)
+#define LCD_WINCTRL1_FRM_16BPPI1555	(8<<25)
+#define LCD_WINCTRL1_FRM_16BPPI5551	(9<<25)
+#define LCD_WINCTRL1_FRM_16BPPA1555	(10<<25)
+#define LCD_WINCTRL1_FRM_16BPPA5551	(11<<25)
+#define LCD_WINCTRL1_FRM_24BPP		(12<<25)
+#define LCD_WINCTRL1_FRM_32BPP		(13<<25)
+#define LCD_WINCTRL1_PRI_N(N)	((N)<<30)
+#define LCD_WINCTRL1_PO_00		(0<<22)
+#define LCD_WINCTRL1_PO_01		(1<<22)
+#define LCD_WINCTRL1_PO_10		(2<<22)
+#define LCD_WINCTRL1_PO_11		(3<<22)
+#define LCD_WINCTRL1_SZX_N(N)	((N-1)<<11)
+#define LCD_WINCTRL1_SZY_N(N)	((N-1)<<0)
+
+/* lcd windows control 2 */
+#define LCD_WINCTRL2_CKMODE		(3<<24)
+#define LCD_WINCTRL2_DBM		(1<<23)
+#define LCD_WINCTRL2_RAM		(3<<21)
+#define LCD_WINCTRL2_BX			(0x1FFF<<8)
+#define LCD_WINCTRL2_SCX		(0xF<<4)
+#define LCD_WINCTRL2_SCY		(0xF<<0)
+#define LCD_WINCTRL2_CKMODE_00		(0<<24)
+#define LCD_WINCTRL2_CKMODE_01		(1<<24)
+#define LCD_WINCTRL2_CKMODE_10		(2<<24)
+#define LCD_WINCTRL2_CKMODE_11		(3<<24)
+#define LCD_WINCTRL2_RAM_NONE		(0<<21)
+#define LCD_WINCTRL2_RAM_PALETTE	(1<<21)
+#define LCD_WINCTRL2_RAM_GAMMA		(2<<21)
+#define LCD_WINCTRL2_RAM_BUFFER		(3<<21)
+#define LCD_WINCTRL2_BX_N(N)	((N)<<8)
+#define LCD_WINCTRL2_SCX_1		(0<<4)
+#define LCD_WINCTRL2_SCX_2		(1<<4)
+#define LCD_WINCTRL2_SCX_4		(2<<4)
+#define LCD_WINCTRL2_SCY_1		(0<<0)
+#define LCD_WINCTRL2_SCY_2		(1<<0)
+#define LCD_WINCTRL2_SCY_4		(2<<0)
+
+/* lcd windows buffer control */
+#define LCD_WINBUFCTRL_DB		(1<<1)
+#define LCD_WINBUFCTRL_DBN		(1<<0)
+
+/* lcd_intstatus, lcd_intenable */
+#define LCD_INT_IFO				(0xF<<14)
+#define LCD_INT_IFU				(0xF<<10)
+#define LCD_INT_OFO				(1<<9)
+#define LCD_INT_OFU				(1<<8)
+#define LCD_INT_WAIT			(1<<3)
+#define LCD_INT_SD				(1<<2)
+#define LCD_INT_SA				(1<<1)
+#define LCD_INT_SS				(1<<0)
+
+/* lcd_horztiming */
+#define LCD_HORZTIMING_HND2		(0x1FF<<18)
+#define LCD_HORZTIMING_HND1		(0x1FF<<9)
+#define LCD_HORZTIMING_HPW		(0x1FF<<0)
+#define LCD_HORZTIMING_HND2_N(N)(((N)-1)<<18)
+#define LCD_HORZTIMING_HND1_N(N)(((N)-1)<<9)
+#define LCD_HORZTIMING_HPW_N(N)	(((N)-1)<<0)
+
+/* lcd_verttiming */
+#define LCD_VERTTIMING_VND2		(0x1FF<<18)
+#define LCD_VERTTIMING_VND1		(0x1FF<<9)
+#define LCD_VERTTIMING_VPW		(0x1FF<<0)
+#define LCD_VERTTIMING_VND2_N(N)(((N)-1)<<18)
+#define LCD_VERTTIMING_VND1_N(N)(((N)-1)<<9)
+#define LCD_VERTTIMING_VPW_N(N)	(((N)-1)<<0)
+
+/* lcd_clkcontrol */
+#define LCD_CLKCONTROL_EXT		(1<<22)
+#define LCD_CLKCONTROL_DELAY	(3<<20)
+#define LCD_CLKCONTROL_CDD		(1<<19)
+#define LCD_CLKCONTROL_IB		(1<<18)
+#define LCD_CLKCONTROL_IC		(1<<17)
+#define LCD_CLKCONTROL_IH		(1<<16)
+#define LCD_CLKCONTROL_IV		(1<<15)
+#define LCD_CLKCONTROL_BF		(0x1F<<10)
+#define LCD_CLKCONTROL_PCD		(0x3FF<<0)
+#define LCD_CLKCONTROL_BF_N(N)	(((N)-1)<<10)
+#define LCD_CLKCONTROL_PCD_N(N)	((N)<<0)
+
+/* lcd_pwmdiv */
+#define LCD_PWMDIV_EN			(1<<31)
+#define LCD_PWMDIV_PWMDIV		(0x1FFFF<<0)
+#define LCD_PWMDIV_PWMDIV_N(N)	((N)<<0)
+
+/* lcd_pwmhi */
+#define LCD_PWMHI_PWMHI1		(0xFFFF<<16)
+#define LCD_PWMHI_PWMHI0		(0xFFFF<<0)
+#define LCD_PWMHI_PWMHI1_N(N)	((N)<<16)
+#define LCD_PWMHI_PWMHI0_N(N)	((N)<<0)
+
+/* lcd_hwccon */
+#define LCD_HWCCON_EN			(1<<0)
+
+/* lcd_cursorpos */
+#define LCD_CURSORPOS_HWCXOFF		(0x1F<<27)
+#define LCD_CURSORPOS_HWCXPOS		(0x07FF<<16)
+#define LCD_CURSORPOS_HWCYOFF		(0x1F<<11)
+#define LCD_CURSORPOS_HWCYPOS		(0x07FF<<0)
+#define LCD_CURSORPOS_HWCXOFF_N(N)	((N)<<27)
+#define LCD_CURSORPOS_HWCXPOS_N(N)	((N)<<16)
+#define LCD_CURSORPOS_HWCYOFF_N(N)	((N)<<11)
+#define LCD_CURSORPOS_HWCYPOS_N(N)	((N)<<0)
+
+/* lcd_cursorcolor */
+#define LCD_CURSORCOLOR_HWCA		(0xFF<<24)
+#define LCD_CURSORCOLOR_HWCR		(0xFF<<16)
+#define LCD_CURSORCOLOR_HWCG		(0xFF<<8)
+#define LCD_CURSORCOLOR_HWCB		(0xFF<<0)
+#define LCD_CURSORCOLOR_HWCA_N(N)	((N)<<24)
+#define LCD_CURSORCOLOR_HWCR_N(N)	((N)<<16)
+#define LCD_CURSORCOLOR_HWCG_N(N)	((N)<<8)
+#define LCD_CURSORCOLOR_HWCB_N(N)	((N)<<0)
+
+/* lcd_fifoctrl */
+#define LCD_FIFOCTRL_F3IF		(1<<29)
+#define LCD_FIFOCTRL_F3REQ		(0x1F<<24)
+#define LCD_FIFOCTRL_F2IF		(1<<29)
+#define LCD_FIFOCTRL_F2REQ		(0x1F<<16)
+#define LCD_FIFOCTRL_F1IF		(1<<29)
+#define LCD_FIFOCTRL_F1REQ		(0x1F<<8)
+#define LCD_FIFOCTRL_F0IF		(1<<29)
+#define LCD_FIFOCTRL_F0REQ		(0x1F<<0)
+#define LCD_FIFOCTRL_F3REQ_N(N)	((N-1)<<24)
+#define LCD_FIFOCTRL_F2REQ_N(N)	((N-1)<<16)
+#define LCD_FIFOCTRL_F1REQ_N(N)	((N-1)<<8)
+#define LCD_FIFOCTRL_F0REQ_N(N)	((N-1)<<0)
+
+/* lcd_outmask */
+#define LCD_OUTMASK_MASK		(0x00FFFFFF)
+
+/********************************************************************/
+#endif /* _AU1200LCD_H */
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 9d996f2..b895eaa 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -43,11 +43,11 @@
 	default y
 
 config BACKLIGHT_CORGI
-	tristate "Sharp Corgi Backlight Driver (SL-C7xx Series)"
+	tristate "Sharp Corgi Backlight Driver (SL Series)"
 	depends on BACKLIGHT_DEVICE && PXA_SHARPSL
 	default y
 	help
-	  If you have a Sharp Zaurus SL-C7xx, say y to enable the
+	  If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the
 	  backlight driver.
 
 config BACKLIGHT_HP680
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 151fda8..334b1db 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -16,14 +16,12 @@
 
 static ssize_t backlight_show_power(struct class_device *cdev, char *buf)
 {
-	int rc;
+	int rc = -ENXIO;
 	struct backlight_device *bd = to_backlight_device(cdev);
 
 	down(&bd->sem);
-	if (likely(bd->props && bd->props->get_power))
-		rc = sprintf(buf, "%d\n", bd->props->get_power(bd));
-	else
-		rc = -ENXIO;
+	if (likely(bd->props))
+		rc = sprintf(buf, "%d\n", bd->props->power);
 	up(&bd->sem);
 
 	return rc;
@@ -31,7 +29,7 @@
 
 static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count)
 {
-	int rc, power;
+	int rc = -ENXIO, power;
 	char *endp;
 	struct backlight_device *bd = to_backlight_device(cdev);
 
@@ -40,12 +38,13 @@
 		return -EINVAL;
 
 	down(&bd->sem);
-	if (likely(bd->props && bd->props->set_power)) {
+	if (likely(bd->props)) {
 		pr_debug("backlight: set power to %d\n", power);
-		bd->props->set_power(bd, power);
+		bd->props->power = power;
+		if (likely(bd->props->update_status))
+			bd->props->update_status(bd);
 		rc = count;
-	} else
-		rc = -ENXIO;
+	}
 	up(&bd->sem);
 
 	return rc;
@@ -53,14 +52,12 @@
 
 static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf)
 {
-	int rc;
+	int rc = -ENXIO;
 	struct backlight_device *bd = to_backlight_device(cdev);
 
 	down(&bd->sem);
-	if (likely(bd->props && bd->props->get_brightness))
-		rc = sprintf(buf, "%d\n", bd->props->get_brightness(bd));
-	else
-		rc = -ENXIO;
+	if (likely(bd->props))
+		rc = sprintf(buf, "%d\n", bd->props->brightness);
 	up(&bd->sem);
 
 	return rc;
@@ -68,7 +65,7 @@
 
 static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count)
 {
-	int rc, brightness;
+	int rc = -ENXIO, brightness;
 	char *endp;
 	struct backlight_device *bd = to_backlight_device(cdev);
 
@@ -77,12 +74,18 @@
 		return -EINVAL;
 
 	down(&bd->sem);
-	if (likely(bd->props && bd->props->set_brightness)) {
-		pr_debug("backlight: set brightness to %d\n", brightness);
-		bd->props->set_brightness(bd, brightness);
-		rc = count;
-	} else
-		rc = -ENXIO;
+	if (likely(bd->props)) {
+		if (brightness > bd->props->max_brightness)
+			rc = -EINVAL;
+		else {
+			pr_debug("backlight: set brightness to %d\n",
+				 brightness);
+			bd->props->brightness = brightness;
+			if (likely(bd->props->update_status))
+				bd->props->update_status(bd);
+			rc = count;
+		}
+	}
 	up(&bd->sem);
 
 	return rc;
@@ -90,14 +93,26 @@
 
 static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf)
 {
-	int rc;
+	int rc = -ENXIO;
 	struct backlight_device *bd = to_backlight_device(cdev);
 
 	down(&bd->sem);
 	if (likely(bd->props))
 		rc = sprintf(buf, "%d\n", bd->props->max_brightness);
-	else
-		rc = -ENXIO;
+	up(&bd->sem);
+
+	return rc;
+}
+
+static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
+						char *buf)
+{
+	int rc = -ENXIO;
+	struct backlight_device *bd = to_backlight_device(cdev);
+
+	down(&bd->sem);
+	if (likely(bd->props && bd->props->get_brightness))
+		rc = sprintf(buf, "%d\n", bd->props->get_brightness(bd));
 	up(&bd->sem);
 
 	return rc;
@@ -123,7 +138,10 @@
 
 static 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, backlight_store_brightness),
+	DECLARE_ATTR(brightness, 0644, backlight_show_brightness,
+		     backlight_store_brightness),
+	DECLARE_ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
+		     NULL),
 	DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
 };
 
@@ -144,8 +162,12 @@
 	bd = container_of(self, struct backlight_device, fb_notif);
 	down(&bd->sem);
 	if (bd->props)
-		if (!bd->props->check_fb || bd->props->check_fb(evdata->info))
-			bd->props->set_power(bd, *(int *)evdata->data);
+		if (!bd->props->check_fb ||
+		    bd->props->check_fb(evdata->info)) {
+			bd->props->fb_blank = *(int *)evdata->data;
+			if (likely(bd->props && bd->props->update_status))
+				bd->props->update_status(bd);
+		}
 	up(&bd->sem);
 	return 0;
 }
@@ -231,6 +253,12 @@
 					 &bl_class_device_attributes[i]);
 
 	down(&bd->sem);
+	if (likely(bd->props && bd->props->update_status)) {
+		bd->props->brightness = 0;
+		bd->props->power = 0;
+		bd->props->update_status(bd);
+	}
+
 	bd->props = NULL;
 	up(&bd->sem);
 
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
index d0aaf45..2ebbfd9 100644
--- a/drivers/video/backlight/corgi_bl.c
+++ b/drivers/video/backlight/corgi_bl.c
@@ -1,7 +1,7 @@
 /*
- *  Backlight Driver for Sharp Corgi
+ *  Backlight Driver for Sharp Zaurus Handhelds (various models)
  *
- *  Copyright (c) 2004-2005 Richard Purdie
+ *  Copyright (c) 2004-2006 Richard Purdie
  *
  *  Based on Sharp's 2.4 Backlight Driver
  *
@@ -15,80 +15,63 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/fb.h>
 #include <linux/backlight.h>
-
 #include <asm/arch/sharpsl.h>
 #include <asm/hardware/sharpsl_pm.h>
 
-#define CORGI_DEFAULT_INTENSITY		0x1f
-#define CORGI_LIMIT_MASK		0x0b
-
-static int corgibl_powermode = FB_BLANK_UNBLANK;
-static int current_intensity = 0;
-static int corgibl_limit = 0;
-static void (*corgibl_mach_set_intensity)(int intensity);
-static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED;
+static int corgibl_intensity;
+static DEFINE_MUTEX(bl_mutex);
 static struct backlight_properties corgibl_data;
+static struct backlight_device *corgi_backlight_device;
+static struct corgibl_machinfo *bl_machinfo;
 
-static void corgibl_send_intensity(int intensity)
+static unsigned long corgibl_flags;
+#define CORGIBL_SUSPENDED     0x01
+#define CORGIBL_BATTLOW       0x02
+
+static int corgibl_send_intensity(struct backlight_device *bd)
 {
-	unsigned long flags;
 	void (*corgi_kick_batt)(void);
+	int intensity = bd->props->brightness;
 
-	if (corgibl_powermode != FB_BLANK_UNBLANK) {
+	if (bd->props->power != FB_BLANK_UNBLANK)
 		intensity = 0;
-	} else {
-		if (corgibl_limit)
-			intensity &= CORGI_LIMIT_MASK;
-	}
+	if (bd->props->fb_blank != FB_BLANK_UNBLANK)
+		intensity = 0;
+	if (corgibl_flags & CORGIBL_SUSPENDED)
+		intensity = 0;
+	if (corgibl_flags & CORGIBL_BATTLOW)
+		intensity &= bl_machinfo->limit_mask;
 
-	spin_lock_irqsave(&bl_lock, flags);
+ 	mutex_lock(&bl_mutex);
+	bl_machinfo->set_bl_intensity(intensity);
+	mutex_unlock(&bl_mutex);
 
-	corgibl_mach_set_intensity(intensity);
-
-	spin_unlock_irqrestore(&bl_lock, flags);
+	corgibl_intensity = intensity;
 
  	corgi_kick_batt = symbol_get(sharpsl_battery_kick);
  	if (corgi_kick_batt) {
  		corgi_kick_batt();
  		symbol_put(sharpsl_battery_kick);
  	}
-}
 
-static void corgibl_blank(int blank)
-{
-	switch(blank) {
-
-	case FB_BLANK_NORMAL:
-	case FB_BLANK_VSYNC_SUSPEND:
-	case FB_BLANK_HSYNC_SUSPEND:
-	case FB_BLANK_POWERDOWN:
-		if (corgibl_powermode == FB_BLANK_UNBLANK) {
-			corgibl_send_intensity(0);
-			corgibl_powermode = blank;
-		}
-		break;
-	case FB_BLANK_UNBLANK:
-		if (corgibl_powermode != FB_BLANK_UNBLANK) {
-			corgibl_powermode = blank;
-			corgibl_send_intensity(current_intensity);
-		}
-		break;
-	}
+	return 0;
 }
 
 #ifdef CONFIG_PM
 static int corgibl_suspend(struct platform_device *dev, pm_message_t state)
 {
-	corgibl_blank(FB_BLANK_POWERDOWN);
+	corgibl_flags |= CORGIBL_SUSPENDED;
+	corgibl_send_intensity(corgi_backlight_device);
 	return 0;
 }
 
 static int corgibl_resume(struct platform_device *dev)
 {
-	corgibl_blank(FB_BLANK_UNBLANK);
+	corgibl_flags &= ~CORGIBL_SUSPENDED;
+	corgibl_send_intensity(corgi_backlight_device);
 	return 0;
 }
 #else
@@ -96,30 +79,15 @@
 #define corgibl_resume	NULL
 #endif
 
-
-static int corgibl_set_power(struct backlight_device *bd, int state)
-{
-	corgibl_blank(state);
-	return 0;
-}
-
-static int corgibl_get_power(struct backlight_device *bd)
-{
-	return corgibl_powermode;
-}
-
-static int corgibl_set_intensity(struct backlight_device *bd, int intensity)
-{
-	if (intensity > corgibl_data.max_brightness)
-		intensity = corgibl_data.max_brightness;
-	corgibl_send_intensity(intensity);
-	current_intensity=intensity;
-	return 0;
-}
-
 static int corgibl_get_intensity(struct backlight_device *bd)
 {
-	return current_intensity;
+	return corgibl_intensity;
+}
+
+static int corgibl_set_intensity(struct backlight_device *bd)
+{
+	corgibl_send_intensity(corgi_backlight_device);
+	return 0;
 }
 
 /*
@@ -128,36 +96,38 @@
  */
 void corgibl_limit_intensity(int limit)
 {
-	corgibl_limit = (limit ? 1 : 0);
-	corgibl_send_intensity(current_intensity);
+	if (limit)
+		corgibl_flags |= CORGIBL_BATTLOW;
+	else
+		corgibl_flags &= ~CORGIBL_BATTLOW;
+	corgibl_send_intensity(corgi_backlight_device);
 }
 EXPORT_SYMBOL(corgibl_limit_intensity);
 
 
 static struct backlight_properties corgibl_data = {
-	.owner		= THIS_MODULE,
-	.get_power      = corgibl_get_power,
-	.set_power      = corgibl_set_power,
+	.owner          = THIS_MODULE,
 	.get_brightness = corgibl_get_intensity,
-	.set_brightness = corgibl_set_intensity,
+	.update_status  = corgibl_set_intensity,
 };
 
-static struct backlight_device *corgi_backlight_device;
-
 static int __init corgibl_probe(struct platform_device *pdev)
 {
 	struct corgibl_machinfo *machinfo = pdev->dev.platform_data;
 
+	bl_machinfo = machinfo;
 	corgibl_data.max_brightness = machinfo->max_intensity;
-	corgibl_mach_set_intensity = machinfo->set_bl_intensity;
+	if (!machinfo->limit_mask)
+		machinfo->limit_mask = -1;
 
 	corgi_backlight_device = backlight_device_register ("corgi-bl",
 		NULL, &corgibl_data);
 	if (IS_ERR (corgi_backlight_device))
 		return PTR_ERR (corgi_backlight_device);
 
-	corgibl_set_intensity(NULL, CORGI_DEFAULT_INTENSITY);
-	corgibl_limit_intensity(0);
+	corgibl_data.power = FB_BLANK_UNBLANK;
+	corgibl_data.brightness = machinfo->default_intensity;
+	corgibl_send_intensity(corgi_backlight_device);
 
 	printk("Corgi Backlight Driver Initialized.\n");
 	return 0;
@@ -167,8 +137,6 @@
 {
 	backlight_device_unregister(corgi_backlight_device);
 
-	corgibl_set_intensity(NULL, 0);
-
 	printk("Corgi Backlight Driver Unloaded\n");
 	return 0;
 }
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index 95da4c9..a71e984 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -13,7 +13,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
 #include <linux/spinlock.h>
 #include <linux/fb.h>
 #include <linux/backlight.h>
@@ -25,66 +25,58 @@
 #define HP680_MAX_INTENSITY 255
 #define HP680_DEFAULT_INTENSITY 10
 
-static int hp680bl_powermode = FB_BLANK_UNBLANK;
+static int hp680bl_suspended;
 static int current_intensity = 0;
 static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED;
+static struct backlight_device *hp680_backlight_device;
 
-static void hp680bl_send_intensity(int intensity)
+static void hp680bl_send_intensity(struct backlight_device *bd)
 {
 	unsigned long flags;
+	u16 v;
+	int intensity = bd->props->brightness;
 
-	if (hp680bl_powermode != FB_BLANK_UNBLANK)
+	if (bd->props->power != FB_BLANK_UNBLANK)
+		intensity = 0;
+	if (bd->props->fb_blank != FB_BLANK_UNBLANK)
+		intensity = 0;
+	if (hp680bl_suspended)
 		intensity = 0;
 
 	spin_lock_irqsave(&bl_lock, flags);
-	sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS);
-	spin_unlock_irqrestore(&bl_lock, flags);
-}
-
-static void hp680bl_blank(int blank)
-{
-	u16 v;
-
-	switch(blank) {
-
-	case FB_BLANK_NORMAL:
-	case FB_BLANK_VSYNC_SUSPEND:
-	case FB_BLANK_HSYNC_SUSPEND:
-	case FB_BLANK_POWERDOWN:
-		if (hp680bl_powermode == FB_BLANK_UNBLANK) {
-			hp680bl_send_intensity(0);
-			hp680bl_powermode = blank;
-			sh_dac_disable(DAC_LCD_BRIGHTNESS);
-			v = inw(HD64461_GPBDR);
-			v |= HD64461_GPBDR_LCDOFF;
-			outw(v, HD64461_GPBDR);
-		}
-		break;
-	case FB_BLANK_UNBLANK:
-		if (hp680bl_powermode != FB_BLANK_UNBLANK) {
-			sh_dac_enable(DAC_LCD_BRIGHTNESS);
-			v = inw(HD64461_GPBDR);
-			v &= ~HD64461_GPBDR_LCDOFF;
-			outw(v, HD64461_GPBDR);
-			hp680bl_powermode = blank;
-			hp680bl_send_intensity(current_intensity);
-		}
-		break;
+	if (intensity && current_intensity == 0) {
+		sh_dac_enable(DAC_LCD_BRIGHTNESS);
+		v = inw(HD64461_GPBDR);
+		v &= ~HD64461_GPBDR_LCDOFF;
+		outw(v, HD64461_GPBDR);
+		sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS);
+	} else if (intensity == 0 && current_intensity != 0) {
+		sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS);
+		sh_dac_disable(DAC_LCD_BRIGHTNESS);
+		v = inw(HD64461_GPBDR);
+		v |= HD64461_GPBDR_LCDOFF;
+		outw(v, HD64461_GPBDR);
+	} else if (intensity) {
+		sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS);
 	}
+	spin_unlock_irqrestore(&bl_lock, flags);
+
+	current_intensity = intensity;
 }
 
+
 #ifdef CONFIG_PM
-static int hp680bl_suspend(struct device *dev, pm_message_t state, u32 level)
+static int hp680bl_suspend(struct platform_device *dev, pm_message_t state)
 {
-	if (level == SUSPEND_POWER_DOWN)
-		hp680bl_blank(FB_BLANK_POWERDOWN);
+	hp680bl_suspended = 1;
+	hp680bl_send_intensity(hp680_backlight_device);
 	return 0;
 }
 
-static int hp680bl_resume(struct device *dev, u32 level)
+static int hp680bl_resume(struct platform_device *dev)
 {
-	if (level == RESUME_POWER_ON)
-		hp680bl_blank(FB_BLANK_UNBLANK);
+	hp680bl_suspended = 0;
+	hp680bl_send_intensity(hp680_backlight_device);
 	return 0;
 }
 #else
@@ -92,24 +84,9 @@
 #define hp680bl_resume	NULL
 #endif
 
-
-static int hp680bl_set_power(struct backlight_device *bd, int state)
+static int hp680bl_set_intensity(struct backlight_device *bd)
 {
-	hp680bl_blank(state);
-	return 0;
-}
-
-static int hp680bl_get_power(struct backlight_device *bd)
-{
-	return hp680bl_powermode;
-}
-
-static int hp680bl_set_intensity(struct backlight_device *bd, int intensity)
-{
-	if (intensity > HP680_MAX_INTENSITY)
-		intensity = HP680_MAX_INTENSITY;
-	hp680bl_send_intensity(intensity);
-	current_intensity = intensity;
+	hp680bl_send_intensity(bd);
 	return 0;
 }
 
@@ -120,65 +97,67 @@
 
 static struct backlight_properties hp680bl_data = {
 	.owner		= THIS_MODULE,
-	.get_power      = hp680bl_get_power,
-	.set_power      = hp680bl_set_power,
 	.max_brightness = HP680_MAX_INTENSITY,
 	.get_brightness = hp680bl_get_intensity,
-	.set_brightness = hp680bl_set_intensity,
+	.update_status  = hp680bl_set_intensity,
 };
 
-static struct backlight_device *hp680_backlight_device;
-
-static int __init hp680bl_probe(struct device *dev)
+static int __init hp680bl_probe(struct platform_device *dev)
 {
 	hp680_backlight_device = backlight_device_register ("hp680-bl",
 		NULL, &hp680bl_data);
 	if (IS_ERR (hp680_backlight_device))
 		return PTR_ERR (hp680_backlight_device);
 
-	hp680bl_set_intensity(NULL, HP680_DEFAULT_INTENSITY);
+	hp680_backlight_device->props->brightness = HP680_DEFAULT_INTENSITY;
+	hp680bl_send_intensity(hp680_backlight_device);
 
 	return 0;
 }
 
-static int hp680bl_remove(struct device *dev)
+static int hp680bl_remove(struct platform_device *dev)
 {
 	backlight_device_unregister(hp680_backlight_device);
 
 	return 0;
 }
 
-static struct device_driver hp680bl_driver = {
-	.name		= "hp680-bl",
-	.bus		= &platform_bus_type,
+static struct platform_driver hp680bl_driver = {
 	.probe		= hp680bl_probe,
 	.remove		= hp680bl_remove,
 	.suspend	= hp680bl_suspend,
 	.resume		= hp680bl_resume,
+	.driver		= {
+		.name	= "hp680-bl",
+	},
 };
 
-static struct platform_device hp680bl_device = {
-	.name	= "hp680-bl",
-	.id	= -1,
-};
+static struct platform_device *hp680bl_device;
 
 static int __init hp680bl_init(void)
 {
 	int ret;
 
-	ret=driver_register(&hp680bl_driver);
+	ret = platform_driver_register(&hp680bl_driver);
 	if (!ret) {
-		ret = platform_device_register(&hp680bl_device);
-		if (ret)
-			driver_unregister(&hp680bl_driver);
+		hp680bl_device = platform_device_alloc("hp680-bl", -1);
+		if (!hp680bl_device)
+			return -ENOMEM;
+
+		ret = platform_device_add(hp680bl_device);
+
+		if (ret) {
+			platform_device_put(hp680bl_device);
+			platform_driver_unregister(&hp680bl_driver);
+		}
 	}
 	return ret;
 }
 
 static void __exit hp680bl_exit(void)
 {
-	platform_device_unregister(&hp680bl_device);
- 	driver_unregister(&hp680bl_driver);
+	platform_device_unregister(hp680bl_device);
+ 	platform_driver_unregister(&hp680bl_driver);
 }
 
 module_init(hp680bl_init);
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
index 910e233..8ba6152 100644
--- a/drivers/video/cfbimgblt.c
+++ b/drivers/video/cfbimgblt.c
@@ -169,7 +169,7 @@
 
 		while (j--) {
 			l--;
-			color = (*s & 1 << (FB_BIT_NR(l))) ? fgcolor : bgcolor;
+			color = (*s & (1 << l)) ? fgcolor : bgcolor;
 			val |= FB_SHIFT_HIGH(color, shift);
 			
 			/* Did the bitshift spill bits to the next long? */
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index bc061d4..72ff6bf 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -178,8 +178,6 @@
 	unsigned char data;
 };
 
-#define N_ELTS(x)	(sizeof(x) / sizeof(x[0]))
-
 static struct chips_init_reg chips_init_sr[] = {
 	{ 0x00, 0x03 },
 	{ 0x01, 0x01 },
@@ -287,18 +285,18 @@
 {
 	int i;
 
-	for (i = 0; i < N_ELTS(chips_init_xr); ++i)
+	for (i = 0; i < ARRAY_SIZE(chips_init_xr); ++i)
 		write_xr(chips_init_xr[i].addr, chips_init_xr[i].data);
 	outb(0x29, 0x3c2); /* set misc output reg */
-	for (i = 0; i < N_ELTS(chips_init_sr); ++i)
+	for (i = 0; i < ARRAY_SIZE(chips_init_sr); ++i)
 		write_sr(chips_init_sr[i].addr, chips_init_sr[i].data);
-	for (i = 0; i < N_ELTS(chips_init_gr); ++i)
+	for (i = 0; i < ARRAY_SIZE(chips_init_gr); ++i)
 		write_gr(chips_init_gr[i].addr, chips_init_gr[i].data);
-	for (i = 0; i < N_ELTS(chips_init_ar); ++i)
+	for (i = 0; i < ARRAY_SIZE(chips_init_ar); ++i)
 		write_ar(chips_init_ar[i].addr, chips_init_ar[i].data);
-	for (i = 0; i < N_ELTS(chips_init_cr); ++i)
+	for (i = 0; i < ARRAY_SIZE(chips_init_cr); ++i)
 		write_cr(chips_init_cr[i].addr, chips_init_cr[i].data);
-	for (i = 0; i < N_ELTS(chips_init_fr); ++i)
+	for (i = 0; i < ARRAY_SIZE(chips_init_fr); ++i)
 		write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
 }
 
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index 66d6f2f..1103010 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -60,8 +60,8 @@
 #include <asm/amigahw.h>
 #endif
 #ifdef CONFIG_PPC_PREP
-#include <asm/processor.h>
-#define isPReP (_machine == _MACH_prep)
+#include <asm/machdep.h>
+#define isPReP (machine_is(prep))
 #else
 #define isPReP 0
 #endif
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 6ee4498..4444bef 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -26,6 +26,30 @@
 #	   fi
 #	fi
 
+config VGACON_SOFT_SCROLLBACK
+       bool "Enable Scrollback Buffer in System RAM"
+       depends on VGA_CONSOLE
+       default n
+       help
+         The scrollback buffer of the standard VGA console is located in
+	 the VGA RAM.  The size of this RAM is fixed and is quite small.
+	 If you require a larger scrollback buffer, this can be placed in
+	 System RAM which is dynamically allocated during intialization.
+	 Placing the scrollback buffer in System RAM will slightly slow
+	 down the console.
+
+	 If you want this feature, say 'Y' here and enter the amount of
+	 RAM to allocate for this buffer.  If unsure, say 'N'.
+
+config VGACON_SOFT_SCROLLBACK_SIZE
+       int "Scrollback Buffer Size (in KB)"
+       depends on VGACON_SOFT_SCROLLBACK
+       default "64"
+       help
+         Enter the amount of System RAM to allocate for the scrollback
+	 buffer.  Each 64KB will give you approximately 16 80x25
+	 screenfuls of scrollback buffer
+
 config VIDEO_SELECT
 	bool "Video mode selection support"
 	depends on  X86 && VGA_CONSOLE
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 041d069..ca020719 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -466,7 +466,7 @@
 	int i, j;
 
 	if (!this_opt || !*this_opt)
-		return 0;
+		return 1;
 
 	while ((options = strsep(&this_opt, ",")) != NULL) {
 		if (!strncmp(options, "font:", 5))
@@ -481,10 +481,10 @@
 					options++;
 				}
 				if (*options != ',')
-					return 0;
+					return 1;
 				options++;
 			} else
-				return 0;
+				return 1;
 		}
 		
 		if (!strncmp(options, "map:", 4)) {
@@ -496,7 +496,7 @@
 					con2fb_map_boot[i] =
 						(options[j++]-'0') % FB_MAX;
 				}
-			return 0;
+			return 1;
 		}
 
 		if (!strncmp(options, "vc:", 3)) {
@@ -518,7 +518,7 @@
 				rotate = 0;
 		}
 	}
-	return 0;
+	return 1;
 }
 
 __setup("fbcon=", fb_console_setup);
@@ -1142,6 +1142,7 @@
 		set_blitting_type(vc, info);
 	}
 
+	ops->p = &fb_display[fg_console];
 }
 
 static void fbcon_deinit(struct vc_data *vc)
diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c
index 4fd07d9..0cc1bfd 100644
--- a/drivers/video/console/fonts.c
+++ b/drivers/video/console/fonts.c
@@ -66,7 +66,7 @@
 #endif
 };
 
-#define num_fonts (sizeof(fonts)/sizeof(*fonts))
+#define num_fonts ARRAY_SIZE(fonts)
 
 #ifdef NO_FONTS
 #error No fonts configured.
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index 762c7a5..e99fe30 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -149,7 +149,7 @@
 	newport_clear_screen(0, ystart, 1280 + 63, yend, ci);
 }
 
-void newport_reset(void)
+static void newport_reset(void)
 {
 	unsigned short treg;
 	int i;
@@ -193,7 +193,7 @@
  * calculate the actual screen size by reading
  * the video timing out of the VC2
  */
-void newport_get_screensize(void)
+static void newport_get_screensize(void)
 {
 	int i, cols;
 	unsigned short ventry, treg;
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c
index 0339f56..74ac2ac 100644
--- a/drivers/video/console/sticore.c
+++ b/drivers/video/console/sticore.c
@@ -275,7 +275,7 @@
 	if (str)
 		strlcpy (default_sti_path, str, sizeof (default_sti_path));
 	
-	return 0;
+	return 1;
 }
 
 /*	Assuming the machine has multiple STI consoles (=graphic cards) which
@@ -321,7 +321,7 @@
 		i++;
 	}
 
-	return 0;
+	return 1;
 }
 
 /*	The optional linux kernel parameter "sti_font" defines which font
@@ -373,7 +373,7 @@
 		glob_cfg->save_addr));
 
 	/* dump extended cfg */ 
-	cfg = PTR_STI(glob_cfg->ext_ptr);
+	cfg = PTR_STI((unsigned long)glob_cfg->ext_ptr);
 	DPRINTK(( KERN_INFO
 		"monitor %d\n"
 		"in friendly mode: %d\n"
@@ -453,25 +453,11 @@
 		sti->regions_phys[i] =
 			REGION_OFFSET_TO_PHYS(sti->regions[i], newhpa);
 		
-		/* remap virtually */
-		/* FIXME: add BTLB support if btlb==1 */
 		len = sti->regions[i].region_desc.length * 4096;
-
-/* XXX: Enabling IOREMAP debugging causes a crash, so we must be passing
- * a virtual address to something expecting a physical address that doesn't
- * go through a readX macro */
-#if 0
-		if (len)
-		   glob_cfg->region_ptrs[i] = (unsigned long) (
-			sti->regions[i].region_desc.cache ?
-			ioremap(sti->regions_phys[i], len) :
-			ioremap_nocache(sti->regions_phys[i], len) );
-#else
 		if (len)
 			glob_cfg->region_ptrs[i] = sti->regions_phys[i];
-#endif
 		
-		DPRINTK(("region #%d: phys %08lx, virt %08x, len=%lukB, "
+		DPRINTK(("region #%d: phys %08lx, region_ptr %08x, len=%lukB, "
 			 "btlb=%d, sysonly=%d, cache=%d, last=%d\n",
 			i, sti->regions_phys[i], glob_cfg->region_ptrs[i],
 			len/1024,
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index 5a86978..d5a04b6 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -93,7 +93,6 @@
 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
 static unsigned long vgacon_uni_pagedir[2];
 
-
 /* Description of the hardware situation */
 static unsigned long	vga_vram_base;		/* Base of video memory */
 static unsigned long	vga_vram_end;		/* End of video memory */
@@ -161,6 +160,201 @@
 	spin_unlock_irqrestore(&vga_lock, flags);
 }
 
+static inline void vga_set_mem_top(struct vc_data *c)
+{
+	write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
+}
+
+#ifdef CONFIG_VGACON_SOFT_SCROLLBACK
+#include <linux/bootmem.h>
+/* software scrollback */
+static void *vgacon_scrollback;
+static int vgacon_scrollback_tail;
+static int vgacon_scrollback_size;
+static int vgacon_scrollback_rows;
+static int vgacon_scrollback_cnt;
+static int vgacon_scrollback_cur;
+static int vgacon_scrollback_save;
+static int vgacon_scrollback_restore;
+
+static void vgacon_scrollback_init(int pitch)
+{
+	int rows = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024/pitch;
+
+	if (vgacon_scrollback) {
+		vgacon_scrollback_cnt  = 0;
+		vgacon_scrollback_tail = 0;
+		vgacon_scrollback_cur  = 0;
+		vgacon_scrollback_rows = rows - 1;
+		vgacon_scrollback_size = rows * pitch;
+	}
+}
+
+static void __init vgacon_scrollback_startup(void)
+{
+	vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE
+					  * 1024);
+	vgacon_scrollback_init(vga_video_num_columns * 2);
+}
+
+static void vgacon_scrollback_update(struct vc_data *c, int t, int count)
+{
+	void *p;
+
+	if (!vgacon_scrollback_size || c->vc_num != fg_console)
+		return;
+
+	p = (void *) (c->vc_origin + t * c->vc_size_row);
+
+	while (count--) {
+		scr_memcpyw(vgacon_scrollback + vgacon_scrollback_tail,
+			    p, c->vc_size_row);
+		vgacon_scrollback_cnt++;
+		p += c->vc_size_row;
+		vgacon_scrollback_tail += c->vc_size_row;
+
+		if (vgacon_scrollback_tail >= vgacon_scrollback_size)
+			vgacon_scrollback_tail = 0;
+
+		if (vgacon_scrollback_cnt > vgacon_scrollback_rows)
+			vgacon_scrollback_cnt = vgacon_scrollback_rows;
+
+		vgacon_scrollback_cur = vgacon_scrollback_cnt;
+	}
+}
+
+static void vgacon_restore_screen(struct vc_data *c)
+{
+	vgacon_scrollback_save = 0;
+
+	if (!vga_is_gfx && !vgacon_scrollback_restore) {
+		scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
+			    c->vc_screenbuf_size > vga_vram_size ?
+			    vga_vram_size : c->vc_screenbuf_size);
+		vgacon_scrollback_restore = 1;
+		vgacon_scrollback_cur = vgacon_scrollback_cnt;
+	}
+}
+
+static int vgacon_scrolldelta(struct vc_data *c, int lines)
+{
+	int start, end, count, soff, diff;
+	void *d, *s;
+
+	if (!lines) {
+		c->vc_visible_origin = c->vc_origin;
+		vga_set_mem_top(c);
+		return 1;
+	}
+
+	if (!vgacon_scrollback)
+		return 1;
+
+	if (!vgacon_scrollback_save) {
+		vgacon_cursor(c, CM_ERASE);
+		vgacon_save_screen(c);
+		vgacon_scrollback_save = 1;
+	}
+
+	vgacon_scrollback_restore = 0;
+	start = vgacon_scrollback_cur + lines;
+	end = start + abs(lines);
+
+	if (start < 0)
+		start = 0;
+
+	if (start > vgacon_scrollback_cnt)
+		start = vgacon_scrollback_cnt;
+
+	if (end < 0)
+		end = 0;
+
+	if (end > vgacon_scrollback_cnt)
+		end = vgacon_scrollback_cnt;
+
+	vgacon_scrollback_cur = start;
+	count = end - start;
+	soff = vgacon_scrollback_tail - ((vgacon_scrollback_cnt - end) *
+					 c->vc_size_row);
+	soff -= count * c->vc_size_row;
+
+	if (soff < 0)
+		soff += vgacon_scrollback_size;
+
+	count = vgacon_scrollback_cnt - start;
+
+	if (count > c->vc_rows)
+		count = c->vc_rows;
+
+	diff = c->vc_rows - count;
+
+	d = (void *) c->vc_origin;
+	s = (void *) c->vc_screenbuf;
+
+	while (count--) {
+		scr_memcpyw(d, vgacon_scrollback + soff, c->vc_size_row);
+		d += c->vc_size_row;
+		soff += c->vc_size_row;
+
+		if (soff >= vgacon_scrollback_size)
+			soff = 0;
+	}
+
+	if (diff == c->vc_rows) {
+		vgacon_cursor(c, CM_MOVE);
+	} else {
+		while (diff--) {
+			scr_memcpyw(d, s, c->vc_size_row);
+			d += c->vc_size_row;
+			s += c->vc_size_row;
+		}
+	}
+
+	return 1;
+}
+#else
+#define vgacon_scrollback_startup(...) do { } while (0)
+#define vgacon_scrollback_init(...)    do { } while (0)
+#define vgacon_scrollback_update(...)  do { } while (0)
+
+static void vgacon_restore_screen(struct vc_data *c)
+{
+	if (c->vc_origin != c->vc_visible_origin)
+		vgacon_scrolldelta(c, 0);
+}
+
+static int vgacon_scrolldelta(struct vc_data *c, int lines)
+{
+	if (!lines)		/* Turn scrollback off */
+		c->vc_visible_origin = c->vc_origin;
+	else {
+		int margin = c->vc_size_row * 4;
+		int ul, we, p, st;
+
+		if (vga_rolled_over >
+		    (c->vc_scr_end - vga_vram_base) + margin) {
+			ul = c->vc_scr_end - vga_vram_base;
+			we = vga_rolled_over + c->vc_size_row;
+		} else {
+			ul = 0;
+			we = vga_vram_size;
+		}
+		p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
+		    lines * c->vc_size_row;
+		st = (c->vc_origin - vga_vram_base - ul + we) % we;
+		if (st < 2 * margin)
+			margin = 0;
+		if (p < margin)
+			p = 0;
+		if (p > st - margin)
+			p = st;
+		c->vc_visible_origin = vga_vram_base + (p + ul) % we;
+	}
+	vga_set_mem_top(c);
+	return 1;
+}
+#endif /* CONFIG_VGACON_SOFT_SCROLLBACK */
+
 static const char __init *vgacon_startup(void)
 {
 	const char *display_desc = NULL;
@@ -330,7 +524,7 @@
 
 	vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH;
 	vgacon_yres = vga_scan_lines;
-
+	vgacon_scrollback_startup();
 	return display_desc;
 }
 
@@ -357,11 +551,6 @@
 		con_set_default_unimap(c);
 }
 
-static inline void vga_set_mem_top(struct vc_data *c)
-{
-	write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
-}
-
 static void vgacon_deinit(struct vc_data *c)
 {
 	/* When closing the last console, reset video origin */
@@ -433,29 +622,37 @@
 	cursor_size_lastto = to;
 
 	spin_lock_irqsave(&vga_lock, flags);
-	outb_p(0x0a, vga_video_port_reg);	/* Cursor start */
-	curs = inb_p(vga_video_port_val);
-	outb_p(0x0b, vga_video_port_reg);	/* Cursor end */
-	cure = inb_p(vga_video_port_val);
+	if (vga_video_type >= VIDEO_TYPE_VGAC) {
+		outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
+		curs = inb_p(vga_video_port_val);
+		outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
+		cure = inb_p(vga_video_port_val);
+	} else {
+		curs = 0;
+		cure = 0;
+	}
 
 	curs = (curs & 0xc0) | from;
 	cure = (cure & 0xe0) | to;
 
-	outb_p(0x0a, vga_video_port_reg);	/* Cursor start */
+	outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
 	outb_p(curs, vga_video_port_val);
-	outb_p(0x0b, vga_video_port_reg);	/* Cursor end */
+	outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
 	outb_p(cure, vga_video_port_val);
 	spin_unlock_irqrestore(&vga_lock, flags);
 }
 
 static void vgacon_cursor(struct vc_data *c, int mode)
 {
-	if (c->vc_origin != c->vc_visible_origin)
-		vgacon_scrolldelta(c, 0);
+	vgacon_restore_screen(c);
+
 	switch (mode) {
 	case CM_ERASE:
 		write_vga(14, (c->vc_pos - vga_vram_base) / 2);
-		vgacon_set_cursor_size(c->vc_x, 31, 30);
+	        if (vga_video_type >= VIDEO_TYPE_VGAC)
+			vgacon_set_cursor_size(c->vc_x, 31, 30);
+		else
+			vgacon_set_cursor_size(c->vc_x, 31, 31);
 		break;
 
 	case CM_MOVE:
@@ -493,7 +690,10 @@
 						10 ? 1 : 2));
 			break;
 		case CUR_NONE:
-			vgacon_set_cursor_size(c->vc_x, 31, 30);
+			if (vga_video_type >= VIDEO_TYPE_VGAC)
+				vgacon_set_cursor_size(c->vc_x, 31, 30);
+			else
+				vgacon_set_cursor_size(c->vc_x, 31, 31);
 			break;
 		default:
 			vgacon_set_cursor_size(c->vc_x, 1,
@@ -595,6 +795,7 @@
 			vgacon_doresize(c, c->vc_cols, c->vc_rows);
 	}
 
+	vgacon_scrollback_init(c->vc_size_row);
 	return 0;		/* Redrawing not needed */
 }
 
@@ -1062,37 +1263,6 @@
 	return 0;
 }
 
-static int vgacon_scrolldelta(struct vc_data *c, int lines)
-{
-	if (!lines)		/* Turn scrollback off */
-		c->vc_visible_origin = c->vc_origin;
-	else {
-		int margin = c->vc_size_row * 4;
-		int ul, we, p, st;
-
-		if (vga_rolled_over >
-		    (c->vc_scr_end - vga_vram_base) + margin) {
-			ul = c->vc_scr_end - vga_vram_base;
-			we = vga_rolled_over + c->vc_size_row;
-		} else {
-			ul = 0;
-			we = vga_vram_size;
-		}
-		p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
-		    lines * c->vc_size_row;
-		st = (c->vc_origin - vga_vram_base - ul + we) % we;
-		if (st < 2 * margin)
-			margin = 0;
-		if (p < margin)
-			p = 0;
-		if (p > st - margin)
-			p = st;
-		c->vc_visible_origin = vga_vram_base + (p + ul) % we;
-	}
-	vga_set_mem_top(c);
-	return 1;
-}
-
 static int vgacon_set_origin(struct vc_data *c)
 {
 	if (vga_is_gfx ||	/* We don't play origin tricks in graphic modes */
@@ -1135,15 +1305,14 @@
 	if (t || b != c->vc_rows || vga_is_gfx)
 		return 0;
 
-	if (c->vc_origin != c->vc_visible_origin)
-		vgacon_scrolldelta(c, 0);
-
 	if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
 		return 0;
 
+	vgacon_restore_screen(c);
 	oldo = c->vc_origin;
 	delta = lines * c->vc_size_row;
 	if (dir == SM_UP) {
+		vgacon_scrollback_update(c, t, lines);
 		if (c->vc_scr_end + delta >= vga_vram_end) {
 			scr_memcpyw((u16 *) vga_vram_base,
 				    (u16 *) (oldo + delta),
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
index c32a2a5..1f98392 100644
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -85,7 +85,7 @@
  *	Allocates memory for a colormap @cmap.  @len is the
  *	number of entries in the palette.
  *
- *	Returns -1 errno on error, or zero on success.
+ *	Returns negative errno on error, or zero on success.
  *
  */
 
@@ -116,7 +116,7 @@
 
 fail:
     fb_dealloc_cmap(cmap);
-    return -1;
+    return -ENOMEM;
 }
 
 /**
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 07d882b..944855b 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -55,7 +55,7 @@
 
 #define FBPIXMAPSIZE	(1024 * 8)
 
-static struct notifier_block *fb_notifier_list;
+static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);
 struct fb_info *registered_fb[FB_MAX];
 int num_registered_fb;
 
@@ -784,7 +784,7 @@
 
 		    event.info = info;
 		    event.data = &mode1;
-		    ret = notifier_call_chain(&fb_notifier_list,
+		    ret = blocking_notifier_call_chain(&fb_notifier_list,
 					      FB_EVENT_MODE_DELETE, &event);
 		}
 
@@ -830,8 +830,8 @@
 
 				info->flags &= ~FBINFO_MISC_USEREVENT;
 				event.info = info;
-				notifier_call_chain(&fb_notifier_list, evnt,
-						    &event);
+				blocking_notifier_call_chain(&fb_notifier_list,
+						evnt, &event);
 			}
 		}
 	}
@@ -854,7 +854,8 @@
 
 		event.info = info;
 		event.data = &blank;
-		notifier_call_chain(&fb_notifier_list, FB_EVENT_BLANK, &event);
+		blocking_notifier_call_chain(&fb_notifier_list,
+				FB_EVENT_BLANK, &event);
 	}
 
  	return ret;
@@ -925,7 +926,7 @@
 		con2fb.framebuffer = -1;
 		event.info = info;
 		event.data = &con2fb;
-		notifier_call_chain(&fb_notifier_list,
+		blocking_notifier_call_chain(&fb_notifier_list,
 				    FB_EVENT_GET_CONSOLE_MAP, &event);
 		return copy_to_user(argp, &con2fb,
 				    sizeof(con2fb)) ? -EFAULT : 0;
@@ -944,7 +945,7 @@
 		    return -EINVAL;
 		event.info = info;
 		event.data = &con2fb;
-		return notifier_call_chain(&fb_notifier_list,
+		return blocking_notifier_call_chain(&fb_notifier_list,
 					   FB_EVENT_SET_CONSOLE_MAP,
 					   &event);
 	case FBIOBLANK:
@@ -1324,7 +1325,7 @@
 	devfs_mk_cdev(MKDEV(FB_MAJOR, i),
 			S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i);
 	event.info = fb_info;
-	notifier_call_chain(&fb_notifier_list,
+	blocking_notifier_call_chain(&fb_notifier_list,
 			    FB_EVENT_FB_REGISTERED, &event);
 	return 0;
 }
@@ -1366,7 +1367,7 @@
  */
 int fb_register_client(struct notifier_block *nb)
 {
-	return notifier_chain_register(&fb_notifier_list, nb);
+	return blocking_notifier_chain_register(&fb_notifier_list, nb);
 }
 
 /**
@@ -1375,7 +1376,7 @@
  */
 int fb_unregister_client(struct notifier_block *nb)
 {
-	return notifier_chain_unregister(&fb_notifier_list, nb);
+	return blocking_notifier_chain_unregister(&fb_notifier_list, nb);
 }
 
 /**
@@ -1393,11 +1394,13 @@
 
 	event.info = info;
 	if (state) {
-		notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, &event);
+		blocking_notifier_call_chain(&fb_notifier_list,
+				FB_EVENT_SUSPEND, &event);
 		info->state = FBINFO_STATE_SUSPENDED;
 	} else {
 		info->state = FBINFO_STATE_RUNNING;
-		notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, &event);
+		blocking_notifier_call_chain(&fb_notifier_list,
+				FB_EVENT_RESUME, &event);
 	}
 }
 
@@ -1469,7 +1472,7 @@
 
 	if (!list_empty(&info->modelist)) {
 		event.info = info;
-		err = notifier_call_chain(&fb_notifier_list,
+		err = blocking_notifier_call_chain(&fb_notifier_list,
 					   FB_EVENT_NEW_MODELIST,
 					   &event);
 	}
@@ -1495,7 +1498,7 @@
 	evnt.info = info;
 	evnt.data = data;
 
-	return notifier_call_chain(&fb_notifier_list, event, &evnt);
+	return blocking_notifier_call_chain(&fb_notifier_list, event, &evnt);
 }
 EXPORT_SYMBOL(fb_con_duit);
 
@@ -1585,7 +1588,7 @@
 		}
 	}
 
-	return 0;
+	return 1;
 }
 __setup("video=", video_setup);
 #endif
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 7c74e73..53beeb4 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -1281,7 +1281,7 @@
 		-EINVAL : 0;
 }
 
-#if defined(__i386__)
+#if defined(CONFIG_FB_FIRMWARE_EDID) && defined(__i386__)
 #include <linux/pci.h>
 
 /*
@@ -1311,11 +1311,11 @@
 {
 	return NULL;
 }
-#endif /* _i386_ */
+#endif
+EXPORT_SYMBOL(fb_firmware_edid);
 
 EXPORT_SYMBOL(fb_parse_edid);
 EXPORT_SYMBOL(fb_edid_to_monspecs);
-EXPORT_SYMBOL(fb_firmware_edid);
 EXPORT_SYMBOL(fb_get_mode);
 EXPORT_SYMBOL(fb_validate_mode);
 EXPORT_SYMBOL(fb_destroy_modedb);
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 6d26057..b72b052 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -348,7 +348,7 @@
 		fb_copy_cmap(&umap, &fb_info->cmap);
 		fb_dealloc_cmap(&umap);
 
-		return rc;
+		return rc ?: count;
 	}
 	for (i = 0; i < length; i++) {
 		u16 red, blue, green, tsp;
@@ -367,7 +367,7 @@
 		if (transp)
 			fb_info->cmap.transp[i] = tsp;
 	}
-	return 0;
+	return count;
 }
 
 static ssize_t show_cmap(struct class_device *class_device, char *buf)
diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig
index 42fb9a8..4e173ef 100644
--- a/drivers/video/geode/Kconfig
+++ b/drivers/video/geode/Kconfig
@@ -8,9 +8,24 @@
 	  Say 'Y' here to allow you to select framebuffer drivers for
 	  the AMD Geode family of processors.
 
+config FB_GEODE_GX
+	tristate "AMD Geode GX framebuffer support (EXPERIMENTAL)"
+	depends on FB && FB_GEODE && EXPERIMENTAL
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	---help---
+	  Framebuffer driver for the display controller integrated into the
+	  AMD Geode GX processors.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called gxfb.
+
+	  If unsure, say N.
+
 config FB_GEODE_GX1
 	tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)"
-	depends on FB_GEODE && EXPERIMENTAL
+	depends on FB && FB_GEODE && EXPERIMENTAL
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/geode/Makefile b/drivers/video/geode/Makefile
index 13ad501e..f896565 100644
--- a/drivers/video/geode/Makefile
+++ b/drivers/video/geode/Makefile
@@ -1,5 +1,7 @@
 # Makefile for the Geode family framebuffer drivers
 
 obj-$(CONFIG_FB_GEODE_GX1) += gx1fb.o
+obj-$(CONFIG_FB_GEODE_GX)  += gxfb.o
 
-gx1fb-objs   		:= gx1fb_core.o display_gx1.o video_cs5530.o
+gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o
+gxfb-objs  := gxfb_core.o display_gx.o video_gx.o
diff --git a/drivers/video/geode/display_gx.c b/drivers/video/geode/display_gx.c
new file mode 100644
index 0000000..825c340
--- /dev/null
+++ b/drivers/video/geode/display_gx.c
@@ -0,0 +1,156 @@
+/*
+ * Geode GX display controller.
+ *
+ *   Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ *   Portions from AMD's original 2.4 driver:
+ *     Copyright (C) 2004 Advanced Micro Devices, Inc.
+ *
+ *   This program is free software; you can redistribute it and/or modify it
+ *   under the terms of the GNU General Public License as published by * the
+ *   Free Software Foundation; either version 2 of the License, or * (at your
+ *   option) any later version.
+ */
+#include <linux/spinlock.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/div64.h>
+#include <asm/delay.h>
+
+#include "geodefb.h"
+#include "display_gx.h"
+
+int gx_frame_buffer_size(void)
+{
+	/* Assuming 16 MiB. */
+	return 16*1024*1024;
+}
+
+int gx_line_delta(int xres, int bpp)
+{
+	/* Must be a multiple of 8 bytes. */
+	return (xres * (bpp >> 3) + 7) & ~0x7;
+}
+
+static void gx_set_mode(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+	u32 gcfg, dcfg;
+	int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
+	int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
+
+	/* Unlock the display controller registers. */
+	readl(par->dc_regs + DC_UNLOCK);
+	writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
+
+	gcfg = readl(par->dc_regs + DC_GENERAL_CFG);
+	dcfg = readl(par->dc_regs + DC_DISPLAY_CFG);
+
+	/* Disable the timing generator. */
+	dcfg &= ~(DC_DCFG_TGEN);
+	writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
+
+	/* Wait for pending memory requests before disabling the FIFO load. */
+	udelay(100);
+
+	/* Disable FIFO load and compression. */
+	gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
+	writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+	/* Setup DCLK and its divisor. */
+	par->vid_ops->set_dclk(info);
+
+	/*
+	 * Setup new mode.
+	 */
+
+	/* Clear all unused feature bits. */
+	gcfg &= DC_GCFG_YUVM | DC_GCFG_VDSE;
+	dcfg = 0;
+
+	/* Set FIFO priority (default 6/5) and enable. */
+	/* FIXME: increase fifo priority for 1280x1024 and higher modes? */
+	gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE;
+
+	/* Framebuffer start offset. */
+	writel(0, par->dc_regs + DC_FB_ST_OFFSET);
+
+	/* Line delta and line buffer length. */
+	writel(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH);
+	writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
+	       par->dc_regs + DC_LINE_SIZE);
+
+	/* Enable graphics and video data and unmask address lines. */
+	dcfg |= DC_DCFG_GDEN | DC_DCFG_VDEN | DC_DCFG_A20M | DC_DCFG_A18M;
+
+	/* Set pixel format. */
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		dcfg |= DC_DCFG_DISP_MODE_8BPP;
+		break;
+	case 16:
+		dcfg |= DC_DCFG_DISP_MODE_16BPP;
+		dcfg |= DC_DCFG_16BPP_MODE_565;
+		break;
+	case 32:
+		dcfg |= DC_DCFG_DISP_MODE_24BPP;
+		dcfg |= DC_DCFG_PALB;
+		break;
+	}
+
+	/* Enable timing generator. */
+	dcfg |= DC_DCFG_TGEN;
+
+	/* Horizontal and vertical timings. */
+	hactive = info->var.xres;
+	hblankstart = hactive;
+	hsyncstart = hblankstart + info->var.right_margin;
+	hsyncend =  hsyncstart + info->var.hsync_len;
+	hblankend = hsyncend + info->var.left_margin;
+	htotal = hblankend;
+
+	vactive = info->var.yres;
+	vblankstart = vactive;
+	vsyncstart = vblankstart + info->var.lower_margin;
+	vsyncend =  vsyncstart + info->var.vsync_len;
+	vblankend = vsyncend + info->var.upper_margin;
+	vtotal = vblankend;
+
+	writel((hactive - 1)     | ((htotal - 1) << 16),    par->dc_regs + DC_H_ACTIVE_TIMING);
+	writel((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING);
+	writel((hsyncstart - 1)  | ((hsyncend - 1) << 16),  par->dc_regs + DC_H_SYNC_TIMING);
+
+	writel((vactive - 1)     | ((vtotal - 1) << 16),    par->dc_regs + DC_V_ACTIVE_TIMING);
+	writel((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING);
+	writel((vsyncstart - 1)  | ((vsyncend - 1) << 16),  par->dc_regs + DC_V_SYNC_TIMING);
+
+	/* Write final register values. */
+	writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
+	writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+	par->vid_ops->configure_display(info);
+
+	/* Relock display controller registers */
+	writel(0, par->dc_regs + DC_UNLOCK);
+}
+
+static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno,
+				   unsigned red, unsigned green, unsigned blue)
+{
+	struct geodefb_par *par = info->par;
+	int val;
+
+	/* Hardware palette is in RGB 8-8-8 format. */
+	val  = (red   << 8) & 0xff0000;
+	val |= (green)      & 0x00ff00;
+	val |= (blue  >> 8) & 0x0000ff;
+
+	writel(regno, par->dc_regs + DC_PAL_ADDRESS);
+	writel(val, par->dc_regs + DC_PAL_DATA);
+}
+
+struct geode_dc_ops gx_dc_ops = {
+	.set_mode	 = gx_set_mode,
+	.set_palette_reg = gx_set_hw_palette_reg,
+};
diff --git a/drivers/video/geode/display_gx.h b/drivers/video/geode/display_gx.h
new file mode 100644
index 0000000..86c6233
--- /dev/null
+++ b/drivers/video/geode/display_gx.h
@@ -0,0 +1,96 @@
+/*
+ * Geode GX display controller
+ *
+ * Copyright (C) 2006 Arcom Control Systems Ltd.
+ *
+ * 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 __DISPLAY_GX_H__
+#define __DISPLAY_GX_H__
+
+int gx_frame_buffer_size(void);
+int gx_line_delta(int xres, int bpp);
+
+extern struct geode_dc_ops gx_dc_ops;
+
+/* Display controller registers */
+
+#define DC_UNLOCK 0x00
+#  define DC_UNLOCK_CODE 0x00004758
+
+#define DC_GENERAL_CFG 0x04
+#  define DC_GCFG_DFLE	      0x00000001
+#  define DC_GCFG_CURE	      0x00000002
+#  define DC_GCFG_ICNE	      0x00000004
+#  define DC_GCFG_VIDE	      0x00000008
+#  define DC_GCFG_CMPE	      0x00000020
+#  define DC_GCFG_DECE	      0x00000040
+#  define DC_GCFG_VGAE	      0x00000080
+#  define DC_GCFG_DFHPSL_MASK 0x00000F00
+#  define DC_GCFG_DFHPSL_POS	       8
+#  define DC_GCFG_DFHPEL_MASK 0x0000F000
+#  define DC_GCFG_DFHPEL_POS	      12
+#  define DC_GCFG_STFM	      0x00010000
+#  define DC_GCFG_FDTY	      0x00020000
+#  define DC_GCFG_VGAFT	      0x00040000
+#  define DC_GCFG_VDSE	      0x00080000
+#  define DC_GCFG_YUVM	      0x00100000
+#  define DC_GCFG_VFSL	      0x00800000
+#  define DC_GCFG_SIGE	      0x01000000
+#  define DC_GCFG_SGRE	      0x02000000
+#  define DC_GCFG_SGFR	      0x04000000
+#  define DC_GCFG_CRC_MODE    0x08000000
+#  define DC_GCFG_DIAG	      0x10000000
+#  define DC_GCFG_CFRW	      0x20000000
+
+#define DC_DISPLAY_CFG 0x08
+#  define DC_DCFG_TGEN            0x00000001
+#  define DC_DCFG_GDEN            0x00000008
+#  define DC_DCFG_VDEN            0x00000010
+#  define DC_DCFG_TRUP            0x00000040
+#  define DC_DCFG_DISP_MODE_MASK  0x00000300
+#  define DC_DCFG_DISP_MODE_8BPP  0x00000000
+#  define DC_DCFG_DISP_MODE_16BPP 0x00000100
+#  define DC_DCFG_DISP_MODE_24BPP 0x00000200
+#  define DC_DCFG_16BPP_MODE_MASK 0x00000c00
+#  define DC_DCFG_16BPP_MODE_565  0x00000000
+#  define DC_DCFG_16BPP_MODE_555  0x00000100
+#  define DC_DCFG_16BPP_MODE_444  0x00000200
+#  define DC_DCFG_DCEN            0x00080000
+#  define DC_DCFG_PALB            0x02000000
+#  define DC_DCFG_FRLK            0x04000000
+#  define DC_DCFG_VISL            0x08000000
+#  define DC_DCFG_FRSL            0x20000000
+#  define DC_DCFG_A18M            0x40000000
+#  define DC_DCFG_A20M            0x80000000
+
+#define DC_FB_ST_OFFSET 0x10
+
+#define DC_LINE_SIZE 0x30
+#  define DC_LINE_SIZE_FB_LINE_SIZE_MASK  0x000007ff
+#  define DC_LINE_SIZE_FB_LINE_SIZE_POS            0
+#  define DC_LINE_SIZE_CB_LINE_SIZE_MASK  0x007f0000
+#  define DC_LINE_SIZE_CB_LINE_SIZE_POS           16
+#  define DC_LINE_SIZE_VID_LINE_SIZE_MASK 0xff000000
+#  define DC_LINE_SIZE_VID_LINE_SIZE_POS          24
+
+#define DC_GFX_PITCH 0x34
+#  define DC_GFX_PITCH_FB_PITCH_MASK 0x0000ffff
+#  define DC_GFX_PITCH_FB_PITCH_POS           0
+#  define DC_GFX_PITCH_CB_PITCH_MASK 0xffff0000
+#  define DC_GFX_PITCH_CB_PITCH_POS          16
+
+#define DC_H_ACTIVE_TIMING 0x40
+#define DC_H_BLANK_TIMING  0x44
+#define DC_H_SYNC_TIMING   0x48
+#define DC_V_ACTIVE_TIMING 0x50
+#define DC_V_BLANK_TIMING  0x54
+#define DC_V_SYNC_TIMING   0x58
+
+#define DC_PAL_ADDRESS 0x70
+#define DC_PAL_DATA    0x74
+
+#endif /* !__DISPLAY_GX1_H__ */
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c
new file mode 100644
index 0000000..89c34b1
--- /dev/null
+++ b/drivers/video/geode/gxfb_core.c
@@ -0,0 +1,423 @@
+/*
+ * Geode GX framebuffer driver.
+ *
+ *   Copyright (C) 2006 Arcom Control Systems Ltd.
+ *
+ *   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 driver assumes that the BIOS has created a virtual PCI device header
+ * for the video device. The PCI header is assumed to contain the following
+ * BARs:
+ *
+ *    BAR0 - framebuffer memory
+ *    BAR1 - graphics processor registers
+ *    BAR2 - display controller registers
+ *    BAR3 - video processor and flat panel control registers.
+ *
+ * 16 MiB of framebuffer memory is assumed to be available.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include "geodefb.h"
+#include "display_gx.h"
+#include "video_gx.h"
+
+static char mode_option[32] = "640x480-16@60";
+
+/* Modes relevant to the GX (taken from modedb.c) */
+static const struct fb_videomode __initdata gx_modedb[] = {
+	/* 640x480-60 VESA */
+	{ NULL, 60, 640, 480, 39682,  48, 16, 33, 10, 96, 2,
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 640x480-75 VESA */
+	{ NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 640x480-85 VESA */
+	{ NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3,
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 800x600-60 VESA */
+	{ NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 800x600-75 VESA */
+	{ NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 800x600-85 VESA */
+	{ NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 1024x768-60 VESA */
+	{ NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 1024x768-75 VESA */
+	{ NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 1024x768-85 VESA */
+	{ NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 1280x960-60 VESA */
+	{ NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 1280x960-85 VESA */
+	{ NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 1280x1024-60 VESA */
+	{ NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 1280x1024-75 VESA */
+	{ NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 1280x1024-85 VESA */
+	{ NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 1600x1200-60 VESA */
+	{ NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 1600x1200-75 VESA */
+	{ NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 1600x1200-85 VESA */
+	{ NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+};
+
+static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	if (var->xres > 1600 || var->yres > 1200)
+		return -EINVAL;
+	if ((var->xres > 1280 || var->yres > 1024) && var->bits_per_pixel > 16)
+		return -EINVAL;
+
+	if (var->bits_per_pixel == 32) {
+		var->red.offset   = 16; var->red.length   = 8;
+		var->green.offset =  8; var->green.length = 8;
+		var->blue.offset  =  0; var->blue.length  = 8;
+	} else if (var->bits_per_pixel == 16) {
+		var->red.offset   = 11; var->red.length   = 5;
+		var->green.offset =  5; var->green.length = 6;
+		var->blue.offset  =  0; var->blue.length  = 5;
+	} else if (var->bits_per_pixel == 8) {
+		var->red.offset   = 0; var->red.length   = 8;
+		var->green.offset = 0; var->green.length = 8;
+		var->blue.offset  = 0; var->blue.length  = 8;
+	} else
+		return -EINVAL;
+	var->transp.offset = 0; var->transp.length = 0;
+
+	/* Enough video memory? */
+	if (gx_line_delta(var->xres, var->bits_per_pixel) * var->yres > info->fix.smem_len)
+		return -EINVAL;
+
+	/* FIXME: Check timing parameters here? */
+
+	return 0;
+}
+
+static int gxfb_set_par(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+
+	if (info->var.bits_per_pixel > 8) {
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+		fb_dealloc_cmap(&info->cmap);
+	} else {
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
+	}
+
+	info->fix.line_length = gx_line_delta(info->var.xres, info->var.bits_per_pixel);
+
+	par->dc_ops->set_mode(info);
+
+	return 0;
+}
+
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+
+	if (info->var.grayscale) {
+		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	/* Truecolor has hardware independent palette */
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+		u32 *pal = info->pseudo_palette;
+		u32 v;
+
+		if (regno >= 16)
+			return -EINVAL;
+
+		v  = chan_to_field(red, &info->var.red);
+		v |= chan_to_field(green, &info->var.green);
+		v |= chan_to_field(blue, &info->var.blue);
+
+		pal[regno] = v;
+	} else {
+		if (regno >= 256)
+			return -EINVAL;
+
+		par->dc_ops->set_palette_reg(info, regno, red, green, blue);
+	}
+
+	return 0;
+}
+
+static int gxfb_blank(int blank_mode, struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+
+	return par->vid_ops->blank_display(info, blank_mode);
+}
+
+static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
+{
+	struct geodefb_par *par = info->par;
+	int fb_len;
+	int ret;
+
+	ret = pci_enable_device(dev);
+	if (ret < 0)
+		return ret;
+
+	ret = pci_request_region(dev, 3, "gxfb (video processor)");
+	if (ret < 0)
+		return ret;
+	par->vid_regs = ioremap(pci_resource_start(dev, 3),
+				pci_resource_len(dev, 3));
+	if (!par->vid_regs)
+		return -ENOMEM;
+
+	ret = pci_request_region(dev, 2, "gxfb (display controller)");
+	if (ret < 0)
+		return ret;
+	par->dc_regs = ioremap(pci_resource_start(dev, 2), pci_resource_len(dev, 2));
+	if (!par->dc_regs)
+		return -ENOMEM;
+
+	ret = pci_request_region(dev, 0, "gxfb (framebuffer)");
+	if (ret < 0)
+		return ret;
+	if ((fb_len = gx_frame_buffer_size()) < 0)
+		return -ENOMEM;
+	info->fix.smem_start = pci_resource_start(dev, 0);
+	info->fix.smem_len = fb_len;
+	info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+	if (!info->screen_base)
+		return -ENOMEM;
+
+	dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n",
+		 info->fix.smem_len / 1024, info->fix.smem_start);
+
+	return 0;
+}
+
+static struct fb_ops gxfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= gxfb_check_var,
+	.fb_set_par	= gxfb_set_par,
+	.fb_setcolreg	= gxfb_setcolreg,
+	.fb_blank       = gxfb_blank,
+	/* No HW acceleration for now. */
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+static struct fb_info * __init gxfb_init_fbinfo(struct device *dev)
+{
+	struct geodefb_par *par;
+	struct fb_info *info;
+
+	/* Alloc enough space for the pseudo palette. */
+	info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, dev);
+	if (!info)
+		return NULL;
+
+	par = info->par;
+
+	strcpy(info->fix.id, "Geode GX");
+
+	info->fix.type		= FB_TYPE_PACKED_PIXELS;
+	info->fix.type_aux	= 0;
+	info->fix.xpanstep	= 0;
+	info->fix.ypanstep	= 0;
+	info->fix.ywrapstep	= 0;
+	info->fix.accel		= FB_ACCEL_NONE;
+
+	info->var.nonstd	= 0;
+	info->var.activate	= FB_ACTIVATE_NOW;
+	info->var.height	= -1;
+	info->var.width	= -1;
+	info->var.accel_flags = 0;
+	info->var.vmode	= FB_VMODE_NONINTERLACED;
+
+	info->fbops		= &gxfb_ops;
+	info->flags		= FBINFO_DEFAULT;
+	info->node		= -1;
+
+	info->pseudo_palette	= (void *)par + sizeof(struct geodefb_par);
+
+	info->var.grayscale	= 0;
+
+	return info;
+}
+
+static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct geodefb_par *par;
+	struct fb_info *info;
+	int ret;
+
+	info = gxfb_init_fbinfo(&pdev->dev);
+	if (!info)
+		return -ENOMEM;
+	par = info->par;
+
+	/* GX display controller and GX video device. */
+	par->dc_ops  = &gx_dc_ops;
+	par->vid_ops = &gx_vid_ops;
+
+	if ((ret = gxfb_map_video_memory(info, pdev)) < 0) {
+		dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n");
+		goto err;
+	}
+
+	ret = fb_find_mode(&info->var, info, mode_option,
+			   gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16);
+	if (ret == 0 || ret == 4) {
+		dev_err(&pdev->dev, "could not find valid video mode\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+        /* Clear the frame buffer of garbage. */
+        memset_io(info->screen_base, 0, info->fix.smem_len);
+
+	gxfb_check_var(&info->var, info);
+	gxfb_set_par(info);
+
+	if (register_framebuffer(info) < 0) {
+		ret = -EINVAL;
+		goto err;
+	}
+	pci_set_drvdata(pdev, info);
+	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
+	return 0;
+
+  err:
+	if (info->screen_base) {
+		iounmap(info->screen_base);
+		pci_release_region(pdev, 0);
+	}
+	if (par->vid_regs) {
+		iounmap(par->vid_regs);
+		pci_release_region(pdev, 3);
+	}
+	if (par->dc_regs) {
+		iounmap(par->dc_regs);
+		pci_release_region(pdev, 2);
+	}
+
+	pci_disable_device(pdev);
+
+	if (info)
+		framebuffer_release(info);
+	return ret;
+}
+
+static void gxfb_remove(struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct geodefb_par *par = info->par;
+
+	unregister_framebuffer(info);
+
+	iounmap((void __iomem *)info->screen_base);
+	pci_release_region(pdev, 0);
+
+	iounmap(par->vid_regs);
+	pci_release_region(pdev, 3);
+
+	iounmap(par->dc_regs);
+	pci_release_region(pdev, 2);
+
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+
+	framebuffer_release(info);
+}
+
+static struct pci_device_id gxfb_id_table[] = {
+	{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_VIDEO,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	  0xff0000, 0 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, gxfb_id_table);
+
+static struct pci_driver gxfb_driver = {
+	.name		= "gxfb",
+	.id_table	= gxfb_id_table,
+	.probe		= gxfb_probe,
+	.remove		= gxfb_remove,
+};
+
+static int __init gxfb_init(void)
+{
+#ifndef MODULE
+	if (fb_get_options("gxfb", NULL))
+		return -ENODEV;
+#endif
+	return pci_register_driver(&gxfb_driver);
+}
+
+static void __exit gxfb_cleanup(void)
+{
+	pci_unregister_driver(&gxfb_driver);
+}
+
+module_init(gxfb_init);
+module_exit(gxfb_cleanup);
+
+module_param_string(mode, mode_option, sizeof(mode_option), 0444);
+MODULE_PARM_DESC(mode, "video mode (<x>x<y>[-<bpp>][@<refr>])");
+
+MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c
new file mode 100644
index 0000000..2b2a788
--- /dev/null
+++ b/drivers/video/geode/video_gx.c
@@ -0,0 +1,262 @@
+/*
+ * Geode GX video processor device.
+ *
+ *   Copyright (C) 2006 Arcom Control Systems Ltd.
+ *
+ *   Portions from AMD's original 2.4 driver:
+ *     Copyright (C) 2004 Advanced Micro Devices, Inc.
+ *
+ *   This program is free software; you can redistribute it and/or modify it
+ *   under the terms of the GNU General Public License as published by the
+ *   Free Software Foundation; either version 2 of the License, or (at your
+ *   option) any later version.
+ */
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/msr.h>
+
+#include "geodefb.h"
+#include "video_gx.h"
+
+
+/*
+ * Tables of register settings for various DOTCLKs.
+ */
+struct gx_pll_entry {
+	long pixclock; /* ps */
+	u32 sys_rstpll_bits;
+	u32 dotpll_value;
+};
+
+#define POSTDIV3 ((u32)MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3)
+#define PREMULT2 ((u32)MSR_GLCP_SYS_RSTPLL_DOTPREMULT2)
+#define PREDIV2  ((u32)MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3)
+
+static const struct gx_pll_entry gx_pll_table_48MHz[] = {
+	{ 40123, POSTDIV3,	    0x00000BF2 },	/*  24.9230 */
+	{ 39721, 0,		    0x00000037 },	/*  25.1750 */
+	{ 35308, POSTDIV3|PREMULT2, 0x00000B1A },	/*  28.3220 */
+	{ 31746, POSTDIV3,	    0x000002D2 },	/*  31.5000 */
+	{ 27777, POSTDIV3|PREMULT2, 0x00000FE2 },	/*  36.0000 */
+	{ 26666, POSTDIV3,	    0x0000057A },	/*  37.5000 */
+	{ 25000, POSTDIV3,	    0x0000030A },	/*  40.0000 */
+	{ 22271, 0,		    0x00000063 },	/*  44.9000 */
+	{ 20202, 0,		    0x0000054B },	/*  49.5000 */
+	{ 20000, 0,		    0x0000026E },	/*  50.0000 */
+	{ 19860, PREMULT2,	    0x00000037 },	/*  50.3500 */
+	{ 18518, POSTDIV3|PREMULT2, 0x00000B0D },	/*  54.0000 */
+	{ 17777, 0,		    0x00000577 },	/*  56.2500 */
+	{ 17733, 0,		    0x000007F7 },	/*  56.3916 */
+	{ 17653, 0,		    0x0000057B },	/*  56.6444 */
+	{ 16949, PREMULT2,	    0x00000707 },	/*  59.0000 */
+	{ 15873, POSTDIV3|PREMULT2, 0x00000B39 },	/*  63.0000 */
+	{ 15384, POSTDIV3|PREMULT2, 0x00000B45 },	/*  65.0000 */
+	{ 14814, POSTDIV3|PREMULT2, 0x00000FC1 },	/*  67.5000 */
+	{ 14124, POSTDIV3,	    0x00000561 },	/*  70.8000 */
+	{ 13888, POSTDIV3,	    0x000007E1 },	/*  72.0000 */
+	{ 13426, PREMULT2,	    0x00000F4A },	/*  74.4810 */
+	{ 13333, 0,		    0x00000052 },	/*  75.0000 */
+	{ 12698, 0,		    0x00000056 },	/*  78.7500 */
+	{ 12500, POSTDIV3|PREMULT2, 0x00000709 },	/*  80.0000 */
+	{ 11135, PREMULT2,	    0x00000262 },	/*  89.8000 */
+	{ 10582, 0,		    0x000002D2 },	/*  94.5000 */
+	{ 10101, PREMULT2,	    0x00000B4A },	/*  99.0000 */
+	{ 10000, PREMULT2,	    0x00000036 },	/* 100.0000 */
+	{  9259, 0,		    0x000007E2 },	/* 108.0000 */
+	{  8888, 0,		    0x000007F6 },	/* 112.5000 */
+	{  7692, POSTDIV3|PREMULT2, 0x00000FB0 },	/* 130.0000 */
+	{  7407, POSTDIV3|PREMULT2, 0x00000B50 },	/* 135.0000 */
+	{  6349, 0,		    0x00000055 },	/* 157.5000 */
+	{  6172, 0,		    0x000009C1 },	/* 162.0000 */
+	{  5787, PREMULT2,	    0x0000002D },	/* 172.798  */
+	{  5698, 0,		    0x000002C1 },	/* 175.5000 */
+	{  5291, 0,		    0x000002D1 },	/* 189.0000 */
+	{  4938, 0,		    0x00000551 },	/* 202.5000 */
+	{  4357, 0,		    0x0000057D },	/* 229.5000 */
+};
+
+static const struct gx_pll_entry gx_pll_table_14MHz[] = {
+	{ 39721, 0, 0x00000037 },	/*  25.1750 */
+	{ 35308, 0, 0x00000B7B },	/*  28.3220 */
+	{ 31746, 0, 0x000004D3 },	/*  31.5000 */
+	{ 27777, 0, 0x00000BE3 },	/*  36.0000 */
+	{ 26666, 0, 0x0000074F },	/*  37.5000 */
+	{ 25000, 0, 0x0000050B },	/*  40.0000 */
+	{ 22271, 0, 0x00000063 },	/*  44.9000 */
+	{ 20202, 0, 0x0000054B },	/*  49.5000 */
+	{ 20000, 0, 0x0000026E },	/*  50.0000 */
+	{ 19860, 0, 0x000007C3 },	/*  50.3500 */
+	{ 18518, 0, 0x000007E3 },	/*  54.0000 */
+	{ 17777, 0, 0x00000577 },	/*  56.2500 */
+	{ 17733, 0, 0x000002FB },	/*  56.3916 */
+	{ 17653, 0, 0x0000057B },	/*  56.6444 */
+	{ 16949, 0, 0x0000058B },	/*  59.0000 */
+	{ 15873, 0, 0x0000095E },	/*  63.0000 */
+	{ 15384, 0, 0x0000096A },	/*  65.0000 */
+	{ 14814, 0, 0x00000BC2 },	/*  67.5000 */
+	{ 14124, 0, 0x0000098A },	/*  70.8000 */
+	{ 13888, 0, 0x00000BE2 },	/*  72.0000 */
+	{ 13333, 0, 0x00000052 },	/*  75.0000 */
+	{ 12698, 0, 0x00000056 },	/*  78.7500 */
+	{ 12500, 0, 0x0000050A },	/*  80.0000 */
+	{ 11135, 0, 0x0000078E },	/*  89.8000 */
+	{ 10582, 0, 0x000002D2 },	/*  94.5000 */
+	{ 10101, 0, 0x000011F6 },	/*  99.0000 */
+	{ 10000, 0, 0x0000054E },	/* 100.0000 */
+	{  9259, 0, 0x000007E2 },	/* 108.0000 */
+	{  8888, 0, 0x000002FA },	/* 112.5000 */
+	{  7692, 0, 0x00000BB1 },	/* 130.0000 */
+	{  7407, 0, 0x00000975 },	/* 135.0000 */
+	{  6349, 0, 0x00000055 },	/* 157.5000 */
+	{  6172, 0, 0x000009C1 },	/* 162.0000 */
+	{  5698, 0, 0x000002C1 },	/* 175.5000 */
+	{  5291, 0, 0x00000539 },	/* 189.0000 */
+	{  4938, 0, 0x00000551 },	/* 202.5000 */
+	{  4357, 0, 0x0000057D },	/* 229.5000 */
+};
+
+static void gx_set_dclk_frequency(struct fb_info *info)
+{
+	const struct gx_pll_entry *pll_table;
+	int pll_table_len;
+	int i, best_i;
+	long min, diff;
+	u64 dotpll, sys_rstpll;
+	int timeout = 1000;
+
+	/* Rev. 1 Geode GXs use a 14 MHz reference clock instead of 48 MHz. */
+	if (cpu_data->x86_mask == 1) {
+		pll_table = gx_pll_table_14MHz;
+		pll_table_len = ARRAY_SIZE(gx_pll_table_14MHz);
+	} else {
+		pll_table = gx_pll_table_48MHz;
+		pll_table_len = ARRAY_SIZE(gx_pll_table_48MHz);
+	}
+
+	/* Search the table for the closest pixclock. */
+	best_i = 0;
+	min = abs(pll_table[0].pixclock - info->var.pixclock);
+	for (i = 1; i < pll_table_len; i++) {
+		diff = abs(pll_table[i].pixclock - info->var.pixclock);
+		if (diff < min) {
+			min = diff;
+			best_i = i;
+		}
+	}
+
+	rdmsrl(MSR_GLCP_SYS_RSTPLL, sys_rstpll);
+	rdmsrl(MSR_GLCP_DOTPLL, dotpll);
+
+	/* Program new M, N and P. */
+	dotpll &= 0x00000000ffffffffull;
+	dotpll |= (u64)pll_table[best_i].dotpll_value << 32;
+	dotpll |= MSR_GLCP_DOTPLL_DOTRESET;
+	dotpll &= ~MSR_GLCP_DOTPLL_BYPASS;
+
+	wrmsrl(MSR_GLCP_DOTPLL, dotpll);
+
+	/* Program dividers. */
+	sys_rstpll &= ~( MSR_GLCP_SYS_RSTPLL_DOTPREDIV2
+			 | MSR_GLCP_SYS_RSTPLL_DOTPREMULT2
+			 | MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 );
+	sys_rstpll |= pll_table[best_i].sys_rstpll_bits;
+
+	wrmsrl(MSR_GLCP_SYS_RSTPLL, sys_rstpll);
+
+	/* Clear reset bit to start PLL. */
+	dotpll &= ~(MSR_GLCP_DOTPLL_DOTRESET);
+	wrmsrl(MSR_GLCP_DOTPLL, dotpll);
+
+	/* Wait for LOCK bit. */
+	do {
+		rdmsrl(MSR_GLCP_DOTPLL, dotpll);
+	} while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK));
+}
+
+static void gx_configure_display(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+	u32 dcfg, fp_pm;
+
+	dcfg = readl(par->vid_regs + GX_DCFG);
+
+	/* Clear bits from existing mode. */
+	dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK
+		  | GX_DCFG_CRT_HSYNC_POL   | GX_DCFG_CRT_VSYNC_POL
+		  | GX_DCFG_VSYNC_EN        | GX_DCFG_HSYNC_EN);
+
+	/* Set default sync skew.  */
+	dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT;
+
+	/* Enable hsync and vsync. */
+	dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN;
+
+	/* Sync polarities. */
+	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+		dcfg |= GX_DCFG_CRT_HSYNC_POL;
+	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+		dcfg |= GX_DCFG_CRT_VSYNC_POL;
+
+	writel(dcfg, par->vid_regs + GX_DCFG);
+
+	/* Power on flat panel. */
+	fp_pm = readl(par->vid_regs + GX_FP_PM);
+	fp_pm |= GX_FP_PM_P;
+	writel(fp_pm, par->vid_regs + GX_FP_PM);
+}
+
+static int gx_blank_display(struct fb_info *info, int blank_mode)
+{
+	struct geodefb_par *par = info->par;
+	u32 dcfg, fp_pm;
+	int blank, hsync, vsync;
+
+	/* CRT power saving modes. */
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		blank = 0; hsync = 1; vsync = 1;
+		break;
+	case FB_BLANK_NORMAL:
+		blank = 1; hsync = 1; vsync = 1;
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		blank = 1; hsync = 1; vsync = 0;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		blank = 1; hsync = 0; vsync = 1;
+		break;
+	case FB_BLANK_POWERDOWN:
+		blank = 1; hsync = 0; vsync = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	dcfg = readl(par->vid_regs + GX_DCFG);
+	dcfg &= ~(GX_DCFG_DAC_BL_EN
+		  | GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN);
+	if (!blank)
+		dcfg |= GX_DCFG_DAC_BL_EN;
+	if (hsync)
+		dcfg |= GX_DCFG_HSYNC_EN;
+	if (vsync)
+		dcfg |= GX_DCFG_VSYNC_EN;
+	writel(dcfg, par->vid_regs + GX_DCFG);
+
+	/* Power on/off flat panel. */
+	fp_pm = readl(par->vid_regs + GX_FP_PM);
+	if (blank_mode == FB_BLANK_POWERDOWN)
+		fp_pm &= ~GX_FP_PM_P;
+	else
+		fp_pm |= GX_FP_PM_P;
+	writel(fp_pm, par->vid_regs + GX_FP_PM);
+
+	return 0;
+}
+
+struct geode_vid_ops gx_vid_ops = {
+	.set_dclk	   = gx_set_dclk_frequency,
+	.configure_display = gx_configure_display,
+	.blank_display	   = gx_blank_display,
+};
diff --git a/drivers/video/geode/video_gx.h b/drivers/video/geode/video_gx.h
new file mode 100644
index 0000000..2d9211f
--- /dev/null
+++ b/drivers/video/geode/video_gx.h
@@ -0,0 +1,47 @@
+/*
+ * Geode GX video device
+ *
+ * Copyright (C) 2006 Arcom Control Systems Ltd.
+ *
+ * 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 __VIDEO_GX_H__
+#define __VIDEO_GX_H__
+
+extern struct geode_vid_ops gx_vid_ops;
+
+/* Geode GX video processor registers */
+
+#define GX_DCFG		0x0008
+#  define GX_DCFG_CRT_EN		0x00000001
+#  define GX_DCFG_HSYNC_EN		0x00000002
+#  define GX_DCFG_VSYNC_EN		0x00000004
+#  define GX_DCFG_DAC_BL_EN		0x00000008
+#  define GX_DCFG_CRT_HSYNC_POL		0x00000100
+#  define GX_DCFG_CRT_VSYNC_POL		0x00000200
+#  define GX_DCFG_CRT_SYNC_SKW_MASK	0x0001C000
+#  define GX_DCFG_CRT_SYNC_SKW_DFLT	0x00010000
+#  define GX_DCFG_VG_CK			0x00100000
+#  define GX_DCFG_GV_GAM		0x00200000
+#  define GX_DCFG_DAC_VREF		0x04000000
+
+/* Geode GX flat panel display control registers */
+#define GX_FP_PM 0x410
+#  define GX_FP_PM_P 0x01000000
+
+/* Geode GX clock control MSRs */
+
+#define MSR_GLCP_SYS_RSTPLL	0x4c000014
+#  define MSR_GLCP_SYS_RSTPLL_DOTPREDIV2	(0x0000000000000002ull)
+#  define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2	(0x0000000000000004ull)
+#  define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3	(0x0000000000000008ull)
+
+#define MSR_GLCP_DOTPLL		0x4c000015
+#  define MSR_GLCP_DOTPLL_DOTRESET		(0x0000000000000001ull)
+#  define MSR_GLCP_DOTPLL_BYPASS		(0x0000000000008000ull)
+#  define MSR_GLCP_DOTPLL_LOCK			(0x0000000002000000ull)
+
+#endif /* !__VIDEO_GX_H__ */
diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c
index e3c8b5f..3fe3ae1 100644
--- a/drivers/video/i810/i810-i2c.c
+++ b/drivers/video/i810/i810-i2c.c
@@ -210,8 +210,7 @@
 		}
 	}
 
-        if (out_edid)
-                *out_edid = edid;
+	*out_edid = edid;
 
         return (edid) ? 0 : 1;
 }
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
index 7db4254..f73c642 100644
--- a/drivers/video/imsttfb.c
+++ b/drivers/video/imsttfb.c
@@ -440,9 +440,9 @@
 static void
 setclkMHz(struct imstt_par *par, __u32 MHz)
 {
-	__u32 clk_m, clk_n, clk_p, x, stage, spilled;
+	__u32 clk_m, clk_n, x, stage, spilled;
 
-	clk_m = clk_n = clk_p = 0;
+	clk_m = clk_n = 0;
 	stage = spilled = 0;
 	for (;;) {
 		switch (stage) {
@@ -453,7 +453,7 @@
 				clk_n++;
 				break;
 		}
-		x = 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1));
+		x = 20 * (clk_m + 1) / (clk_n + 1);
 		if (x == MHz)
 			break;
 		if (x > MHz) {
@@ -466,7 +466,7 @@
 
 	par->init.pclk_m = clk_m;
 	par->init.pclk_n = clk_n;
-	par->init.pclk_p = clk_p;
+	par->init.pclk_p = 0;
 }
 
 static struct imstt_regvals *
@@ -1372,18 +1372,24 @@
 	write_reg_le32(par->dc_regs, STGCTL, tmp & ~0x1);
 	write_reg_le32(par->dc_regs, SSR, 0);
 
-	/* set default values for DAC registers */ 
+	/* set default values for DAC registers */
 	if (par->ramdac == IBM) {
-		par->cmap_regs[PPMASK] = 0xff;	eieio();
-		par->cmap_regs[PIDXHI] = 0;	eieio();
-		for (i = 0; i < sizeof(ibm_initregs) / sizeof(*ibm_initregs); i++) {
-			par->cmap_regs[PIDXLO] = ibm_initregs[i].addr;	eieio();
-			par->cmap_regs[PIDXDATA] = ibm_initregs[i].value;	eieio();
+		par->cmap_regs[PPMASK] = 0xff;
+		eieio();
+		par->cmap_regs[PIDXHI] = 0;
+		eieio();
+		for (i = 0; i < ARRAY_SIZE(ibm_initregs); i++) {
+			par->cmap_regs[PIDXLO] = ibm_initregs[i].addr;
+			eieio();
+			par->cmap_regs[PIDXDATA] = ibm_initregs[i].value;
+			eieio();
 		}
 	} else {
-		for (i = 0; i < sizeof(tvp_initregs) / sizeof(*tvp_initregs); i++) {
-			par->cmap_regs[TVPADDRW] = tvp_initregs[i].addr;	eieio();
-			par->cmap_regs[TVPIDATA] = tvp_initregs[i].value;	eieio();
+		for (i = 0; i < ARRAY_SIZE(tvp_initregs); i++) {
+			par->cmap_regs[TVPADDRW] = tvp_initregs[i].addr;
+			eieio();
+			par->cmap_regs[TVPIDATA] = tvp_initregs[i].value;
+			eieio();
 		}
 	}
 
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c
index 2fc7108..c0385c6 100644
--- a/drivers/video/macmodes.c
+++ b/drivers/video/macmodes.c
@@ -380,7 +380,7 @@
     if (mode_option && !strncmp(mode_option, "mac", 3)) {
 	mode_option += 3;
 	db = mac_modedb;
-	dbsize = sizeof(mac_modedb)/sizeof(*mac_modedb);
+	dbsize = ARRAY_SIZE(mac_modedb);
     }
     return fb_find_mode(var, info, mode_option, db, dbsize,
 			&mac_modedb[DEFAULT_MODEDB_INDEX], default_bpp);
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index 951c997..23c1827 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -115,6 +115,7 @@
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_PPC_PMAC
+#include <asm/machdep.h>
 unsigned char nvram_read_byte(int);
 static int default_vmode = VMODE_NVRAM;
 static int default_cmode = CMODE_NVRAM;
@@ -1833,7 +1834,7 @@
 	/* FIXME: Where to move this?! */
 #if defined(CONFIG_PPC_PMAC)
 #ifndef MODULE
-	if (_machine == _MACH_Pmac) {
+	if (machine_is(powermac)) {
 		struct fb_var_screeninfo var;
 		if (default_vmode <= 0 || default_vmode > VMODE_MAX)
 			default_vmode = VMODE_640_480_60;
diff --git a/drivers/video/matrox/matroxfb_g450.c b/drivers/video/matrox/matroxfb_g450.c
index c122d87..4d610b4 100644
--- a/drivers/video/matrox/matroxfb_g450.c
+++ b/drivers/video/matrox/matroxfb_g450.c
@@ -59,7 +59,7 @@
 	}, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
 };
 
-#define G450CTRLS (sizeof(g450_controls)/sizeof(g450_controls[0]))
+#define G450CTRLS ARRAY_SIZE(g450_controls)
 
 /* Return: positive number: id found
            -EINVAL:         id not found, return failure
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
index 6019710..5d29a26 100644
--- a/drivers/video/matrox/matroxfb_maven.c
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -89,12 +89,12 @@
 	}, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
 	{ { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER,
 	  "gamma",
-	  0, sizeof(maven_gamma)/sizeof(maven_gamma[0])-1, 1, 3,
+	  0, ARRAY_SIZE(maven_gamma) - 1, 1, 3,
 	  0,
 	}, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) },
 	{ { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
 	  "test output",
-	  0, 1, 1, 0, 
+	  0, 1, 1, 0,
 	  0,
 	}, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
 	{ { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER,
@@ -105,7 +105,7 @@
 
 };
 
-#define MAVCTRLS (sizeof(maven_controls)/sizeof(maven_controls[0]))
+#define MAVCTRLS ARRAY_SIZE(maven_controls)
 
 /* Return: positive number: id found
            -EINVAL:         id not found, return failure
@@ -129,7 +129,7 @@
 
 struct maven_data {
 	struct matrox_fb_info*		primary_head;
-	struct i2c_client*		client;
+	struct i2c_client		client;
 	int				version;
 };
 
@@ -970,7 +970,7 @@
 
 static int maven_program_timming(struct maven_data* md,
 		const struct mavenregs* m) {
-	struct i2c_client* c = md->client;
+	struct i2c_client* c = &md->client;
 
 	if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
 		LR(0x80);
@@ -1007,7 +1007,7 @@
 }
 
 static inline int maven_resync(struct maven_data* md) {
-	struct i2c_client* c = md->client;
+	struct i2c_client* c = &md->client;
 	maven_set_reg(c, 0x95, 0x20);	/* start whole thing */
 	return 0;
 }
@@ -1065,48 +1065,48 @@
 		  maven_compute_bwlevel(md, &blacklevel, &whitelevel);
 		  blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8);
 		  whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8);
-		  maven_set_reg_pair(md->client, 0x0e, blacklevel);
-		  maven_set_reg_pair(md->client, 0x1e, whitelevel);
+		  maven_set_reg_pair(&md->client, 0x0e, blacklevel);
+		  maven_set_reg_pair(&md->client, 0x1e, whitelevel);
 		}
 		break;
 		case V4L2_CID_SATURATION:
 		{
-		  maven_set_reg(md->client, 0x20, p->value);
-		  maven_set_reg(md->client, 0x22, p->value);
+		  maven_set_reg(&md->client, 0x20, p->value);
+		  maven_set_reg(&md->client, 0x22, p->value);
 		}
 		break;
 		case V4L2_CID_HUE:
 		{
-		  maven_set_reg(md->client, 0x25, p->value);
+		  maven_set_reg(&md->client, 0x25, p->value);
 		}
 		break;
 		case V4L2_CID_GAMMA:
 		{
 		  const struct maven_gamma* g;
 		  g = maven_compute_gamma(md);
-		  maven_set_reg(md->client, 0x83, g->reg83);
-		  maven_set_reg(md->client, 0x84, g->reg84);
-		  maven_set_reg(md->client, 0x85, g->reg85);
-		  maven_set_reg(md->client, 0x86, g->reg86);
-		  maven_set_reg(md->client, 0x87, g->reg87);
-		  maven_set_reg(md->client, 0x88, g->reg88);
-		  maven_set_reg(md->client, 0x89, g->reg89);
-		  maven_set_reg(md->client, 0x8a, g->reg8a);
-		  maven_set_reg(md->client, 0x8b, g->reg8b);
+		  maven_set_reg(&md->client, 0x83, g->reg83);
+		  maven_set_reg(&md->client, 0x84, g->reg84);
+		  maven_set_reg(&md->client, 0x85, g->reg85);
+		  maven_set_reg(&md->client, 0x86, g->reg86);
+		  maven_set_reg(&md->client, 0x87, g->reg87);
+		  maven_set_reg(&md->client, 0x88, g->reg88);
+		  maven_set_reg(&md->client, 0x89, g->reg89);
+		  maven_set_reg(&md->client, 0x8a, g->reg8a);
+		  maven_set_reg(&md->client, 0x8b, g->reg8b);
 		}
 		break;
 		case MATROXFB_CID_TESTOUT:
 		{
 			unsigned char val 
-			  = maven_get_reg (md->client,0x8d);
+			  = maven_get_reg(&md->client,0x8d);
 			if (p->value) val |= 0x10;
 			else          val &= ~0x10;
-			maven_set_reg (md->client, 0x8d, val);
+			maven_set_reg(&md->client, 0x8d, val);
 		}
 		break;
 		case MATROXFB_CID_DEFLICKER:
 		{
-		  maven_set_reg(md->client, 0x93, maven_compute_deflicker(md));
+		  maven_set_reg(&md->client, 0x93, maven_compute_deflicker(md));
 		}
 		break;
 	}
@@ -1185,7 +1185,6 @@
 	MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo);
 
 	md->primary_head = MINFO;
-	md->client = clnt;
 	down_write(&ACCESS_FBINFO(altout.lock));
 	ACCESS_FBINFO(outputs[1]).output = &maven_altout;
 	ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src;
@@ -1243,19 +1242,17 @@
 					      I2C_FUNC_SMBUS_BYTE_DATA |
 					      I2C_FUNC_PROTOCOL_MANGLING))
 		goto ERROR0;
-	if (!(new_client = (struct i2c_client*)kmalloc(sizeof(*new_client) + sizeof(*data),
-			GFP_KERNEL))) {
+	if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) {
 		err = -ENOMEM;
 		goto ERROR0;
 	}
-	memset(new_client, 0, sizeof(*new_client) + sizeof(*data));
-	data = (struct maven_data*)(new_client + 1);
+	new_client = &data->client;
 	i2c_set_clientdata(new_client, data);
 	new_client->addr = address;
 	new_client->adapter = adapter;
 	new_client->driver = &maven_driver;
 	new_client->flags = 0;
-	strcpy(new_client->name, "maven client");
+	strlcpy(new_client->name, "maven", I2C_NAME_SIZE);
 	if ((err = i2c_attach_client(new_client)))
 		goto ERROR3;
 	err = maven_init_client(new_client);
@@ -1279,12 +1276,10 @@
 static int maven_detach_client(struct i2c_client* client) {
 	int err;
 
-	if ((err = i2c_detach_client(client))) {
-		printk(KERN_ERR "maven: Cannot deregister client\n");
+	if ((err = i2c_detach_client(client)))
 		return err;
-	}
 	maven_shutdown_client(client);
-	kfree(client);
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
@@ -1297,20 +1292,13 @@
 	.detach_client	= maven_detach_client,
 };
 
-/* ************************** */
-
-static int matroxfb_maven_init(void) {
-	int err;
-
-	err = i2c_add_driver(&maven_driver);
-	if (err) {
-		printk(KERN_ERR "maven: Maven driver failed to register (%d).\n", err);
-		return err;
-	}
-	return 0;
+static int __init matroxfb_maven_init(void)
+{
+	return i2c_add_driver(&maven_driver);
 }
 
-static void matroxfb_maven_exit(void) {
+static void __exit matroxfb_maven_exit(void)
+{
 	i2c_del_driver(&maven_driver);
 }
 
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 1da2f84..26a1c61 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -183,6 +183,10 @@
 	NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
 	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
     }, {
+	/* 1680x1050 @ 60 Hz, 65.191 kHz hsync */
+	NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
 	/* 1600x1200 @ 85 Hz, 105.77 kHz hsync */
 	NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3,
 	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
@@ -496,7 +500,7 @@
     /* Set up defaults */
     if (!db) {
 	db = modedb;
-	dbsize = sizeof(modedb)/sizeof(*modedb);
+	dbsize = ARRAY_SIZE(modedb);
     }
     if (!default_mode)
 	default_mode = &modedb[DEFAULT_MODEDB_INDEX];
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index b961d56..24b12f7 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -165,20 +165,20 @@
 
 	switch (depth) {
 	case 8:
-		size = sizeof(bios8) / sizeof(biosMode);
+		size = ARRAY_SIZE(bios8);
 		mode = bios8;
 		break;
 	case 16:
-		size = sizeof(bios16) / sizeof(biosMode);
+		size = ARRAY_SIZE(bios16);
 		mode = bios16;
 		break;
 	case 24:
-		size = sizeof(bios24) / sizeof(biosMode);
+		size = ARRAY_SIZE(bios24);
 		mode = bios24;
 		break;
 #ifdef NO_32BIT_SUPPORT_YET
 	case 32:
-		size = sizeof(bios32) / sizeof(biosMode);
+		size = ARRAY_SIZE(bios32);
 		mode = bios32;
 		break;
 #endif
diff --git a/drivers/video/nvidia/nv_accel.c b/drivers/video/nvidia/nv_accel.c
index f377a29..4aefb8f 100644
--- a/drivers/video/nvidia/nv_accel.c
+++ b/drivers/video/nvidia/nv_accel.c
@@ -300,6 +300,9 @@
 {
 	struct nvidia_par *par = info->par;
 
+	if (info->state != FBINFO_STATE_RUNNING)
+		return 0;
+
 	if (!par->lockup)
 		NVFlush(par);
 
@@ -313,6 +316,9 @@
 {
 	struct nvidia_par *par = info->par;
 
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
+
 	if (par->lockup)
 		return cfb_copyarea(info, region);
 
@@ -329,6 +335,9 @@
 	struct nvidia_par *par = info->par;
 	u32 color;
 
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
+
 	if (par->lockup)
 		return cfb_fillrect(info, rect);
 
@@ -412,6 +421,9 @@
 {
 	struct nvidia_par *par = info->par;
 
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
+
 	if (image->depth == 1 && !par->lockup)
 		nvidiafb_mono_color_expand(info, image);
 	else
diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c
index bd9eca0..1edb1c4 100644
--- a/drivers/video/nvidia/nv_i2c.c
+++ b/drivers/video/nvidia/nv_i2c.c
@@ -218,8 +218,7 @@
 		}
 	}
 
-	if (out_edid)
-		*out_edid = edid;
+	*out_edid = edid;
 
 	return (edid) ? 0 : 1;
 }
diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h
index e4a5b1d..acdc266 100644
--- a/drivers/video/nvidia/nv_type.h
+++ b/drivers/video/nvidia/nv_type.h
@@ -129,6 +129,7 @@
 	int fpHeight;
 	int PanelTweak;
 	int paneltweak;
+	int pm_state;
 	u32 crtcSync_read;
 	u32 fpSyncs;
 	u32 dmaPut;
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index a7c4e5e..093ab99 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -21,6 +21,7 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/console.h>
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
@@ -29,6 +30,7 @@
 #include <asm/pci-bridge.h>
 #endif
 #ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/machdep.h>
 #include <asm/backlight.h>
 #endif
 
@@ -296,6 +298,8 @@
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{PCI_VENDOR_ID_NVIDIA, 0x0252,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{PCI_VENDOR_ID_NVIDIA, 0x0313,
@@ -615,6 +619,30 @@
    return tweak;
 }
 
+static void nvidia_vga_protect(struct nvidia_par *par, int on)
+{
+	unsigned char tmp;
+
+	if (on) {
+		/*
+		 * Turn off screen and disable sequencer.
+		 */
+		tmp = NVReadSeq(par, 0x01);
+
+		NVWriteSeq(par, 0x00, 0x01);		/* Synchronous Reset */
+		NVWriteSeq(par, 0x01, tmp | 0x20);	/* disable the display */
+	} else {
+		/*
+		 * Reenable sequencer, then turn on screen.
+		 */
+
+		tmp = NVReadSeq(par, 0x01);
+
+		NVWriteSeq(par, 0x01, tmp & ~0x20);	/* reenable display */
+		NVWriteSeq(par, 0x00, 0x03);		/* End Reset */
+	}
+}
+
 static void nvidia_save_vga(struct nvidia_par *par,
 			    struct _riva_hw_state *state)
 {
@@ -643,9 +671,9 @@
 
 #undef DUMP_REG
 
-static void nvidia_write_regs(struct nvidia_par *par)
+static void nvidia_write_regs(struct nvidia_par *par,
+			      struct _riva_hw_state *state)
 {
-	struct _riva_hw_state *state = &par->ModeReg;
 	int i;
 
 	NVTRACE_ENTER();
@@ -694,32 +722,6 @@
 	NVTRACE_LEAVE();
 }
 
-static void nvidia_vga_protect(struct nvidia_par *par, int on)
-{
-	unsigned char tmp;
-
-	if (on) {
-		/*
-		 * Turn off screen and disable sequencer.
-		 */
-		tmp = NVReadSeq(par, 0x01);
-
-		NVWriteSeq(par, 0x00, 0x01);		/* Synchronous Reset */
-		NVWriteSeq(par, 0x01, tmp | 0x20);	/* disable the display */
-	} else {
-		/*
-		 * Reenable sequencer, then turn on screen.
-		 */
-
-		tmp = NVReadSeq(par, 0x01);
-
-		NVWriteSeq(par, 0x01, tmp & ~0x20);	/* reenable display */
-		NVWriteSeq(par, 0x00, 0x03);		/* End Reset */
-	}
-}
-
-
-
 static int nvidia_calc_regs(struct fb_info *info)
 {
 	struct nvidia_par *par = info->par;
@@ -1068,7 +1070,8 @@
 
 	nvidia_vga_protect(par, 1);
 
-	nvidia_write_regs(par);
+	nvidia_write_regs(par, &par->ModeReg);
+	NVSetStartAddress(par, 0);
 
 #if defined (__BIG_ENDIAN)
 	/* turn on LFB swapping */
@@ -1353,7 +1356,7 @@
 	NVWriteCrtc(par, 0x1a, vesa);
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if (par->FlatPanel && _machine == _MACH_Pmac) {
+	if (par->FlatPanel && machine_is(powermac)) {
 		set_backlight_enable(!blank);
 	}
 #endif
@@ -1377,6 +1380,57 @@
 	.fb_sync        = nvidiafb_sync,
 };
 
+#ifdef CONFIG_PM
+static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t state)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct nvidia_par *par = info->par;
+
+	acquire_console_sem();
+	par->pm_state = state.event;
+
+	if (state.event == PM_EVENT_FREEZE) {
+		dev->dev.power.power_state = state;
+	} else {
+		fb_set_suspend(info, 1);
+		nvidiafb_blank(FB_BLANK_POWERDOWN, info);
+		nvidia_write_regs(par, &par->SavedReg);
+		pci_save_state(dev);
+		pci_disable_device(dev);
+		pci_set_power_state(dev, pci_choose_state(dev, state));
+	}
+
+	release_console_sem();
+	return 0;
+}
+
+static int nvidiafb_resume(struct pci_dev *dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct nvidia_par *par = info->par;
+
+	acquire_console_sem();
+	pci_set_power_state(dev, PCI_D0);
+
+	if (par->pm_state != PM_EVENT_FREEZE) {
+		pci_restore_state(dev);
+		pci_enable_device(dev);
+		pci_set_master(dev);
+	}
+
+	par->pm_state = PM_EVENT_ON;
+	nvidiafb_set_par(info);
+	fb_set_suspend (info, 0);
+	nvidiafb_blank(FB_BLANK_UNBLANK, info);
+
+	release_console_sem();
+	return 0;
+}
+#else
+#define nvidiafb_suspend NULL
+#define nvidiafb_resume NULL
+#endif
+
 static int __devinit nvidia_set_fbinfo(struct fb_info *info)
 {
 	struct fb_monspecs *specs = &info->monspecs;
@@ -1688,7 +1742,7 @@
 	       info->fix.id,
 	       par->FbMapSize / (1024 * 1024), info->fix.smem_start);
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if (par->FlatPanel && _machine == _MACH_Pmac)
+	if (par->FlatPanel && machine_is(powermac))
 		register_backlight_controller(&nvidia_backlight_controller,
 					      par, "mnca");
 #endif
@@ -1720,8 +1774,6 @@
 	struct nvidia_par *par = info->par;
 
 	NVTRACE_ENTER();
-	if (!info)
-		return;
 
 	unregister_framebuffer(info);
 #ifdef CONFIG_MTRR
@@ -1798,8 +1850,10 @@
 static struct pci_driver nvidiafb_driver = {
 	.name = "nvidiafb",
 	.id_table = nvidiafb_pci_tbl,
-	.probe = nvidiafb_probe,
-	.remove = __exit_p(nvidiafb_remove),
+	.probe    = nvidiafb_probe,
+	.suspend  = nvidiafb_suspend,
+	.resume   = nvidiafb_resume,
+	.remove   = __exit_p(nvidiafb_remove),
 };
 
 /* ------------------------------------------------------------------------- *
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
index eeeac92..73e2d7d 100644
--- a/drivers/video/pmagb-b-fb.c
+++ b/drivers/video/pmagb-b-fb.c
@@ -228,7 +228,7 @@
 
 	freq1 = (par->osc0 * count1 + count0 / 2) / count0;
 	par->osc1 = freq1;
-	for (i = 0; i < sizeof(pmagbbfb_freqs) / sizeof(*pmagbbfb_freqs); i++)
+	for (i = 0; i < ARRAY_SIZE(pmagbbfb_freqs); i++)
 		if (freq1 >= pmagbbfb_freqs[i] -
 			     (pmagbbfb_freqs[i] + 128) / 256 &&
 		    freq1 <= pmagbbfb_freqs[i] +
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 53ad61f..809fc5e 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -232,9 +232,9 @@
 	if (var->yres < MIN_YRES)
 		var->yres = MIN_YRES;
 	if (var->xres > fbi->max_xres)
-		var->xres = fbi->max_xres;
+		return -EINVAL;
 	if (var->yres > fbi->max_yres)
-		var->yres = fbi->max_yres;
+		return -EINVAL;
 	var->xres_virtual =
 		max(var->xres_virtual, var->xres);
 	var->yres_virtual =
@@ -781,7 +781,7 @@
 	LCCR0 &= ~LCCR0_LDM;	/* Enable LCD Disable Done Interrupt */
 	LCCR0 |= LCCR0_DIS;	/* Disable LCD Controller */
 
-	schedule_timeout(20 * HZ / 1000);
+	schedule_timeout(200 * HZ / 1000);
 	remove_wait_queue(&fbi->ctrlr_wait, &wait);
 
 	/* disable LCD controller clock */
@@ -1274,7 +1274,7 @@
 	struct pxafb_mach_info *inf;
 	int ret;
 
-	dev_dbg(dev, "pxafb_probe\n");
+	dev_dbg(&dev->dev, "pxafb_probe\n");
 
 	inf = dev->dev.platform_data;
 	ret = -ENOMEM;
diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c
deleted file mode 100644
index db9fb90..0000000
--- a/drivers/video/radeonfb.c
+++ /dev/null
@@ -1,3167 +0,0 @@
-/*
- *	drivers/video/radeonfb.c
- *	framebuffer driver for ATI Radeon chipset video boards
- *
- *	Copyright 2000	Ani Joshi <ajoshi@kernel.crashing.org>
- *
- *
- *	ChangeLog:
- *	2000-08-03	initial version 0.0.1
- *	2000-09-10	more bug fixes, public release 0.0.5
- *	2001-02-19	mode bug fixes, 0.0.7
- *	2001-07-05	fixed scrolling issues, engine initialization,
- *			and minor mode tweaking, 0.0.9
- *	2001-09-07	Radeon VE support, Nick Kurshev
- *			blanking, pan_display, and cmap fixes, 0.1.0
- *	2001-10-10	Radeon 7500 and 8500 support, and experimental
- *			flat panel support, 0.1.1
- *	2001-11-17	Radeon M6 (ppc) support, Daniel Berlin, 0.1.2
- *	2001-11-18	DFP fixes, Kevin Hendricks, 0.1.3
- *	2001-11-29	more cmap, backlight fixes, Benjamin Herrenschmidt
- *	2002-01-18	DFP panel detection via BIOS, Michael Clark, 0.1.4
- *	2002-06-02	console switching, mode set fixes, accel fixes
- *	2002-06-03	MTRR support, Peter Horton, 0.1.5
- *	2002-09-21	rv250, r300, m9 initial support,
- *			added mirror option, 0.1.6
- *
- *	Special thanks to ATI DevRel team for their hardware donations.
- *
- */
-
-
-#define RADEON_VERSION	"0.1.6"
-
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#if defined(__powerpc__)
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include "macmodes.h"
-
-#ifdef CONFIG_NVRAM
-#include <linux/nvram.h>
-#endif
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
-
-#ifdef CONFIG_BOOTX_TEXT
-#include <asm/btext.h>
-#endif
-
-#ifdef CONFIG_ADB_PMU
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#endif
-
-#endif /* __powerpc__ */
-
-#ifdef CONFIG_MTRR
-#include <asm/mtrr.h>
-#endif
-
-#include <video/radeon.h>
-#include <linux/radeonfb.h>
-
-#define DEBUG  0
-
-#if DEBUG
-#define RTRACE		printk
-#else
-#define RTRACE		if(0) printk
-#endif
-
-// XXX
-#undef CONFIG_PMAC_PBOOK
-
-
-enum radeon_chips {
-	RADEON_QD,
-	RADEON_QE,
-	RADEON_QF,
-	RADEON_QG,
-	RADEON_QY,
-	RADEON_QZ,
-	RADEON_LW,
-	RADEON_LX,
-	RADEON_LY,
-	RADEON_LZ,
-	RADEON_QL,
-	RADEON_QN,
-	RADEON_QO,
-	RADEON_Ql,
-	RADEON_BB,
-	RADEON_QW,
-	RADEON_QX,
-	RADEON_Id,
-	RADEON_Ie,
-	RADEON_If,
-	RADEON_Ig,
-	RADEON_Ya,
-	RADEON_Yd,
-	RADEON_Ld,
-	RADEON_Le,
-	RADEON_Lf,
-	RADEON_Lg,
-	RADEON_ND,
-	RADEON_NE,
-	RADEON_NF,
-	RADEON_NG,
-	RADEON_QM
-};
-
-enum radeon_arch {
-	RADEON_R100,
-	RADEON_RV100,
-	RADEON_R200,
-	RADEON_RV200,
-	RADEON_RV250,
-	RADEON_R300,
-	RADEON_M6,
-	RADEON_M7,
-	RADEON_M9
-};
-
-static struct radeon_chip_info {
-	const char *name;
-	unsigned char arch;
-} radeon_chip_info[] __devinitdata = {
-	{ "QD", RADEON_R100 },
-	{ "QE", RADEON_R100 },
-	{ "QF", RADEON_R100 },
-	{ "QG", RADEON_R100 },
-	{ "VE QY", RADEON_RV100 },
-	{ "VE QZ", RADEON_RV100 },
-	{ "M7 LW", RADEON_M7 },
-	{ "M7 LX", RADEON_M7 },
-	{ "M6 LY", RADEON_M6 },
-	{ "M6 LZ", RADEON_M6 },
-	{ "8500 QL", RADEON_R200 },
-	{ "8500 QN", RADEON_R200 },
-	{ "8500 QO", RADEON_R200 },
-	{ "8500 Ql", RADEON_R200 },
-	{ "8500 BB", RADEON_R200 },
-	{ "7500 QW", RADEON_RV200 },
-	{ "7500 QX", RADEON_RV200 },
-	{ "9000 Id", RADEON_RV250 },
-	{ "9000 Ie", RADEON_RV250 },
-	{ "9000 If", RADEON_RV250 },
-	{ "9000 Ig", RADEON_RV250 },
-	{ "M9 Ld", RADEON_M9 },
-	{ "M9 Le", RADEON_M9 },
-	{ "M9 Lf", RADEON_M9 },
-	{ "M9 Lg", RADEON_M9 },
-	{ "9700 ND", RADEON_R300 },
-	{ "9700 NE", RADEON_R300 },
-	{ "9700 NF", RADEON_R300 },
-	{ "9700 NG", RADEON_R300 },
-	{ "9100 QM", RADEON_R200 }
-};
-
-
-enum radeon_montype
-{
-	MT_NONE,
-	MT_CRT,		/* CRT */
-	MT_LCD,		/* LCD */
-	MT_DFP,		/* DVI */
-	MT_CTV,		/* composite TV */
-	MT_STV		/* S-Video out */
-};
-
-
-static struct pci_device_id radeonfb_pci_table[] = {
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QD},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QE},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QF},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QG},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QY, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QY},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QZ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QZ},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LW},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LX},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LY, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LY},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LZ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LZ},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QL},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QN, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QN},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QO},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ql, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ql},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_BB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_BB},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QW},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QX},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Id},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ie, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ie},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_If, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_If},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ig, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ig},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ya, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ya},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Yd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Yd},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ld, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ld},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Le, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Le},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Lf, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Lf},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Lg, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Lg},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_ND, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_ND},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NE},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NF},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NG},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QM},
-	{ 0, }
-};
-MODULE_DEVICE_TABLE(pci, radeonfb_pci_table);
-
-
-typedef struct {
-	u16 reg;
-	u32 val;
-} reg_val;
-
-
-/* these common regs are cleared before mode setting so they do not
- * interfere with anything
- */
-static reg_val common_regs[] = {
-	{ OVR_CLR, 0 },	
-	{ OVR_WID_LEFT_RIGHT, 0 },
-	{ OVR_WID_TOP_BOTTOM, 0 },
-	{ OV0_SCALE_CNTL, 0 },
-	{ SUBPIC_CNTL, 0 },
-	{ VIPH_CONTROL, 0 },
-	{ I2C_CNTL_1, 0 },
-	{ GEN_INT_CNTL, 0 },
-	{ CAP0_TRIG_CNTL, 0 },
-};
-
-static reg_val common_regs_m6[] = {
-	{ OVR_CLR,      0 },
-	{ OVR_WID_LEFT_RIGHT,   0 },
-	{ OVR_WID_TOP_BOTTOM,   0 },
-	{ OV0_SCALE_CNTL,   0 },
-	{ SUBPIC_CNTL,      0 },
-	{ GEN_INT_CNTL,     0 },
-	{ CAP0_TRIG_CNTL,   0 } 
-};
-
-typedef struct {
-        u8 clock_chip_type;
-        u8 struct_size;
-        u8 accelerator_entry;
-        u8 VGA_entry;
-        u16 VGA_table_offset;
-        u16 POST_table_offset;
-        u16 XCLK;
-        u16 MCLK;
-        u8 num_PLL_blocks;
-        u8 size_PLL_blocks;
-        u16 PCLK_ref_freq;
-        u16 PCLK_ref_divider;
-        u32 PCLK_min_freq;
-        u32 PCLK_max_freq;
-        u16 MCLK_ref_freq;
-        u16 MCLK_ref_divider;
-        u32 MCLK_min_freq;
-        u32 MCLK_max_freq;
-        u16 XCLK_ref_freq;
-        u16 XCLK_ref_divider;
-        u32 XCLK_min_freq;
-        u32 XCLK_max_freq;
-} __attribute__ ((packed)) PLL_BLOCK;
-
-
-struct pll_info {
-	int ppll_max;
-	int ppll_min;
-	int xclk;
-	int ref_div;
-	int ref_clk;
-};
-
-
-struct ram_info {
-	int ml;
-	int mb;
-	int trcd;
-	int trp;
-	int twr;
-	int cl;
-	int tr2w;
-	int loop_latency;
-	int rloop;
-};
-
-
-struct radeon_regs {
-	/* CRTC regs */
-	u32 crtc_h_total_disp;
-	u32 crtc_h_sync_strt_wid;
-	u32 crtc_v_total_disp;
-	u32 crtc_v_sync_strt_wid;
-	u32 crtc_pitch;
-	u32 crtc_gen_cntl;
-	u32 crtc_ext_cntl;
-	u32 dac_cntl;
-
-	u32 flags;
-	u32 pix_clock;
-	int xres, yres;
-
-	/* DDA regs */
-	u32 dda_config;
-	u32 dda_on_off;
-
-	/* PLL regs */
-	u32 ppll_div_3;
-	u32 ppll_ref_div;
-	u32 vclk_ecp_cntl;
-	
-	/* Flat panel regs */
-	u32 fp_crtc_h_total_disp;
-	u32 fp_crtc_v_total_disp;
-	u32 fp_gen_cntl;
-	u32 fp_h_sync_strt_wid;
-	u32 fp_horz_stretch;
-	u32 fp_panel_cntl;
-	u32 fp_v_sync_strt_wid;
-	u32 fp_vert_stretch;
-	u32 lvds_gen_cntl;
-	u32 lvds_pll_cntl;
-	u32 tmds_crc;
-	u32 tmds_transmitter_cntl;
-
-#if defined(__BIG_ENDIAN)
-	u32 surface_cntl;
-#endif
-};
-
-
-struct radeonfb_info {
-	struct fb_info info;
-
-	struct radeon_regs state;
-	struct radeon_regs init_state;
-
-	char name[32];
-	char ram_type[12];
-
-	unsigned long mmio_base_phys;
-	unsigned long fb_base_phys;
-
-	void __iomem *mmio_base;
-	void __iomem *fb_base;
-
-	struct pci_dev *pdev;
-
-	unsigned char *EDID;
-	unsigned char __iomem *bios_seg;
-
-	u32 pseudo_palette[17];
-	struct { u8 red, green, blue, pad; } palette[256];
-
-	int chipset;
-	unsigned char arch;
-	int video_ram;
-	u8 rev;
-	int pitch, bpp, depth;
-	int xres, yres, pixclock;
-	int xres_virtual, yres_virtual;
-	u32 accel_flags;
-
-	int use_default_var;
-	int got_dfpinfo;
-
-	int hasCRTC2;
-	int crtDisp_type;
-	int dviDisp_type;
-
-	int panel_xres, panel_yres;
-	int clock;
-	int hOver_plus, hSync_width, hblank;
-	int vOver_plus, vSync_width, vblank;
-	int hAct_high, vAct_high, interlaced;
-	int synct, misc;
-
-	u32 dp_gui_master_cntl;
-
-	struct pll_info pll;
-	int pll_output_freq, post_div, fb_div;
-
-	struct ram_info ram;
-
-	int mtrr_hdl;
-
-#ifdef CONFIG_PMAC_PBOOK
-	int pm_reg;
-	u32 save_regs[64];
-	u32 mdll, mdll2;
-#endif /* CONFIG_PMAC_PBOOK */
-	int asleep;
-	
-	struct radeonfb_info *next;
-};
-
-
-static struct fb_var_screeninfo radeonfb_default_var = {
-        640, 480, 640, 480, 0, 0, 8, 0,
-        {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-        0, 0, -1, -1, 0, 39721, 40, 24, 32, 11, 96, 2,
-        0, FB_VMODE_NONINTERLACED
-};
-
-/*
- * IO macros
- */
-
-#define INREG8(addr)		readb((rinfo->mmio_base)+addr)
-#define OUTREG8(addr,val)	writeb(val, (rinfo->mmio_base)+addr)
-#define INREG(addr)		readl((rinfo->mmio_base)+addr)
-#define OUTREG(addr,val)	writel(val, (rinfo->mmio_base)+addr)
-
-#define OUTPLL(addr,val)	\
-	do {	\
-		OUTREG8(CLOCK_CNTL_INDEX, (addr & 0x0000003f) | 0x00000080); \
-		OUTREG(CLOCK_CNTL_DATA, val); \
-	} while(0)
-
-#define OUTPLLP(addr,val,mask)  					\
-	do {								\
-		unsigned int _tmp = INPLL(addr);			\
-		_tmp &= (mask);						\
-		_tmp |= (val);						\
-		OUTPLL(addr, _tmp);					\
-	} while (0)
-
-#define OUTREGP(addr,val,mask)  					\
-	do {								\
-		unsigned int _tmp = INREG(addr);			\
-		_tmp &= (mask);						\
-		_tmp |= (val);						\
-		OUTREG(addr, _tmp);					\
-	} while (0)
-
-
-static __inline__ u32 _INPLL(struct radeonfb_info *rinfo, u32 addr)
-{
-	OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
-	return (INREG(CLOCK_CNTL_DATA));
-}
-
-#define INPLL(addr)		_INPLL(rinfo, addr)
-
-#define PRIMARY_MONITOR(rinfo)	((rinfo->dviDisp_type != MT_NONE) &&	\
-				 (rinfo->dviDisp_type != MT_STV) &&	\
-				 (rinfo->dviDisp_type != MT_CTV) ?	\
-				 rinfo->dviDisp_type : rinfo->crtDisp_type)
-
-static char *GET_MON_NAME(int type)
-{
-	char *pret = NULL;
-
-	switch (type) {
-		case MT_NONE:
-			pret = "no";
-			break;
-		case MT_CRT:
-			pret = "CRT";
-			break;
-		case MT_DFP:
-			pret = "DFP";
-			break;
-		case MT_LCD:
-			pret = "LCD";
-			break;
-		case MT_CTV:
-			pret = "CTV";
-			break;
-		case MT_STV:
-			pret = "STV";
-			break;
-	}
-
-	return pret;
-}
-
-
-/*
- * 2D engine routines
- */
-
-static __inline__ void radeon_engine_flush (struct radeonfb_info *rinfo)
-{
-	int i;
-
-	/* initiate flush */
-	OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
-	        ~RB2D_DC_FLUSH_ALL);
-
-	for (i=0; i < 2000000; i++) {
-		if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
-			break;
-	}
-}
-
-
-static __inline__ void _radeon_fifo_wait (struct radeonfb_info *rinfo, int entries)
-{
-	int i;
-
-	for (i=0; i<2000000; i++)
-		if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
-			return;
-}
-
-
-static __inline__ void _radeon_engine_idle (struct radeonfb_info *rinfo)
-{
-	int i;
-
-	/* ensure FIFO is empty before waiting for idle */
-	_radeon_fifo_wait (rinfo, 64);
-
-	for (i=0; i<2000000; i++) {
-		if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) {
-			radeon_engine_flush (rinfo);
-			return;
-		}
-	}
-}
-
-
-#define radeon_engine_idle()		_radeon_engine_idle(rinfo)
-#define radeon_fifo_wait(entries)	_radeon_fifo_wait(rinfo,entries)
-
-
-
-/*
- * helper routines
- */
-
-static __inline__ u32 radeon_get_dstbpp(u16 depth)
-{
-	switch (depth) {
-		case 8:
-			return DST_8BPP;
-		case 15:
-			return DST_15BPP;
-		case 16:
-			return DST_16BPP;
-		case 32:
-			return DST_32BPP;
-		default:
-			return 0;
-	}
-}
-
-
-static inline int var_to_depth(const struct fb_var_screeninfo *var)
-{
-	if (var->bits_per_pixel != 16)
-		return var->bits_per_pixel;
-	return (var->green.length == 6) ? 16 : 15;
-}
-
-
-static void _radeon_engine_reset(struct radeonfb_info *rinfo)
-{
-	u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset;
-
-	radeon_engine_flush (rinfo);
-
-	clock_cntl_index = INREG(CLOCK_CNTL_INDEX);
-	mclk_cntl = INPLL(MCLK_CNTL);
-
-	OUTPLL(MCLK_CNTL, (mclk_cntl |
-			   FORCEON_MCLKA |
-			   FORCEON_MCLKB |
-			   FORCEON_YCLKA |
-			   FORCEON_YCLKB |
-			   FORCEON_MC |
-			   FORCEON_AIC));
-	rbbm_soft_reset = INREG(RBBM_SOFT_RESET);
-
-	OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset |
-				SOFT_RESET_CP |
-				SOFT_RESET_HI |
-				SOFT_RESET_SE |
-				SOFT_RESET_RE |
-				SOFT_RESET_PP |
-				SOFT_RESET_E2 |
-				SOFT_RESET_RB);
-	INREG(RBBM_SOFT_RESET);
-	OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset & (u32)
-				~(SOFT_RESET_CP |
-				  SOFT_RESET_HI |
-				  SOFT_RESET_SE |
-				  SOFT_RESET_RE |
-				  SOFT_RESET_PP |
-				  SOFT_RESET_E2 |
-				  SOFT_RESET_RB));
-	INREG(RBBM_SOFT_RESET);
-
-	OUTPLL(MCLK_CNTL, mclk_cntl);
-	OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index);
-	OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset);
-
-	return;
-}
-
-#define radeon_engine_reset()		_radeon_engine_reset(rinfo)
-
-
-static __inline__ int round_div(int num, int den)
-{
-        return (num + (den / 2)) / den;
-}
-
-
-
-static __inline__ int min_bits_req(int val)
-{
-        int bits_req = 0;
-                
-        if (val == 0)
-                bits_req = 1;
-                        
-        while (val) {
-                val >>= 1;
-                bits_req++;
-        }       
-
-        return (bits_req);
-}
-
-
-static __inline__ int _max(int val1, int val2)
-{
-        if (val1 >= val2)
-                return val1;
-        else
-                return val2;
-}                       
-
-
-
-/*
- * globals
- */
-
-#ifndef MODULE
-static char *mode_option;
-#endif
-
-static char noaccel = 0;
-static char mirror = 0;
-static int panel_yres = 0;
-static char force_dfp = 0;
-static struct radeonfb_info *board_list = NULL;
-static char nomtrr = 0;
-
-/*
- * prototypes
- */
-
-static void radeon_save_state (struct radeonfb_info *rinfo,
-                               struct radeon_regs *save);
-static void radeon_engine_init (struct radeonfb_info *rinfo);
-static void radeon_write_mode (struct radeonfb_info *rinfo,
-                               struct radeon_regs *mode);
-static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo);
-static int __devinit radeon_init_disp (struct radeonfb_info *rinfo);
-static int radeon_init_disp_var (struct radeonfb_info *rinfo, struct fb_var_screeninfo *var);
-static void __iomem *radeon_find_rom(struct radeonfb_info *rinfo);
-static void radeon_get_pllinfo(struct radeonfb_info *rinfo, void __iomem *bios_seg);
-static void radeon_get_moninfo (struct radeonfb_info *rinfo);
-static int radeon_get_dfpinfo (struct radeonfb_info *rinfo);
-static int radeon_get_dfpinfo_BIOS(struct radeonfb_info *rinfo);
-static void radeon_get_EDID(struct radeonfb_info *rinfo);
-static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo);
-static void radeon_update_default_var(struct radeonfb_info *rinfo);
-
-#ifdef CONFIG_PPC_OF
-
-static int radeon_read_OF (struct radeonfb_info *rinfo);
-static int radeon_get_EDID_OF(struct radeonfb_info *rinfo);
-extern struct device_node *pci_device_to_OF_node(struct pci_dev *dev);
-
-#ifdef CONFIG_PMAC_PBOOK
-int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier radeon_sleep_notifier = {
-	radeon_sleep_notify, SLEEP_LEVEL_VIDEO,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int radeon_set_backlight_enable(int on, int level, void *data);
-static int radeon_set_backlight_level(int level, void *data);
-static struct backlight_controller radeon_backlight_controller = {
-	radeon_set_backlight_enable,
-	radeon_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-#endif /* CONFIG_PPC_OF */
-
-
-static void __iomem *radeon_find_rom(struct radeonfb_info *rinfo)
-{       
-#if defined(__i386__)
-        u32  segstart;
-        char __iomem *rom_base;
-        char __iomem *rom;
-        int  stage;
-        int  i,j;       
-        char aty_rom_sig[] = "761295520";
-        char *radeon_sig[] = {
-          "RG6",
-          "RADEON"
-        };
-                                                
-        for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
-                        
-                stage = 1;
-                
-                rom_base = ioremap(segstart, 0x1000);
-
-                if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa))
-                        stage = 2;
-                
-                    
-                if (stage != 2) {
-                        iounmap(rom_base);
-                        continue;
-                }
-                                              
-                rom = rom_base;
-                     
-                for (i = 0; (i < 128 - strlen(aty_rom_sig)) && (stage != 3); i++) {
-                        if (aty_rom_sig[0] == *rom)
-                                if (strncmp(aty_rom_sig, rom,
-                                                strlen(aty_rom_sig)) == 0)
-                                        stage = 3;
-                        rom++;
-                }
-                if (stage != 3) {
-                        iounmap(rom_base);
-                        continue;
-                }
-                rom = rom_base;
-        
-                for (i = 0; (i < 512) && (stage != 4); i++) {
-                    for(j = 0;j < sizeof(radeon_sig)/sizeof(char *);j++) {
-                        if (radeon_sig[j][0] == *rom)
-                                if (strncmp(radeon_sig[j], rom,
-                                            strlen(radeon_sig[j])) == 0) {
-                                              stage = 4;
-                                              break;
-                                            }
-                    }                           
-                        rom++;
-                }       
-                if (stage != 4) {
-                        iounmap(rom_base);
-                        continue;
-                }       
-                
-                return rom_base;
-        }
-#endif          
-        return NULL;
-}
-
-
-
-
-static void radeon_get_pllinfo(struct radeonfb_info *rinfo, void __iomem *bios_seg)
-{
-        void __iomem *bios_header;
-        void __iomem *header_ptr;
-        u16 bios_header_offset, pll_info_offset;
-        PLL_BLOCK pll;
-
-	if (bios_seg) {
-	        bios_header = bios_seg + 0x48L;
-       		header_ptr  = bios_header;
-        
-        	bios_header_offset = readw(header_ptr);
-	        bios_header = bios_seg + bios_header_offset;
-        	bios_header += 0x30;
-        
-        	header_ptr = bios_header;
-        	pll_info_offset = readw(header_ptr);
-        	header_ptr = bios_seg + pll_info_offset;
-        
-        	memcpy_fromio(&pll, header_ptr, 50);
-        
-        	rinfo->pll.xclk = (u32)pll.XCLK;
-        	rinfo->pll.ref_clk = (u32)pll.PCLK_ref_freq;
-        	rinfo->pll.ref_div = (u32)pll.PCLK_ref_divider;
-        	rinfo->pll.ppll_min = pll.PCLK_min_freq;
-        	rinfo->pll.ppll_max = pll.PCLK_max_freq;
-
-		printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from BIOS\n",
-			rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
-	} else {
-#ifdef CONFIG_PPC_OF
-		if (radeon_read_OF(rinfo)) {
-			unsigned int tmp, Nx, M, ref_div, xclk;
-
-			tmp = INPLL(M_SPLL_REF_FB_DIV);
-			ref_div = INPLL(PPLL_REF_DIV) & 0x3ff;
-
-			Nx = (tmp & 0xff00) >> 8;
-			M = (tmp & 0xff);
-			xclk = ((((2 * Nx * rinfo->pll.ref_clk) + (M)) /
-				(2 * M)));
-
-			rinfo->pll.xclk = xclk;
-			rinfo->pll.ref_div = ref_div;
-			rinfo->pll.ppll_min = 12000;
-			rinfo->pll.ppll_max = 35000;
-
-			printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from OF\n",
-				rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
-
-			return;
-		}
-#endif
-		/* no BIOS or BIOS not found, use defaults */
-		switch (rinfo->chipset) {
-			case PCI_DEVICE_ID_ATI_RADEON_QW:
-			case PCI_DEVICE_ID_ATI_RADEON_QX:
-				rinfo->pll.ppll_max = 35000;
-				rinfo->pll.ppll_min = 12000;
-				rinfo->pll.xclk = 23000;
-				rinfo->pll.ref_div = 12;
-				rinfo->pll.ref_clk = 2700;
-				break;
-			case PCI_DEVICE_ID_ATI_RADEON_QL:
-			case PCI_DEVICE_ID_ATI_RADEON_QN:
-			case PCI_DEVICE_ID_ATI_RADEON_QO:
-			case PCI_DEVICE_ID_ATI_RADEON_Ql:
-			case PCI_DEVICE_ID_ATI_RADEON_BB:
-				rinfo->pll.ppll_max = 35000;
-				rinfo->pll.ppll_min = 12000;
-				rinfo->pll.xclk = 27500;
-				rinfo->pll.ref_div = 12;
-				rinfo->pll.ref_clk = 2700;
-				break;
-			case PCI_DEVICE_ID_ATI_RADEON_Id:
-			case PCI_DEVICE_ID_ATI_RADEON_Ie:
-			case PCI_DEVICE_ID_ATI_RADEON_If:
-			case PCI_DEVICE_ID_ATI_RADEON_Ig:
-				rinfo->pll.ppll_max = 35000;
-				rinfo->pll.ppll_min = 12000;
-				rinfo->pll.xclk = 25000;
-				rinfo->pll.ref_div = 12;
-				rinfo->pll.ref_clk = 2700;
-				break;
-			case PCI_DEVICE_ID_ATI_RADEON_ND:
-			case PCI_DEVICE_ID_ATI_RADEON_NE:
-			case PCI_DEVICE_ID_ATI_RADEON_NF:
-			case PCI_DEVICE_ID_ATI_RADEON_NG:
-				rinfo->pll.ppll_max = 40000;
-				rinfo->pll.ppll_min = 20000;
-				rinfo->pll.xclk = 27000;
-				rinfo->pll.ref_div = 12;
-				rinfo->pll.ref_clk = 2700;
-				break;
-			case PCI_DEVICE_ID_ATI_RADEON_QD:
-			case PCI_DEVICE_ID_ATI_RADEON_QE:
-			case PCI_DEVICE_ID_ATI_RADEON_QF:
-			case PCI_DEVICE_ID_ATI_RADEON_QG:
-			default:
-				rinfo->pll.ppll_max = 35000;
-				rinfo->pll.ppll_min = 12000;
-				rinfo->pll.xclk = 16600;
-				rinfo->pll.ref_div = 67;
-				rinfo->pll.ref_clk = 2700;
-				break;
-		}
-
-		printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d defaults\n",
-			rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
-	}
-}
-
-
-static void radeon_get_moninfo (struct radeonfb_info *rinfo)
-{
-	unsigned int tmp;
-
-	if (force_dfp) {
-		rinfo->dviDisp_type = MT_DFP;
-		return;
-	}
-
-	tmp = INREG(BIOS_4_SCRATCH);
-	printk(KERN_DEBUG "radeon_get_moninfo: bios 4 scratch = %x\n", tmp);
-	
-	if (rinfo->hasCRTC2) {
-		/* primary DVI port */
-		if (tmp & 0x08)
-			rinfo->dviDisp_type = MT_DFP;
-		else if (tmp & 0x4)
-			rinfo->dviDisp_type = MT_LCD;
-		else if (tmp & 0x200)
-			rinfo->dviDisp_type = MT_CRT;
-		else if (tmp & 0x10)
-			rinfo->dviDisp_type = MT_CTV;
-		else if (tmp & 0x20)
-			rinfo->dviDisp_type = MT_STV;
-
-		/* secondary CRT port */
-		if (tmp & 0x2)
-			rinfo->crtDisp_type = MT_CRT;
-		else if (tmp & 0x800)
-			rinfo->crtDisp_type = MT_DFP;
-		else if (tmp & 0x400)
-			rinfo->crtDisp_type = MT_LCD;
-		else if (tmp & 0x1000)
-			rinfo->crtDisp_type = MT_CTV;
-		else if (tmp & 0x2000)
-			rinfo->crtDisp_type = MT_STV;
-	} else {
-		rinfo->dviDisp_type = MT_NONE;
-
-		tmp = INREG(FP_GEN_CNTL);
-
-		if (tmp & FP_EN_TMDS)
-			rinfo->crtDisp_type = MT_DFP;
-		else
-			rinfo->crtDisp_type = MT_CRT;
-	}
-}
-
-
-
-static void radeon_get_EDID(struct radeonfb_info *rinfo)
-{
-#ifdef CONFIG_PPC_OF
-	if (!radeon_get_EDID_OF(rinfo))
-		RTRACE("radeonfb: could not retrieve EDID from OF\n");
-#else
-	/* XXX use other methods later */
-#endif
-}
-
-
-#ifdef CONFIG_PPC_OF
-static int radeon_get_EDID_OF(struct radeonfb_info *rinfo)
-{
-        struct device_node *dp;
-        unsigned char *pedid = NULL;
-        static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", NULL };
-        int i;  
-
-        dp = pci_device_to_OF_node(rinfo->pdev);
-        while (dp != NULL) {
-                for (i = 0; propnames[i] != NULL; ++i) {
-                        pedid = (unsigned char *)
-                                get_property(dp, propnames[i], NULL);
-                        if (pedid != NULL) {
-                                rinfo->EDID = pedid;
-                                return 1;
-                        }
-                }
-                dp = dp->child;
-        }
-        return 0;
-}
-#endif /* CONFIG_PPC_OF */
-
-
-static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo)
-{
-	unsigned char *block = rinfo->EDID;
-
-	if (!block)
-		return 0;
-
-	/* jump to the detailed timing block section */
-	block += 54;
-
-	rinfo->clock = (block[0] + (block[1] << 8));
-	rinfo->panel_xres = (block[2] + ((block[4] & 0xf0) << 4));
-	rinfo->hblank = (block[3] + ((block[4] & 0x0f) << 8));
-	rinfo->panel_yres = (block[5] + ((block[7] & 0xf0) << 4));
-	rinfo->vblank = (block[6] + ((block[7] & 0x0f) << 8));
-	rinfo->hOver_plus = (block[8] + ((block[11] & 0xc0) << 2));
-	rinfo->hSync_width = (block[9] + ((block[11] & 0x30) << 4));
-	rinfo->vOver_plus = ((block[10] >> 4) + ((block[11] & 0x0c) << 2));
-	rinfo->vSync_width = ((block[10] & 0x0f) + ((block[11] & 0x03) << 4));
-	rinfo->interlaced = ((block[17] & 0x80) >> 7);
-	rinfo->synct = ((block[17] & 0x18) >> 3);
-	rinfo->misc = ((block[17] & 0x06) >> 1);
-	rinfo->hAct_high = rinfo->vAct_high = 0;
-	if (rinfo->synct == 3) {
-		if (rinfo->misc & 2)
-			rinfo->hAct_high = 1;
-		if (rinfo->misc & 1)
-			rinfo->vAct_high = 1;
-	}
-
-	printk("radeonfb: detected DFP panel size from EDID: %dx%d\n",
-		rinfo->panel_xres, rinfo->panel_yres);
-
-	rinfo->got_dfpinfo = 1;
-
-	return 1;
-}
-
-
-static void radeon_update_default_var(struct radeonfb_info *rinfo)
-{
-	struct fb_var_screeninfo *var = &radeonfb_default_var;
-
-	var->xres = rinfo->panel_xres;
-	var->yres = rinfo->panel_yres;
-	var->xres_virtual = rinfo->panel_xres;
-	var->yres_virtual = rinfo->panel_yres;
-	var->xoffset = var->yoffset = 0;
-	var->bits_per_pixel = 8;
-	var->pixclock = 100000000 / rinfo->clock;
-	var->left_margin = (rinfo->hblank - rinfo->hOver_plus - rinfo->hSync_width);
-	var->right_margin = rinfo->hOver_plus;
-	var->upper_margin = (rinfo->vblank - rinfo->vOver_plus - rinfo->vSync_width);
-	var->lower_margin = rinfo->vOver_plus;
-	var->hsync_len = rinfo->hSync_width;
-	var->vsync_len = rinfo->vSync_width;
-	var->sync = 0;
-	if (rinfo->synct == 3) {
-		if (rinfo->hAct_high)
-			var->sync |= FB_SYNC_HOR_HIGH_ACT;
-		if (rinfo->vAct_high)
-			var->sync |= FB_SYNC_VERT_HIGH_ACT;
-	}
-
-	var->vmode = 0;
-	if (rinfo->interlaced)
-		var->vmode |= FB_VMODE_INTERLACED;
-
-	rinfo->use_default_var = 1;
-}
-
-
-static int radeon_get_dfpinfo_BIOS(struct radeonfb_info *rinfo)
-{
-	char __iomem *fpbiosstart, *tmp, *tmp0;
-	char stmp[30];
-	int i;
-
-	if (!rinfo->bios_seg)
-		return 0;
-
-	if (!(fpbiosstart = rinfo->bios_seg + readw(rinfo->bios_seg + 0x48))) {
-		printk("radeonfb: Failed to detect DFP panel info using BIOS\n");
-		return 0;
-	}
-
-	if (!(tmp = rinfo->bios_seg + readw(fpbiosstart + 0x40))) {
-		printk("radeonfb: Failed to detect DFP panel info using BIOS\n");
-		return 0;
-	}
-
-	for(i=0; i<24; i++)
-		stmp[i] = readb(tmp+i+1);
-	stmp[24] = 0;
-	printk("radeonfb: panel ID string: %s\n", stmp);
-	rinfo->panel_xres = readw(tmp + 25);
-	rinfo->panel_yres = readw(tmp + 27);
-	printk("radeonfb: detected DFP panel size from BIOS: %dx%d\n",
-		rinfo->panel_xres, rinfo->panel_yres);
-
-	for(i=0; i<32; i++) {
-		tmp0 = rinfo->bios_seg + readw(tmp+64+i*2);
-		if (tmp0 == 0)
-			break;
-		if ((readw(tmp0) == rinfo->panel_xres) &&
-		    (readw(tmp0+2) == rinfo->panel_yres)) {
-			rinfo->hblank = (readw(tmp0+17) - readw(tmp0+19)) * 8;
-			rinfo->hOver_plus = ((readw(tmp0+21) - readw(tmp0+19) -1) * 8) & 0x7fff;
-			rinfo->hSync_width = readb(tmp0+23) * 8;
-			rinfo->vblank = readw(tmp0+24) - readw(tmp0+26);
-			rinfo->vOver_plus = (readw(tmp0+28) & 0x7ff) - readw(tmp0+26);
-			rinfo->vSync_width = (readw(tmp0+28) & 0xf800) >> 11;
-			rinfo->clock = readw(tmp0+9);
-
-			rinfo->got_dfpinfo = 1;
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-
-
-static int radeon_get_dfpinfo (struct radeonfb_info *rinfo)
-{
-	unsigned int tmp;
-	unsigned short a, b;
-
-	if (radeon_get_dfpinfo_BIOS(rinfo))
-		radeon_update_default_var(rinfo);
-
-	if (radeon_dfp_parse_EDID(rinfo))
-		radeon_update_default_var(rinfo);
-
-	if (!rinfo->got_dfpinfo) {
-		/*
-		 * it seems all else has failed now and we
-		 * resort to probing registers for our DFP info
-	         */
-		if (panel_yres) {
-			rinfo->panel_yres = panel_yres;
-		} else {
-			tmp = INREG(FP_VERT_STRETCH);
-			tmp &= 0x00fff000;
-			rinfo->panel_yres = (unsigned short)(tmp >> 0x0c) + 1;
-		}
-
-		switch (rinfo->panel_yres) {
-			case 480:
-				rinfo->panel_xres = 640;
-				break;
-			case 600:
-				rinfo->panel_xres = 800;
-				break;
-			case 768:
-#if defined(__powerpc__)
-				if (rinfo->dviDisp_type == MT_LCD)
-					rinfo->panel_xres = 1152;
-				else
-#endif
-				rinfo->panel_xres = 1024;
-				break;
-			case 1024:
-				rinfo->panel_xres = 1280;
-				break;
-			case 1050:
-				rinfo->panel_xres = 1400;
-				break;
-			case 1200:
-				rinfo->panel_xres = 1600;
-				break;
-			default:
-				printk("radeonfb: Failed to detect DFP panel size\n");
-				return 0;
-		}
-
-		printk("radeonfb: detected DFP panel size from registers: %dx%d\n",
-			rinfo->panel_xres, rinfo->panel_yres);
-
-		tmp = INREG(FP_CRTC_H_TOTAL_DISP);
-		a = (tmp & FP_CRTC_H_TOTAL_MASK) + 4;
-		b = (tmp & 0x01ff0000) >> FP_CRTC_H_DISP_SHIFT;
-		rinfo->hblank = (a - b + 1) * 8;
-
-		tmp = INREG(FP_H_SYNC_STRT_WID);
-		rinfo->hOver_plus = (unsigned short) ((tmp & FP_H_SYNC_STRT_CHAR_MASK) >>
-					FP_H_SYNC_STRT_CHAR_SHIFT) - b - 1;
-		rinfo->hOver_plus *= 8;
-		rinfo->hSync_width = (unsigned short) ((tmp & FP_H_SYNC_WID_MASK) >>
-					FP_H_SYNC_WID_SHIFT);
-		rinfo->hSync_width *= 8;
-		tmp = INREG(FP_CRTC_V_TOTAL_DISP);
-		a = (tmp & FP_CRTC_V_TOTAL_MASK) + 1;
-		b = (tmp & FP_CRTC_V_DISP_MASK) >> FP_CRTC_V_DISP_SHIFT;
-		rinfo->vblank = a - b /* + 24 */ ;
-
-		tmp = INREG(FP_V_SYNC_STRT_WID);
-		rinfo->vOver_plus = (unsigned short) (tmp & FP_V_SYNC_STRT_MASK)
-					- b + 1;
-		rinfo->vSync_width = (unsigned short) ((tmp & FP_V_SYNC_WID_MASK) >>
-					FP_V_SYNC_WID_SHIFT);
-
-		return 1;
-	}
-
-	return 1;
-}
-
-
-#ifdef CONFIG_PPC_OF
-static int radeon_read_OF (struct radeonfb_info *rinfo)
-{
-	struct device_node *dp;
-	unsigned int *xtal;
-
-	dp = pci_device_to_OF_node(rinfo->pdev);
-
-	xtal = (unsigned int *) get_property(dp, "ATY,RefCLK", NULL);
-
-	rinfo->pll.ref_clk = *xtal / 10;
-
-	if (*xtal)
-		return 1;
-	else
-		return 0;
-}
-#endif	
-
-
-static void radeon_engine_init (struct radeonfb_info *rinfo)
-{
-	u32 temp;
-
-	/* disable 3D engine */
-	OUTREG(RB3D_CNTL, 0);
-
-	radeon_engine_reset ();
-
-	radeon_fifo_wait (1);
-	OUTREG(RB2D_DSTCACHE_MODE, 0);
-
-	radeon_fifo_wait (1);
-	temp = INREG(DEFAULT_PITCH_OFFSET);
-	OUTREG(DEFAULT_PITCH_OFFSET, ((temp & 0xc0000000) | 
-				      (rinfo->pitch << 0x16)));
-
-	radeon_fifo_wait (1);
-	OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN);
-
-	radeon_fifo_wait (1);
-	OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX |
-					 DEFAULT_SC_BOTTOM_MAX));
-
-	temp = radeon_get_dstbpp(rinfo->depth);
-	rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS);
-	radeon_fifo_wait (1);
-	OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl |
-				    GMC_BRUSH_SOLID_COLOR |
-				    GMC_SRC_DATATYPE_COLOR));
-
-	radeon_fifo_wait (7);
-
-	/* clear line drawing regs */
-	OUTREG(DST_LINE_START, 0);
-	OUTREG(DST_LINE_END, 0);
-
-	/* set brush color regs */
-	OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff);
-	OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000);
-
-	/* set source color regs */
-	OUTREG(DP_SRC_FRGD_CLR, 0xffffffff);
-	OUTREG(DP_SRC_BKGD_CLR, 0x00000000);
-
-	/* default write mask */
-	OUTREG(DP_WRITE_MSK, 0xffffffff);
-
-	radeon_engine_idle ();
-}
-
-
-static int __devinit radeon_init_disp (struct radeonfb_info *rinfo)
-{
-        struct fb_info *info = &rinfo->info;
-	struct fb_var_screeninfo var;
-
-        var = radeonfb_default_var;
-        if ((radeon_init_disp_var(rinfo, &var)) < 0)
-                return -1;
-
-	rinfo->depth = var_to_depth(&var);
-	rinfo->bpp = var.bits_per_pixel;
-        
-	info->var = var;
-	fb_alloc_cmap(&info->cmap, 256, 0);
-
-	var.activate = FB_ACTIVATE_NOW;
-        return 0;
-}
-
-
-static int radeon_init_disp_var (struct radeonfb_info *rinfo,
-				 struct fb_var_screeninfo *var)
-{
-#ifndef MODULE
-        if (mode_option)
-                fb_find_mode (var, &rinfo->info, mode_option,
-                              NULL, 0, NULL, 8);
-        else
-#endif
-	if (rinfo->use_default_var)
-		/* We will use the modified default far */
-		*var = radeonfb_default_var;
-	else
-
-                fb_find_mode (var, &rinfo->info, "640x480-8@60",
-                              NULL, 0, NULL, 0);
-
-	if (noaccel)
-		var->accel_flags &= ~FB_ACCELF_TEXT;
-	else
-		var->accel_flags |= FB_ACCELF_TEXT;
- 
-        return 0;
-}
-
-
-static int radeon_do_maximize(struct radeonfb_info *rinfo,
-                                struct fb_var_screeninfo *var,
-                                struct fb_var_screeninfo *v,
-                                int nom, int den)
-{
-        static struct {
-                int xres, yres;
-        } modes[] = {
-                {1600, 1280},
-                {1280, 1024},
-                {1024, 768},
-                {800, 600},
-                {640, 480},
-                {-1, -1}
-        };
-        int i;
-  
-        /* use highest possible virtual resolution */
-        if (v->xres_virtual == -1 && v->yres_virtual == -1) {
-                printk("radeonfb: using max available virtual resolution\n");
-                for (i=0; modes[i].xres != -1; i++) {
-                        if (modes[i].xres * nom / den * modes[i].yres <
-                            rinfo->video_ram / 2)
-                                break;
-                }
-                if (modes[i].xres == -1) {
-                        printk("radeonfb: could not find virtual resolution that fits into video memory!\n");
-                        return -EINVAL;
-                }
-                v->xres_virtual = modes[i].xres;  
-                v->yres_virtual = modes[i].yres;
-                
-                printk("radeonfb: virtual resolution set to max of %dx%d\n",
-                        v->xres_virtual, v->yres_virtual);
-        } else if (v->xres_virtual == -1) {
-                v->xres_virtual = (rinfo->video_ram * den /   
-                                (nom * v->yres_virtual * 2)) & ~15;
-        } else if (v->yres_virtual == -1) {
-                v->xres_virtual = (v->xres_virtual + 15) & ~15;
-                v->yres_virtual = rinfo->video_ram * den /
-                        (nom * v->xres_virtual *2);
-        } else {
-                if (v->xres_virtual * nom / den * v->yres_virtual >
-                        rinfo->video_ram) {
-                        return -EINVAL;
-                }
-        }
-                
-        if (v->xres_virtual * nom / den >= 8192) {
-                v->xres_virtual = 8192 * den / nom - 16;
-        }       
-        
-        if (v->xres_virtual < v->xres)
-                return -EINVAL;
-                
-        if (v->yres_virtual < v->yres)
-                return -EINVAL;
-                                
-        return 0;
-}
-
-
-static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info)
-{
-        struct radeonfb_info *rinfo = (struct radeonfb_info *) info->par;
-        struct fb_var_screeninfo v;
-        int nom, den;
-
-        memcpy (&v, var, sizeof (v));
-
-        switch (v.bits_per_pixel) {
-		case 0 ... 8:
-			v.bits_per_pixel = 8;
-			break;
-		case 9 ... 16:
-			v.bits_per_pixel = 16;
-			break;
-		case 17 ... 24:
-#if 0 /* Doesn't seem to work */
-			v.bits_per_pixel = 24;
-			break;
-#endif			
-			return -EINVAL;
-		case 25 ... 32:
-			v.bits_per_pixel = 32;
-			break;
-		default:
-			return -EINVAL;
-	}
-
-	switch (var_to_depth(&v)) {
-                case 8:
-                        nom = den = 1;
-                        v.red.offset = v.green.offset = v.blue.offset = 0;
-                        v.red.length = v.green.length = v.blue.length = 8;
-                        v.transp.offset = v.transp.length = 0;
-                        break;
-		case 15:
-			nom = 2;
-			den = 1;
-			v.red.offset = 10;
-			v.green.offset = 5;
-			v.blue.offset = 0;
-			v.red.length = v.green.length = v.blue.length = 5;
-			v.transp.offset = v.transp.length = 0;
-			break;
-                case 16:
-                        nom = 2;
-                        den = 1;
-                        v.red.offset = 11;
-                        v.green.offset = 5;
-                        v.blue.offset = 0;
-                        v.red.length = 5;
-                        v.green.length = 6;
-                        v.blue.length = 5;
-                        v.transp.offset = v.transp.length = 0;
-                        break;                          
-                case 24:
-                        nom = 4;
-                        den = 1;
-                        v.red.offset = 16;
-                        v.green.offset = 8;
-                        v.blue.offset = 0;
-                        v.red.length = v.blue.length = v.green.length = 8;
-                        v.transp.offset = v.transp.length = 0;
-                        break;
-                case 32:
-                        nom = 4;
-                        den = 1;
-                        v.red.offset = 16;
-                        v.green.offset = 8;
-                        v.blue.offset = 0;
-                        v.red.length = v.blue.length = v.green.length = 8;
-                        v.transp.offset = 24;
-                        v.transp.length = 8;
-                        break;
-                default:
-                        printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n",
-                                var->xres, var->yres, var->bits_per_pixel);
-                        return -EINVAL;
-        }
-
-        if (radeon_do_maximize(rinfo, var, &v, nom, den) < 0)
-                return -EINVAL;  
-                
-        if (v.xoffset < 0)
-                v.xoffset = 0;
-        if (v.yoffset < 0)
-                v.yoffset = 0;
-         
-        if (v.xoffset > v.xres_virtual - v.xres)
-                v.xoffset = v.xres_virtual - v.xres - 1;
-                        
-        if (v.yoffset > v.yres_virtual - v.yres)
-                v.yoffset = v.yres_virtual - v.yres - 1;
-         
-        v.red.msb_right = v.green.msb_right = v.blue.msb_right =
-                          v.transp.offset = v.transp.length =
-                          v.transp.msb_right = 0;
-
-	if (noaccel)
-		v.accel_flags = 0;
-			
-        memcpy(var, &v, sizeof(v));
-        
-        return 0;
-}
-
-
-static int radeonfb_pan_display (struct fb_var_screeninfo *var,
-                                 struct fb_info *info)
-{
-        struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
-
-        if ((var->xoffset + var->xres > var->xres_virtual)
-	    || (var->yoffset + var->yres > var->yres_virtual))
-               return -EINVAL;
-                
-        if (rinfo->asleep)
-        	return 0;
-
-        OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset)
-			     * var->bits_per_pixel / 8) & ~7);
-        return 0;
-}
-
-
-static int radeonfb_ioctl (struct fb_info *info, unsigned int cmd,
-                           unsigned long arg)
-{
-        struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
-	unsigned int tmp;
-	u32 value = 0;
-	int rc;
-
-	switch (cmd) {
-		/*
-		 * TODO:  set mirror accordingly for non-Mobility chipsets with 2 CRTC's
-		 */
-		case FBIO_RADEON_SET_MIRROR:
-			switch (rinfo->arch) {
-				case RADEON_R100:
-				case RADEON_RV100:
-				case RADEON_R200:
-				case RADEON_RV200:
-				case RADEON_RV250:
-				case RADEON_R300:
-					return -EINVAL;
-				default:
-					/* RADEON M6, RADEON_M7, RADEON_M9 */
-					break;
-			}
-
-			rc = get_user(value, (__u32 __user *)arg);
-
-			if (rc)
-				return rc;
-
-			if (value & 0x01) {
-				tmp = INREG(LVDS_GEN_CNTL);
-
-				tmp |= (LVDS_ON | LVDS_BLON);
-			} else {
-				tmp = INREG(LVDS_GEN_CNTL);
-
-				tmp &= ~(LVDS_ON | LVDS_BLON);
-			}
-
-			OUTREG(LVDS_GEN_CNTL, tmp);
-
-			if (value & 0x02) {
-				tmp = INREG(CRTC_EXT_CNTL);
-				tmp |= CRTC_CRT_ON;
-
-				mirror = 1;
-			} else {
-				tmp = INREG(CRTC_EXT_CNTL);
-				tmp &= ~CRTC_CRT_ON;
-
-				mirror = 0;
-			}
-
-			OUTREG(CRTC_EXT_CNTL, tmp);
-
-			break;
-		case FBIO_RADEON_GET_MIRROR:
-			switch (rinfo->arch) {
-				case RADEON_R100:
-				case RADEON_RV100:
-				case RADEON_R200:
-				case RADEON_RV200:
-				case RADEON_RV250:
-				case RADEON_R300:
-					return -EINVAL;
-				default:
-					/* RADEON M6, RADEON_M7, RADEON_M9 */
-					break;
-			}
-
-			tmp = INREG(LVDS_GEN_CNTL);
-			if ((LVDS_ON | LVDS_BLON) & tmp)
-				value |= 0x01;
-
-			tmp = INREG(CRTC_EXT_CNTL);
-			if (CRTC_CRT_ON & tmp)
-				value |= 0x02;
-
-			return put_user(value, (__u32 __user *)arg);
-		default:
-			return -EINVAL;
-	}
-
-	return -EINVAL;
-}
-
-
-static int radeonfb_blank (int blank, struct fb_info *info)
-{
-        struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
-        u32 val = INREG(CRTC_EXT_CNTL);
-	u32 val2 = INREG(LVDS_GEN_CNTL);
-
-	if (rinfo->asleep)
-		return 0;
-		
-#ifdef CONFIG_PMAC_BACKLIGHT
-	if (rinfo->dviDisp_type == MT_LCD && _machine == _MACH_Pmac) {
-		set_backlight_enable(!blank);
-		return 0;
-	}
-#endif
-                        
-        /* reset it */
-        val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |
-                 CRTC_VSYNC_DIS);
-	val2 &= ~(LVDS_DISPLAY_DIS);
-
-        switch (blank) {
-	        case FB_BLANK_UNBLANK:
-	        case FB_BLANK_NORMAL:
-                        break;
-                case FB_BLANK_VSYNC_SUSPEND:
-                        val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS);
-                        break;
-                case FB_BLANK_HSYNC_SUSPEND:
-                        val |= (CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS);
-                        break;
-                case FB_BLANK_POWERDOWN:
-                        val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | 
-                                CRTC_HSYNC_DIS);
-			val2 |= (LVDS_DISPLAY_DIS);
-                        break;
-        }
-
-	switch (rinfo->dviDisp_type) {
-		case MT_LCD:
-			OUTREG(LVDS_GEN_CNTL, val2);
-			break;
-		case MT_CRT:
-		default:
-		        OUTREG(CRTC_EXT_CNTL, val);
-			break;
-	}
-
-	/* let fbcon do a soft blank for us */
-	return (blank == FB_BLANK_NORMAL) ? 1 : 0;
-}
-
-
-static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
-                             unsigned blue, unsigned transp, struct fb_info *info)
-{
-        struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
-	u32 pindex, vclk_cntl;
-	unsigned int i;
-	
-	if (regno > 255)
-		return 1;
-
-	red >>= 8;
-	green >>= 8;
-	blue >>= 8;
-	rinfo->palette[regno].red = red;
-	rinfo->palette[regno].green = green;
-	rinfo->palette[regno].blue = blue;
-
-        /* default */
-        pindex = regno;
-
-        if (!rinfo->asleep) {
-		vclk_cntl = INPLL(VCLK_ECP_CNTL);
-		OUTPLL(VCLK_ECP_CNTL, vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
-
-		if (rinfo->bpp == 16) {
-			pindex = regno * 8;
-
-			if (rinfo->depth == 16 && regno > 63)
-				return 1;
-			if (rinfo->depth == 15 && regno > 31)
-				return 1;
-
-			/* For 565, the green component is mixed one order below */
-			if (rinfo->depth == 16) {
-		                OUTREG(PALETTE_INDEX, pindex>>1);
-	       	         	OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) |
-	                        	(green << 8) | (rinfo->palette[regno>>1].blue));
-	                	green = rinfo->palette[regno<<1].green;
-	        	}
-		}
-
-		if (rinfo->depth != 16 || regno < 32) {
-			OUTREG(PALETTE_INDEX, pindex);
-			OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue);
-		}
-
-		OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
-	}
- 	if (regno < 16) {
-        	switch (rinfo->depth) {
-		case 15:
-			((u16 *) (info->pseudo_palette))[regno] =
-			    (regno << 10) | (regno << 5) | regno;
-			break;
-		case 16:
-			((u16 *) (info->pseudo_palette))[regno] =
-			    (regno << 11) | (regno << 6) | regno;
-			break;
-		case 24:
-			((u32 *) (info->pseudo_palette))[regno] =
-			    (regno << 16) | (regno << 8) | regno;
-			break;
-		case 32:
-			i = (regno << 8) | regno;
-			((u32 *) (info->pseudo_palette))[regno] =
-			    (i << 16) | i;
-			break;
-		}
-        }
-	return 0;
-}
-
-
-
-static void radeon_save_state (struct radeonfb_info *rinfo,
-                               struct radeon_regs *save)
-{
-	/* CRTC regs */
-	save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
-	save->crtc_ext_cntl = INREG(CRTC_EXT_CNTL);
-	save->dac_cntl = INREG(DAC_CNTL);
-        save->crtc_h_total_disp = INREG(CRTC_H_TOTAL_DISP);
-        save->crtc_h_sync_strt_wid = INREG(CRTC_H_SYNC_STRT_WID);
-        save->crtc_v_total_disp = INREG(CRTC_V_TOTAL_DISP);
-        save->crtc_v_sync_strt_wid = INREG(CRTC_V_SYNC_STRT_WID);
-	save->crtc_pitch = INREG(CRTC_PITCH);
-#if defined(__BIG_ENDIAN)
-	save->surface_cntl = INREG(SURFACE_CNTL);
-#endif
-
-	/* FP regs */
-	save->fp_crtc_h_total_disp = INREG(FP_CRTC_H_TOTAL_DISP);
-	save->fp_crtc_v_total_disp = INREG(FP_CRTC_V_TOTAL_DISP);
-	save->fp_gen_cntl = INREG(FP_GEN_CNTL);
-	save->fp_h_sync_strt_wid = INREG(FP_H_SYNC_STRT_WID);
-	save->fp_horz_stretch = INREG(FP_HORZ_STRETCH);
-	save->fp_v_sync_strt_wid = INREG(FP_V_SYNC_STRT_WID);
-	save->fp_vert_stretch = INREG(FP_VERT_STRETCH);
-	save->lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
-	save->lvds_pll_cntl = INREG(LVDS_PLL_CNTL);
-	save->tmds_crc = INREG(TMDS_CRC);
-	save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL);
-	save->vclk_ecp_cntl = INPLL(VCLK_ECP_CNTL);
-}
-
-
-
-static int radeonfb_set_par (struct fb_info *info)
-{
-	struct radeonfb_info *rinfo = (struct radeonfb_info *)info->par;
-	struct fb_var_screeninfo *mode = &info->var;
-	struct radeon_regs newmode;
-	int hTotal, vTotal, hSyncStart, hSyncEnd,
-	    hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync;
-	u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5};
-	u8 hsync_fudge_fp[] = {2, 2, 0, 0, 5, 5};
-	u32 dotClock = 1000000000 / mode->pixclock,
-	    sync, h_sync_pol, v_sync_pol;
-	int freq = dotClock / 10;  /* x 100 */
-        int xclk_freq, vclk_freq, xclk_per_trans, xclk_per_trans_precise;
-        int useable_precision, roff, ron;
-        int min_bits, format = 0;
-	int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid;
-	int primary_mon = PRIMARY_MONITOR(rinfo);
-	int depth = var_to_depth(mode);
-        int accel = (mode->accel_flags & FB_ACCELF_TEXT) != 0;
-
-	rinfo->xres = mode->xres;
-	rinfo->yres = mode->yres;
-	rinfo->xres_virtual = mode->xres_virtual;
-	rinfo->yres_virtual = mode->yres_virtual;
-	rinfo->pixclock = mode->pixclock;
-
-	hSyncStart = mode->xres + mode->right_margin;
-	hSyncEnd = hSyncStart + mode->hsync_len;
-	hTotal = hSyncEnd + mode->left_margin;
-
-	vSyncStart = mode->yres + mode->lower_margin;
-	vSyncEnd = vSyncStart + mode->vsync_len;
-	vTotal = vSyncEnd + mode->upper_margin;
-
-	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
-		if (rinfo->panel_xres < mode->xres)
-			rinfo->xres = mode->xres = rinfo->panel_xres;
-		if (rinfo->panel_yres < mode->yres)
-			rinfo->yres = mode->yres = rinfo->panel_yres;
-
-		hTotal = mode->xres + rinfo->hblank;
-		hSyncStart = mode->xres + rinfo->hOver_plus;
-		hSyncEnd = hSyncStart + rinfo->hSync_width;
-
-		vTotal = mode->yres + rinfo->vblank;
-		vSyncStart = mode->yres + rinfo->vOver_plus;
-		vSyncEnd = vSyncStart + rinfo->vSync_width;
-	}
-
-	sync = mode->sync;
-	h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
-	v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
-
-	RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n",
-		hSyncStart, hSyncEnd, hTotal);
-	RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n",
-		vSyncStart, vSyncEnd, vTotal);
-
-	hsync_wid = (hSyncEnd - hSyncStart) / 8;
-	vsync_wid = vSyncEnd - vSyncStart;
-	if (hsync_wid == 0)
-		hsync_wid = 1;
-	else if (hsync_wid > 0x3f)	/* max */
-		hsync_wid = 0x3f;
-
-	if (vsync_wid == 0)
-		vsync_wid = 1;
-	else if (vsync_wid > 0x1f)	/* max */
-		vsync_wid = 0x1f;
-
-	hSyncPol = mode->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
-	vSyncPol = mode->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
-
-	cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0;
-
-	format = radeon_get_dstbpp(depth);
-	bytpp = mode->bits_per_pixel >> 3;
-
-	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD))
-		hsync_fudge = hsync_fudge_fp[format-1];
-	else
-		hsync_fudge = hsync_adj_tab[format-1];
-
-	hsync_start = hSyncStart - 8 + hsync_fudge;
-
-	newmode.crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN |
-				(format << 8);
-
-	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
-		newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN;
-		if (mirror)
-			newmode.crtc_ext_cntl |= CRTC_CRT_ON;
-
-		newmode.crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN |
-					   CRTC_INTERLACE_EN);
-	} else {
-		newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN |
-					CRTC_CRT_ON;
-	}
-
-	newmode.dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN |
-			   DAC_8BIT_EN;
-
-	newmode.crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) |
-				     (((mode->xres / 8) - 1) << 16));
-
-	newmode.crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) |
-					(hsync_wid << 16) | (h_sync_pol << 23));
-
-	newmode.crtc_v_total_disp = ((vTotal - 1) & 0xffff) |
-				    ((mode->yres - 1) << 16);
-
-	newmode.crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) |
-					 (vsync_wid << 16) | (v_sync_pol  << 23));
-
-	if (accel) {
-		/* We first calculate the engine pitch */
-		rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f)
- 				& ~(0x3f)) >> 6;
-
-		/* Then, re-multiply it to get the CRTC pitch */
-		newmode.crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8);
-	} else
-		newmode.crtc_pitch = (mode->xres_virtual >> 3);
-	newmode.crtc_pitch |= (newmode.crtc_pitch << 16);
-
-#if defined(__BIG_ENDIAN)
-	/*
-	 * It looks like recent chips have a problem with SURFACE_CNTL,
-	 * setting SURF_TRANSLATION_DIS completely disables the
-	 * swapper as well, so we leave it unset now.
-	 */
-	newmode.surface_cntl = 0;
-
-	/* Setup swapping on both apertures, though we currently
-	 * only use aperture 0, enabling swapper on aperture 1
-	 * won't harm
-	 */
-	switch (mode->bits_per_pixel) {
-		case 16:
-			newmode.surface_cntl |= NONSURF_AP0_SWP_16BPP;
-			newmode.surface_cntl |= NONSURF_AP1_SWP_16BPP;
-			break;
-		case 24:	
-		case 32:
-			newmode.surface_cntl |= NONSURF_AP0_SWP_32BPP;
-			newmode.surface_cntl |= NONSURF_AP1_SWP_32BPP;
-			break;
-	}
-#endif
-
-	rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f)
- 			& ~(0x3f)) / 64;
-
-	RTRACE("h_total_disp = 0x%x\t   hsync_strt_wid = 0x%x\n",
-		newmode.crtc_h_total_disp, newmode.crtc_h_sync_strt_wid);
-	RTRACE("v_total_disp = 0x%x\t   vsync_strt_wid = 0x%x\n",
-		newmode.crtc_v_total_disp, newmode.crtc_v_sync_strt_wid);
-
-	newmode.xres = mode->xres;
-	newmode.yres = mode->yres;
-
-	rinfo->bpp = mode->bits_per_pixel;
-	rinfo->depth = depth;
-
-	if (freq > rinfo->pll.ppll_max)
-		freq = rinfo->pll.ppll_max;
-	if (freq*12 < rinfo->pll.ppll_min)
-		freq = rinfo->pll.ppll_min / 12;
-
-	{
-		struct {
-			int divider;
-			int bitvalue;
-		} *post_div,
-		  post_divs[] = {
-			{ 1,  0 },
-			{ 2,  1 },
-			{ 4,  2 },
-			{ 8,  3 },
-			{ 3,  4 },
-			{ 16, 5 },
-			{ 6,  6 },
-			{ 12, 7 },
-			{ 0,  0 },
-		};
-
-		for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
-			rinfo->pll_output_freq = post_div->divider * freq;
-			if (rinfo->pll_output_freq >= rinfo->pll.ppll_min  &&
-			    rinfo->pll_output_freq <= rinfo->pll.ppll_max)
-				break;
-		}
-
-		rinfo->post_div = post_div->divider;
-		rinfo->fb_div = round_div(rinfo->pll.ref_div*rinfo->pll_output_freq,
-					  rinfo->pll.ref_clk);
-		newmode.ppll_ref_div = rinfo->pll.ref_div;
-		newmode.ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16);
-	}
-	newmode.vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl;
-
-#ifdef CONFIG_PPC_OF
-	/* Gross hack for iBook with M7 until I find out a proper fix */
-	if (machine_is_compatible("PowerBook4,3") && rinfo->arch == RADEON_M7)
-		newmode.ppll_div_3 = 0x000600ad;
-#endif /* CONFIG_PPC_OF */	
-
-	RTRACE("post div = 0x%x\n", rinfo->post_div);
-	RTRACE("fb_div = 0x%x\n", rinfo->fb_div);
-	RTRACE("ppll_div_3 = 0x%x\n", newmode.ppll_div_3);
-
-	/* DDA */
-	vclk_freq = round_div(rinfo->pll.ref_clk * rinfo->fb_div,
-			      rinfo->pll.ref_div * rinfo->post_div);
-	xclk_freq = rinfo->pll.xclk;
-
-	xclk_per_trans = round_div(xclk_freq * 128, vclk_freq * mode->bits_per_pixel);
-
-	min_bits = min_bits_req(xclk_per_trans);
-	useable_precision = min_bits + 1;
-
-	xclk_per_trans_precise = round_div((xclk_freq * 128) << (11 - useable_precision),
-					   vclk_freq * mode->bits_per_pixel);
-
-	ron = (4 * rinfo->ram.mb + 3 * _max(rinfo->ram.trcd - 2, 0) +
-	       2 * rinfo->ram.trp + rinfo->ram.twr + rinfo->ram.cl + rinfo->ram.tr2w +
-	       xclk_per_trans) << (11 - useable_precision);
-	roff = xclk_per_trans_precise * (32 - 4);
-
-	RTRACE("ron = %d, roff = %d\n", ron, roff);
-	RTRACE("vclk_freq = %d, per = %d\n", vclk_freq, xclk_per_trans_precise);
-
-	if ((ron + rinfo->ram.rloop) >= roff) {
-		printk("radeonfb: error ron out of range\n");
-		return -EINVAL;
-	}
-
-	newmode.dda_config = (xclk_per_trans_precise |
-			      (useable_precision << 16) |
-			      (rinfo->ram.rloop << 20));
-	newmode.dda_on_off = (ron << 16) | roff;
-
-	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
-		unsigned int hRatio, vRatio;
-
-		/* We force the pixel clock to be always enabled. Allowing it
-		 * to be power managed during blanking would save power, but has
-		 * nasty interactions with the 2D engine & sleep code that haven't
-		 * been solved yet. --BenH
-		 */
-		newmode.vclk_ecp_cntl &= ~PIXCLK_DAC_ALWAYS_ONb;
-		
-		if (mode->xres > rinfo->panel_xres)
-			mode->xres = rinfo->panel_xres;
-		if (mode->yres > rinfo->panel_yres)
-			mode->yres = rinfo->panel_yres;
-
-		newmode.fp_horz_stretch = (((rinfo->panel_xres / 8) - 1)
-					   << HORZ_PANEL_SHIFT);
-		newmode.fp_vert_stretch = ((rinfo->panel_yres - 1)
-					   << VERT_PANEL_SHIFT);
-
-		if (mode->xres != rinfo->panel_xres) {
-			hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX,
-					   rinfo->panel_xres);
-			newmode.fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) |
-						   (newmode.fp_horz_stretch &
-						    (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH |
-						     HORZ_AUTO_RATIO_INC)));
-			newmode.fp_horz_stretch |= (HORZ_STRETCH_BLEND |
-						    HORZ_STRETCH_ENABLE);
-		}
-		newmode.fp_horz_stretch &= ~HORZ_AUTO_RATIO;
-
-		if (mode->yres != rinfo->panel_yres) {
-			vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX,
-					   rinfo->panel_yres);
-			newmode.fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) |
-						   (newmode.fp_vert_stretch &
-						   (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED)));
-			newmode.fp_vert_stretch |= (VERT_STRETCH_BLEND |
-						    VERT_STRETCH_ENABLE);
-		}
-		newmode.fp_vert_stretch &= ~VERT_AUTO_RATIO_EN;
-
-		newmode.fp_gen_cntl = (rinfo->init_state.fp_gen_cntl & (u32)
-				       ~(FP_SEL_CRTC2 |
-					 FP_RMX_HVSYNC_CONTROL_EN |
-					 FP_DFP_SYNC_SEL |
-					 FP_CRT_SYNC_SEL |
-					 FP_CRTC_LOCK_8DOT |
-					 FP_USE_SHADOW_EN |
-					 FP_CRTC_USE_SHADOW_VEND |
-					 FP_CRT_SYNC_ALT));
-
-		newmode.fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR |
-					FP_CRTC_DONT_SHADOW_HEND);
-
-		newmode.lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl;
-		newmode.lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl;
-		newmode.tmds_crc = rinfo->init_state.tmds_crc;
-		newmode.tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl;
-
-		if (primary_mon == MT_LCD) {
-			newmode.lvds_gen_cntl |= (LVDS_ON | LVDS_BLON);
-			newmode.fp_gen_cntl &= ~(FP_FPON | FP_TMDS_EN);
-		} else {
-			/* DFP */
-			newmode.fp_gen_cntl |= (FP_FPON | FP_TMDS_EN);
-			newmode.tmds_transmitter_cntl = (TMDS_RAN_PAT_RST |
-							 TMDS_ICHCSEL | TMDS_PLL_EN) &
-							 ~(TMDS_PLLRST);
-			newmode.crtc_ext_cntl &= ~CRTC_CRT_ON;
-		}
-
-		newmode.fp_crtc_h_total_disp = (((rinfo->hblank / 8) & 0x3ff) |
-				(((mode->xres / 8) - 1) << 16));
-		newmode.fp_crtc_v_total_disp = (rinfo->vblank & 0xffff) |
-				((mode->yres - 1) << 16);
-		newmode.fp_h_sync_strt_wid = ((rinfo->hOver_plus & 0x1fff) |
-				(hsync_wid << 16) | (h_sync_pol << 23));
-		newmode.fp_v_sync_strt_wid = ((rinfo->vOver_plus & 0xfff) |
-				(vsync_wid << 16) | (v_sync_pol  << 23));
-	}
-
-	/* do it! */
-	if (!rinfo->asleep) {
-		radeon_write_mode (rinfo, &newmode);
-		/* (re)initialize the engine */
-		if (noaccel)
-			radeon_engine_init (rinfo);
-	
-	}
-	/* Update fix */
-	if (accel)
-        	info->fix.line_length = rinfo->pitch*64;
-        else
-		info->fix.line_length = mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8);
-        info->fix.visual = rinfo->depth == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
-
-#ifdef CONFIG_BOOTX_TEXT
-	/* Update debug text engine */
-	btext_update_display(rinfo->fb_base_phys, mode->xres, mode->yres,
-			     rinfo->depth, info->fix.line_length);
-#endif
-
-	return 0;
-}
-
-
-static void radeon_write_mode (struct radeonfb_info *rinfo,
-                               struct radeon_regs *mode)
-{
-	int i;
-	int primary_mon = PRIMARY_MONITOR(rinfo);
-
-	radeonfb_blank(VESA_POWERDOWN, (struct fb_info *)rinfo);
-
-
-	if (rinfo->arch == RADEON_M6) {
-		for (i=0; i<7; i++)
-			OUTREG(common_regs_m6[i].reg, common_regs_m6[i].val);
-	} else {
-		for (i=0; i<9; i++)
-			OUTREG(common_regs[i].reg, common_regs[i].val);
-	}
-
-	OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
-	OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
-		CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS);
-	OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
-	OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
-	OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
-	OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
-	OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
-	OUTREG(CRTC_OFFSET, 0);
-	OUTREG(CRTC_OFFSET_CNTL, 0);
-	OUTREG(CRTC_PITCH, mode->crtc_pitch);
-
-#if defined(__BIG_ENDIAN)
-	OUTREG(SURFACE_CNTL, mode->surface_cntl);
-#endif
-
-	while ((INREG(CLOCK_CNTL_INDEX) & PPLL_DIV_SEL_MASK) !=
-	       PPLL_DIV_SEL_MASK) {
-		OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, 0xffff);
-	}
-
-	OUTPLLP(PPLL_CNTL, PPLL_RESET, 0xffff);
-
-	while ((INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK) !=
-	       (mode->ppll_ref_div & PPLL_REF_DIV_MASK)) {
-		OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK);
-	}
-
-	while ((INPLL(PPLL_DIV_3) & PPLL_FB3_DIV_MASK) !=
-	       (mode->ppll_div_3 & PPLL_FB3_DIV_MASK)) {
-		OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK);
-	}
-
-	while ((INPLL(PPLL_DIV_3) & PPLL_POST3_DIV_MASK) !=
-	       (mode->ppll_div_3 & PPLL_POST3_DIV_MASK)) {
-		OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK);
-	}
-
-	OUTPLL(HTOTAL_CNTL, 0);
-
-	OUTPLLP(PPLL_CNTL, 0, ~PPLL_RESET);
-
-//	OUTREG(DDA_CONFIG, mode->dda_config);
-//	OUTREG(DDA_ON_OFF, mode->dda_on_off);
-
-	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
-		OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp);
-		OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp);
-		OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid);
-		OUTREG(FP_V_SYNC_STRT_WID, mode->fp_v_sync_strt_wid);
-		OUTREG(FP_HORZ_STRETCH, mode->fp_horz_stretch);
-		OUTREG(FP_VERT_STRETCH, mode->fp_vert_stretch);
-		OUTREG(FP_GEN_CNTL, mode->fp_gen_cntl);
-		OUTREG(TMDS_CRC, mode->tmds_crc);
-		OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl);
-
-		if (primary_mon == MT_LCD) {
-			unsigned int tmp = INREG(LVDS_GEN_CNTL);
-
-			mode->lvds_gen_cntl &= ~LVDS_STATE_MASK;
-			mode->lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_STATE_MASK);
-
-			if ((tmp & (LVDS_ON | LVDS_BLON)) ==
-			    (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON))) {
-				OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
-			} else {
-				if (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)) {
-					udelay(1000);
-					OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
-				} else {
-					OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl |
-					       LVDS_BLON);
-					udelay(1000);
-					OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
-				}
-			}
-		}
-	}
-
-	radeonfb_blank(VESA_NO_BLANKING, (struct fb_info *)rinfo);
-
-	OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl);
-	
-	return;
-}
-
-static struct fb_ops radeonfb_ops = {
-	.owner			= THIS_MODULE,
-	.fb_check_var		= radeonfb_check_var,
-	.fb_set_par		= radeonfb_set_par,
-	.fb_setcolreg		= radeonfb_setcolreg,
-	.fb_pan_display 	= radeonfb_pan_display,
-	.fb_blank		= radeonfb_blank,
-	.fb_ioctl		= radeonfb_ioctl,
-#if 0
-	.fb_fillrect	= radeonfb_fillrect,
-	.fb_copyarea	= radeonfb_copyarea,
-	.fb_imageblit	= radeonfb_imageblit,
-	.fb_rasterimg	= radeonfb_rasterimg,
-#else
-	.fb_fillrect	= cfb_fillrect,
-	.fb_copyarea	= cfb_copyarea,
-	.fb_imageblit	= cfb_imageblit,
-#endif
-};
-
-
-static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
-{
-	struct fb_info *info;
-
-	info = &rinfo->info;
-
-	info->par = rinfo;
-	info->pseudo_palette = rinfo->pseudo_palette;
-        info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
-        info->fbops = &radeonfb_ops;
-        info->screen_base = rinfo->fb_base;
-
-	/* Fill fix common fields */
-	strlcpy(info->fix.id, rinfo->name, sizeof(info->fix.id));
-        info->fix.smem_start = rinfo->fb_base_phys;
-        info->fix.smem_len = rinfo->video_ram;
-        info->fix.type = FB_TYPE_PACKED_PIXELS;
-        info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
-        info->fix.xpanstep = 8;
-        info->fix.ypanstep = 1;
-        info->fix.ywrapstep = 0;
-        info->fix.type_aux = 0;
-        info->fix.mmio_start = rinfo->mmio_base_phys;
-        info->fix.mmio_len = RADEON_REGSIZE;
-	if (noaccel)
-	        info->fix.accel = FB_ACCEL_NONE;
-	else
-		info->fix.accel = FB_ACCEL_ATI_RADEON;
-
-        if (radeon_init_disp (rinfo) < 0)
-                return -1;   
-
-        return 0;
-}
-
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-
-/* TODO: Dbl check these tables, we don't go up to full ON backlight
- * in these, possibly because we noticed MacOS doesn't, but I'd prefer
- * having some more official numbers from ATI
- */
-static int backlight_conv_m6[] = {
-	0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
-	0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
-};
-static int backlight_conv_m7[] = {
-	0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81,
-	0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9
-};
-
-#define BACKLIGHT_LVDS_OFF
-#undef BACKLIGHT_DAC_OFF
-
-/* We turn off the LCD completely instead of just dimming the backlight.
- * This provides some greater power saving and the display is useless
- * without backlight anyway.
- */
-
-static int radeon_set_backlight_enable(int on, int level, void *data)
-{
-	struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
-	unsigned int lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
-	int* conv_table;
-
-	/* Pardon me for that hack... maybe some day we can figure
-	 * out in what direction backlight should work on a given
-	 * panel ?
-	 */
-	if ((rinfo->arch == RADEON_M7 || rinfo->arch == RADEON_M9)
-		&& !machine_is_compatible("PowerBook4,3"))
-		conv_table = backlight_conv_m7;
-	else
-		conv_table = backlight_conv_m6;
-
-	lvds_gen_cntl |= (LVDS_BL_MOD_EN | LVDS_BLON);
-	if (on && (level > BACKLIGHT_OFF)) {
-		lvds_gen_cntl |= LVDS_DIGON;
-		if (!(lvds_gen_cntl & LVDS_ON)) {
-			lvds_gen_cntl &= ~LVDS_BLON;
-			OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
-			(void)INREG(LVDS_GEN_CNTL);
-			mdelay(10);
-			lvds_gen_cntl |= LVDS_BLON;
-			OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
-		}
-		lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
-		lvds_gen_cntl |= (conv_table[level] <<
-				  LVDS_BL_MOD_LEVEL_SHIFT);
-		lvds_gen_cntl |= (LVDS_ON | LVDS_EN);
-		lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
-	} else {
-		lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
-		lvds_gen_cntl |= (conv_table[0] <<
-				  LVDS_BL_MOD_LEVEL_SHIFT);
-		lvds_gen_cntl |= LVDS_DISPLAY_DIS;
-		OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
-		udelay(10);
-		lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGON);
-	}
-
-	OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
-	rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
-	rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
-
-	return 0;
-}
-
-static int radeon_set_backlight_level(int level, void *data)
-{
-	return radeon_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-
-#ifdef CONFIG_PMAC_PBOOK
-
-static u32 dbg_clk;
-
-/*
- * Radeon M6 Power Management code. This code currently only supports
- * the mobile chips, it's based from some informations provided by ATI
- * along with hours of tracing of MacOS drivers
- */
- 
-static void radeon_pm_save_regs(struct radeonfb_info *rinfo)
-{
-	rinfo->save_regs[0] = INPLL(PLL_PWRMGT_CNTL);
-	rinfo->save_regs[1] = INPLL(CLK_PWRMGT_CNTL);
-	rinfo->save_regs[2] = INPLL(MCLK_CNTL);
-	rinfo->save_regs[3] = INPLL(SCLK_CNTL);
-	rinfo->save_regs[4] = INPLL(CLK_PIN_CNTL);
-	rinfo->save_regs[5] = INPLL(VCLK_ECP_CNTL);
-	rinfo->save_regs[6] = INPLL(PIXCLKS_CNTL);
-	rinfo->save_regs[7] = INPLL(MCLK_MISC);
-	rinfo->save_regs[8] = INPLL(P2PLL_CNTL);
-	
-	rinfo->save_regs[9] = INREG(DISP_MISC_CNTL);
-	rinfo->save_regs[10] = INREG(DISP_PWR_MAN);
-	rinfo->save_regs[11] = INREG(LVDS_GEN_CNTL);
-	rinfo->save_regs[12] = INREG(LVDS_PLL_CNTL);
-	rinfo->save_regs[13] = INREG(TV_DAC_CNTL);
-	rinfo->save_regs[14] = INREG(BUS_CNTL1);
-	rinfo->save_regs[15] = INREG(CRTC_OFFSET_CNTL);
-	rinfo->save_regs[16] = INREG(AGP_CNTL);
-	rinfo->save_regs[17] = (INREG(CRTC_GEN_CNTL) & 0xfdffffff) | 0x04000000;
-	rinfo->save_regs[18] = (INREG(CRTC2_GEN_CNTL) & 0xfdffffff) | 0x04000000;
-	rinfo->save_regs[19] = INREG(GPIOPAD_A);
-	rinfo->save_regs[20] = INREG(GPIOPAD_EN);
-	rinfo->save_regs[21] = INREG(GPIOPAD_MASK);
-	rinfo->save_regs[22] = INREG(ZV_LCDPAD_A);
-	rinfo->save_regs[23] = INREG(ZV_LCDPAD_EN);
-	rinfo->save_regs[24] = INREG(ZV_LCDPAD_MASK);
-	rinfo->save_regs[25] = INREG(GPIO_VGA_DDC);
-	rinfo->save_regs[26] = INREG(GPIO_DVI_DDC);
-	rinfo->save_regs[27] = INREG(GPIO_MONID);
-	rinfo->save_regs[28] = INREG(GPIO_CRT2_DDC);
-
-	rinfo->save_regs[29] = INREG(SURFACE_CNTL);
-	rinfo->save_regs[30] = INREG(MC_FB_LOCATION);
-	rinfo->save_regs[31] = INREG(DISPLAY_BASE_ADDR);
-	rinfo->save_regs[32] = INREG(MC_AGP_LOCATION);
-	rinfo->save_regs[33] = INREG(CRTC2_DISPLAY_BASE_ADDR);
-}
-
-static void radeon_pm_restore_regs(struct radeonfb_info *rinfo)
-{
-	OUTPLL(P2PLL_CNTL, rinfo->save_regs[8] & 0xFFFFFFFE); /* First */
-	
-	OUTPLL(PLL_PWRMGT_CNTL, rinfo->save_regs[0]);
-	OUTPLL(CLK_PWRMGT_CNTL, rinfo->save_regs[1]);
-	OUTPLL(MCLK_CNTL, rinfo->save_regs[2]);
-	OUTPLL(SCLK_CNTL, rinfo->save_regs[3]);
-	OUTPLL(CLK_PIN_CNTL, rinfo->save_regs[4]);
-	OUTPLL(VCLK_ECP_CNTL, rinfo->save_regs[5]);
-	OUTPLL(PIXCLKS_CNTL, rinfo->save_regs[6]);
-	OUTPLL(MCLK_MISC, rinfo->save_regs[7]);
-	
-	OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]);
-	OUTREG(DISP_PWR_MAN, rinfo->save_regs[10]);
-	OUTREG(LVDS_GEN_CNTL, rinfo->save_regs[11]);
-	OUTREG(LVDS_PLL_CNTL,rinfo->save_regs[12]);
-	OUTREG(TV_DAC_CNTL, rinfo->save_regs[13]);
-	OUTREG(BUS_CNTL1, rinfo->save_regs[14]);
-	OUTREG(CRTC_OFFSET_CNTL, rinfo->save_regs[15]);
-	OUTREG(AGP_CNTL, rinfo->save_regs[16]);
-	OUTREG(CRTC_GEN_CNTL, rinfo->save_regs[17]);
-	OUTREG(CRTC2_GEN_CNTL, rinfo->save_regs[18]);
-
-	// wait VBL before that one  ?
-	OUTPLL(P2PLL_CNTL, rinfo->save_regs[8]);
-	
-	OUTREG(GPIOPAD_A, rinfo->save_regs[19]);
-	OUTREG(GPIOPAD_EN, rinfo->save_regs[20]);
-	OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]);
-	OUTREG(ZV_LCDPAD_A, rinfo->save_regs[22]);
-	OUTREG(ZV_LCDPAD_EN, rinfo->save_regs[23]);
-	OUTREG(ZV_LCDPAD_MASK, rinfo->save_regs[24]);
-	OUTREG(GPIO_VGA_DDC, rinfo->save_regs[25]);
-	OUTREG(GPIO_DVI_DDC, rinfo->save_regs[26]);
-	OUTREG(GPIO_MONID, rinfo->save_regs[27]);
-	OUTREG(GPIO_CRT2_DDC, rinfo->save_regs[28]);
-}
-
-static void radeon_pm_disable_iopad(struct radeonfb_info *rinfo)
-{		
-	OUTREG(GPIOPAD_MASK, 0x0001ffff);
-	OUTREG(GPIOPAD_EN, 0x00000400);
-	OUTREG(GPIOPAD_A, 0x00000000);		
-        OUTREG(ZV_LCDPAD_MASK, 0x00000000);
-        OUTREG(ZV_LCDPAD_EN, 0x00000000);
-      	OUTREG(ZV_LCDPAD_A, 0x00000000); 	
-	OUTREG(GPIO_VGA_DDC, 0x00030000);
-	OUTREG(GPIO_DVI_DDC, 0x00000000);
-	OUTREG(GPIO_MONID, 0x00030000);
-	OUTREG(GPIO_CRT2_DDC, 0x00000000);
-}
-
-static void radeon_pm_program_v2clk(struct radeonfb_info *rinfo)
-{
-//
-//	u32 reg;
-//
-//	OUTPLL(P2PLL_REF_DIV, 0x0c);
-//
-//      .../... figure out what macos does here
-}
-
-static void radeon_pm_low_current(struct radeonfb_info *rinfo)
-{
-	u32 reg;
-
-	reg  = INREG(BUS_CNTL1);
-	reg &= ~BUS_CNTL1_MOBILE_PLATFORM_SEL_MASK;
-	reg |= BUS_CNTL1_AGPCLK_VALID | (1<<BUS_CNTL1_MOBILE_PLATFORM_SEL_SHIFT);
-	OUTREG(BUS_CNTL1, reg);
-	
-	reg  = INPLL(PLL_PWRMGT_CNTL);
-	reg |= PLL_PWRMGT_CNTL_SPLL_TURNOFF | PLL_PWRMGT_CNTL_PPLL_TURNOFF |
-		PLL_PWRMGT_CNTL_P2PLL_TURNOFF | PLL_PWRMGT_CNTL_TVPLL_TURNOFF;
-	reg &= ~PLL_PWRMGT_CNTL_SU_MCLK_USE_BCLK;
-	reg &= ~PLL_PWRMGT_CNTL_MOBILE_SU;
-	OUTPLL(PLL_PWRMGT_CNTL, reg);
-
-//	reg  = INPLL(TV_PLL_CNTL1);
-//	reg |= TV_PLL_CNTL1__TVPLL_RESET | TV_PLL_CNTL1__TVPLL_SLEEP;
-//	OUTPLL(TV_PLL_CNTL1, reg);
-	
-	reg  = INREG(TV_DAC_CNTL);
-	reg &= ~(TV_DAC_CNTL_BGADJ_MASK |TV_DAC_CNTL_DACADJ_MASK);
-	reg |=TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD | TV_DAC_CNTL_GDACPD |
-		TV_DAC_CNTL_BDACPD |
-		(8<<TV_DAC_CNTL_BGADJ__SHIFT) | (8<<TV_DAC_CNTL_DACADJ__SHIFT);
-	OUTREG(TV_DAC_CNTL, reg);
-	
-	reg  = INREG(TMDS_TRANSMITTER_CNTL);
-	reg &= ~(TMDS_PLL_EN |TMDS_PLLRST);
-	OUTREG(TMDS_TRANSMITTER_CNTL, reg);
-
-//	lvds_pll_cntl  = regr32(g, LVDS_PLL_CNTL);
-//	lvds_pll_cntl &= ~LVDS_PLL_CNTL__LVDS_PLL_EN;											
-//	lvds_pll_cntl |=  LVDS_PLL_CNTL__LVDS_PLL_RESET;	
-//	regw32(g, LVDS_PLL_CNTL, lvds_pll_cntl);
-
-	reg = INREG(DAC_CNTL);
-	reg &= ~DAC_CMP_EN;
-	OUTREG(DAC_CNTL, reg);
-
-	reg = INREG(DAC_CNTL2);
-	reg &= ~DAC2_CMP_EN;
-	OUTREG(DAC_CNTL2, reg);
-	
-	reg  = INREG(TV_DAC_CNTL);
-	reg &= ~TV_DAC_CNTL_DETECT;
-	OUTREG(TV_DAC_CNTL, reg);
-}
-
-static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
-{
-	/* This code is disabled. It does what is in the pm_init
-	 * function of the MacOS driver code ATI sent me. However,
-	 * it doesn't fix my sleep problem, and is causing other issues
-	 * on wakeup (bascially the machine dying when switching consoles
-	 * I haven't had time to investigate this yet
-	 */
-#if 0
-	u32 disp_misc_cntl;
-	u32 disp_pwr_man;
-	u32 temp;
-
-	// set SPLL, MPLL, PPLL, P2PLL, TVPLL, SCLK, MCLK, PCLK, P2CLK,
-	// TCLK and TEST_MODE to 0
-	temp = INPLL(CLK_PWRMGT_CNTL);
-	OUTPLL(CLK_PWRMGT_CNTL , temp & ~0xc00002ff);
-
-	// Turn on Power Management
-	temp = INPLL(CLK_PWRMGT_CNTL);
-	OUTPLL(CLK_PWRMGT_CNTL , temp | 0x00000400);
-
-	// Turn off display clock if using mobile chips
-	temp = INPLL(CLK_PWRMGT_CNTL);
-	OUTREG(CLK_PWRMGT_CNTL , temp | 0x00100000);
-
-	// Force PIXCLK_ALWAYS_ON and PIXCLK_DAC_ALWAYS_ON
-	temp = INPLL(VCLK_ECP_CNTL);
-	OUTPLL(VCLK_ECP_CNTL, temp & ~0x000000c0);
-
-	// Force ECP_FORCE_ON to 1
-	temp = INPLL(VCLK_ECP_CNTL);
-	OUTPLL(VCLK_ECP_CNTL, temp | 0x00040000);
-
-	// Force PIXCLK_BLEND_ALWAYS_ON and PIXCLK_GV_ALWAYS_ON
-	temp = INPLL(PIXCLKS_CNTL);
-       	OUTPLL(PIXCLKS_CNTL, temp & ~0x00001800);
-
-	// Forcing SCLK_CNTL to ON
-	OUTPLL(SCLK_CNTL, (INPLL(SCLK_CNTL)& 0x00000007) | 0xffff8000 );
-
-	// Set PM control over XTALIN pad
-	temp = INPLL(CLK_PIN_CNTL);
-	OUTPLL(CLK_PIN_CNTL, temp | 0x00080000);
-
-	// Force MCLK and YCLK and MC as dynamic
-    	temp = INPLL(MCLK_CNTL);
-	OUTPLL(MCLK_CNTL, temp & 0xffeaffff);
-
-	// PLL_TURNOFF
-	temp = INPLL(PLL_PWRMGT_CNTL);
-	OUTPLL(PLL_PWRMGT_CNTL, temp | 0x0000001f);
- 
-	// set MOBILE_SU to 1 if M6 or DDR64 is detected
-	temp = INPLL(PLL_PWRMGT_CNTL);
-	OUTPLL(PLL_PWRMGT_CNTL, temp | 0x00010000);
-
-	// select PM access mode (PM_MODE_SEL) (use ACPI mode)
-//      temp = INPLL(PLL_PWRMGT_CNTL);
-//      OUTPLL(PLL_PWRMGT_CNTL, temp | 0x00002000);
-	temp = INPLL(PLL_PWRMGT_CNTL);
-        OUTPLL(PLL_PWRMGT_CNTL, temp & ~0x00002000);
-
-	// set DISP_MISC_CNTL register
-	disp_misc_cntl = INREG(DISP_MISC_CNTL);
-	disp_misc_cntl &= ~(	DISP_MISC_CNTL_SOFT_RESET_GRPH_PP |
-				DISP_MISC_CNTL_SOFT_RESET_SUBPIC_PP |
-				DISP_MISC_CNTL_SOFT_RESET_OV0_PP |
-				DISP_MISC_CNTL_SOFT_RESET_GRPH_SCLK |
-				DISP_MISC_CNTL_SOFT_RESET_SUBPIC_SCLK |
-				DISP_MISC_CNTL_SOFT_RESET_OV0_SCLK |
-				DISP_MISC_CNTL_SOFT_RESET_GRPH2_PP |
-				DISP_MISC_CNTL_SOFT_RESET_GRPH2_SCLK |
-				DISP_MISC_CNTL_SOFT_RESET_LVDS |
-				DISP_MISC_CNTL_SOFT_RESET_TMDS |
-				DISP_MISC_CNTL_SOFT_RESET_DIG_TMDS |
-				DISP_MISC_CNTL_SOFT_RESET_TV);
-	OUTREG(DISP_MISC_CNTL, disp_misc_cntl);
-
-	// set DISP_PWR_MAN register
-	disp_pwr_man = INREG(DISP_PWR_MAN);
-	// clau - 9.29.2000 - changes made to bit23:18 to set to 1 as requested by George
-	disp_pwr_man |= (DISP_PWR_MAN_DIG_TMDS_ENABLE_RST |
-                    DISP_PWR_MAN_TV_ENABLE_RST |
- //                 DISP_PWR_MAN_AUTO_PWRUP_EN |
-                    DISP_PWR_MAN_DISP_D3_GRPH_RST |
-                    DISP_PWR_MAN_DISP_D3_SUBPIC_RST |
-                    DISP_PWR_MAN_DISP_D3_OV0_RST |
-                    DISP_PWR_MAN_DISP_D1D2_GRPH_RST |
-                    DISP_PWR_MAN_DISP_D1D2_SUBPIC_RST |
-                    DISP_PWR_MAN_DISP_D1D2_OV0_RST);
-	disp_pwr_man &= ~(DISP_PWR_MAN_DISP_PWR_MAN_D3_CRTC_EN |
-                    DISP_PWR_MAN_DISP2_PWR_MAN_D3_CRTC2_EN|
-                    DISP_PWR_MAN_DISP_D3_RST |
-                    DISP_PWR_MAN_DISP_D3_REG_RST);
-	OUTREG(DISP_PWR_MAN, disp_pwr_man);
-
-	// clau - 10.24.2000
-	// - add in setting for BUS_CNTL1 b27:26 = 0x01 and b31 = 0x1
-	// - add in setting for AGP_CNTL  b7:0 = 0x20
-	// - add in setting for DVI_DDC_DATA_OUT_EN b17:16 = 0x0
-
-	// the following settings (two lines) are applied at a later part of this function, only on mobile platform
-	// requres -mobile flag
-	OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1) & 0xf3ffffff) | 0x04000000);
-	OUTREG(BUS_CNTL1,  INREG(BUS_CNTL1) | 0x80000000);
-	OUTREG(AGP_CNTL, (INREG(AGP_CNTL) & 0xffffff00) | 0x20);
-	OUTREG(GPIO_DVI_DDC, INREG(GPIO_DVI_DDC) & 0xfffcffff);
-
-	// yulee - 12.12.2000
-	// A12 only
-	// EN_MCLK_TRISTATE_IN_SUSPEND@MCLK_MISC = 1
-	// ACCESS_REGS_IN_SUSPEND@CLK_PIN_CNTL = 0
-	// only on mobile platform
-        OUTPLL(MCLK_MISC, INPLL(MCLK_MISC) | 0x00040000 );
-    	
-	// yulee -12.12.2000
-	// AGPCLK_VALID@BUS_CNTL1 = 1
-	// MOBILE_PLATFORM_SEL@BUS_CNTL1 = 01
-	// CRTC_STEREO_SYNC_OUT_EN@CRTC_OFFSET_CNTL = 0
-	// CG_CLK_TO_OUTPIN@CLK_PIN_CNTL = 0
-	// only on mobile platform
-        OUTPLL(CLK_PIN_CNTL, INPLL(CLK_PIN_CNTL ) & 0xFFFFF7FF );
-        OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1 ) & 0xF3FFFFFF) | 0x84000000 );
-        OUTREG(CRTC_OFFSET_CNTL, INREG(CRTC_OFFSET_CNTL ) & 0xFFEFFFFF );
-
-        mdelay(100);
-#endif
-
-	/* Disable CRTCs */
-	OUTREG(CRTC_GEN_CNTL, (INREG(CRTC_GEN_CNTL) & ~CRTC_EN) | CRTC_DISP_REQ_EN_B);
-	OUTREG(CRTC2_GEN_CNTL, (INREG(CRTC2_GEN_CNTL) & ~CRTC2_EN) | CRTC2_DISP_REQ_EN_B);
-	(void)INREG(CRTC2_GEN_CNTL);
-	mdelay(17);
-}
-
-static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
-{
-	u16 pwr_cmd;
-
-	if (!rinfo->pm_reg)
-		return;
-
-	/* Set the chip into appropriate suspend mode (we use D2,
-	 * D3 would require a compete re-initialization of the chip,
-	 * including PCI config registers, clocks, AGP conf, ...)
-	 */
-	if (suspend) {
-		/* According to ATI, we should program V2CLK here, I have
-		 * to verify what's up exactly
-		 */
-		/* Save some registers */
-		radeon_pm_save_regs(rinfo);
-
-		/* Check that on M7 too, might work might not. M7 may also
-		 * need explicit enabling of PM
-		 */
-		if (rinfo->arch == RADEON_M6) {
-			/* Program V2CLK */
-			radeon_pm_program_v2clk(rinfo);
-		
-			/* Disable IO PADs */
-			radeon_pm_disable_iopad(rinfo);
-
-			/* Set low current */
-			radeon_pm_low_current(rinfo);
-
-			/* Prepare chip for power management */
-			radeon_pm_setup_for_suspend(rinfo);
-
-			/* Reset the MDLL */
-			OUTPLL(MDLL_CKO, INPLL(MDLL_CKO) | MCKOA_RESET);
-			(void)INPLL(MDLL_RDCKA);
-			OUTPLL(MDLL_CKO, INPLL(MDLL_CKO) & ~MCKOA_RESET);
-			(void)INPLL(MDLL_RDCKA);
-		}
-
-		/* Switch PCI power managment to D2. */
-		for (;;) {
-			pci_read_config_word(
-				rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
-				&pwr_cmd);
-			if (pwr_cmd & 2)
-				break;			
-			pci_write_config_word(
-				rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
-				(pwr_cmd & ~PCI_PM_CTRL_STATE_MASK) | 2);
-			mdelay(500);
-		}
-	} else {
-		/* Switch back PCI powermanagment to D0 */
-		mdelay(200);
-		pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, 0);
-		mdelay(500);
-
-		dbg_clk = INPLL(1);
-
-		/* Do we need that on M7 ? */
-		if (rinfo->arch == RADEON_M6) {
-			/* Restore the MDLL */
-			OUTPLL(MDLL_CKO, INPLL(MDLL_CKO) & ~MCKOA_RESET);
-			(void)INPLL(MDLL_CKO);			
-		}
-		
-		/* Restore some registers */
-		radeon_pm_restore_regs(rinfo);
-	}
-}
-
-/*
- * Save the contents of the framebuffer when we go to sleep,
- * and restore it when we wake up again.
- */
-
-int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
-	struct radeonfb_info *rinfo;
-
-	for (rinfo = board_list; rinfo != NULL; rinfo = rinfo->next) {
-		struct fb_fix_screeninfo fix;
-		int nb;
-	        struct display *disp;  
-
-        	disp = (rinfo->currcon < 0) ? rinfo->info.disp : &fb_display[rinfo->currcon];
-
-		switch (rinfo->arch) {
-			case RADEON_M6:
-			case RADEON_M7:
-			case RADEON_M9:
-				break;
-			default:
-				return PBOOK_SLEEP_REFUSE;
-		}
-
-		radeonfb_get_fix(&fix, fg_console, (struct fb_info *)rinfo);
-		nb = fb_display[fg_console].var.yres * fix.line_length;
-
-		switch (when) {
-			case PBOOK_SLEEP_NOW:
-				acquire_console_sem();
-				disp->dispsw = &fbcon_dummy;
-
-				if (!noaccel) {
-					/* Make sure engine is reset */
-					radeon_engine_reset();
-					radeon_engine_idle();
-				}
-
-				/* Blank display and LCD */
-				radeonfb_blank(VESA_POWERDOWN+1,
-					       (struct fb_info *)rinfo);
-
-				/* Sleep */
-				rinfo->asleep = 1;
-				radeon_set_suspend(rinfo, 1);
-				release_console_sem();
-				
-				break;
-			case PBOOK_WAKE:
-				acquire_console_sem();
-				/* Wakeup */
-				radeon_set_suspend(rinfo, 0);
-
-				if (!noaccel)
-					radeon_engine_init(rinfo);
-				rinfo->asleep = 0;
-				radeon_set_dispsw(rinfo, disp);
-				radeon_load_video_mode(rinfo, &disp->var);
-				do_install_cmap(rinfo->currcon < 0 ? 0 : rinfo->currcon,
-						(struct fb_info *)rinfo);
-
-				radeonfb_blank(0, (struct fb_info *)rinfo);
-				release_console_sem();
-				printk("CLK_PIN_CNTL on wakeup was: %08x\n", dbg_clk);
-				break;
-		}
-	}
-
-	return PBOOK_SLEEP_OK;
-}
-
-#endif /* CONFIG_PMAC_PBOOK */
-
-static int radeonfb_pci_register (struct pci_dev *pdev,
-				  const struct pci_device_id *ent)
-{
-	struct radeonfb_info *rinfo;
-	struct radeon_chip_info *rci = &radeon_chip_info[ent->driver_data];
-	u32 tmp;
-
-	RTRACE("radeonfb_pci_register BEGIN\n");
-
-	/* Enable device in PCI config */
-	if (pci_enable_device(pdev) != 0) {
-		printk(KERN_ERR "radeonfb: Cannot enable PCI device\n");
-		return -ENODEV;
-	}
-
-	rinfo = kmalloc (sizeof (struct radeonfb_info), GFP_KERNEL);
-	if (!rinfo) {
-		printk ("radeonfb: could not allocate memory\n");
-		return -ENODEV;
-	}
-
-	memset (rinfo, 0, sizeof (struct radeonfb_info));
-	//info = &rinfo->info;
-	rinfo->pdev = pdev;
-	strcpy(rinfo->name, rci->name);
-	rinfo->arch = rci->arch;
-
-	/* Set base addrs */
-	rinfo->fb_base_phys = pci_resource_start (pdev, 0);
-	rinfo->mmio_base_phys = pci_resource_start (pdev, 2);
-
-	/* request the mem regions */
-	if (!request_mem_region (rinfo->fb_base_phys,
-				 pci_resource_len(pdev, 0), "radeonfb")) {
-		printk ("radeonfb: cannot reserve FB region\n");
-		kfree (rinfo);
-		return -ENODEV;
-	}
-
-	if (!request_mem_region (rinfo->mmio_base_phys,
-				 pci_resource_len(pdev, 2), "radeonfb")) {
-		printk ("radeonfb: cannot reserve MMIO region\n");
-		release_mem_region (rinfo->fb_base_phys,
-				    pci_resource_len(pdev, 0));
-		kfree (rinfo);
-		return -ENODEV;
-	}
-
-	/* map the regions */
-	rinfo->mmio_base = ioremap (rinfo->mmio_base_phys, RADEON_REGSIZE);
-	if (!rinfo->mmio_base) {
-		printk ("radeonfb: cannot map MMIO\n");
-		release_mem_region (rinfo->mmio_base_phys,
-				    pci_resource_len(pdev, 2));
-		release_mem_region (rinfo->fb_base_phys,
-				    pci_resource_len(pdev, 0));
-		kfree (rinfo);
-		return -ENODEV;
-	}
-
-	rinfo->chipset = pdev->device;
-
-	switch (rinfo->arch) {
-		case RADEON_R100:
-			rinfo->hasCRTC2 = 0;
-			break;
-		default:
-			/* all the rest have it */
-			rinfo->hasCRTC2 = 1;
-			break;
-	}
-#if 0
-	if (rinfo->arch == RADEON_M7) {
-		/*
-		 * Noticed some errors in accel with M7, will have to work these out...
-		 */
-		noaccel = 1;
-	}
-#endif
-	if (mirror)
-		printk("radeonfb: mirroring display to CRT\n");
-
-	/* framebuffer size */
-	tmp = INREG(CONFIG_MEMSIZE);
-
-	/* mem size is bits [28:0], mask off the rest */
-	rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
-
-	/* ram type */
-	tmp = INREG(MEM_SDRAM_MODE_REG);
-	switch ((MEM_CFG_TYPE & tmp) >> 30) {
-		case 0:
-			/* SDR SGRAM (2:1) */
-			strcpy(rinfo->ram_type, "SDR SGRAM");
-			rinfo->ram.ml = 4;
-			rinfo->ram.mb = 4;
-			rinfo->ram.trcd = 1;
-			rinfo->ram.trp = 2;
-			rinfo->ram.twr = 1;
-			rinfo->ram.cl = 2;
-			rinfo->ram.loop_latency = 16;
-			rinfo->ram.rloop = 16;
-	
-			break;
-		case 1:
-			/* DDR SGRAM */
-			strcpy(rinfo->ram_type, "DDR SGRAM");
-			rinfo->ram.ml = 4;
-			rinfo->ram.mb = 4;
-			rinfo->ram.trcd = 3;
-			rinfo->ram.trp = 3;
-			rinfo->ram.twr = 2;
-			rinfo->ram.cl = 3;
-			rinfo->ram.tr2w = 1;
-			rinfo->ram.loop_latency = 16;
-			rinfo->ram.rloop = 16;
-
-			break;
-		default:
-			/* 64-bit SDR SGRAM */
-			strcpy(rinfo->ram_type, "SDR SGRAM 64");
-			rinfo->ram.ml = 4;
-			rinfo->ram.mb = 8;
-			rinfo->ram.trcd = 3;
-			rinfo->ram.trp = 3;
-			rinfo->ram.twr = 1;
-			rinfo->ram.cl = 3;
-			rinfo->ram.tr2w = 1;
-			rinfo->ram.loop_latency = 17;
-			rinfo->ram.rloop = 17;
-
-			break;
-	}
-
-	rinfo->bios_seg = radeon_find_rom(rinfo);
-	radeon_get_pllinfo(rinfo, rinfo->bios_seg);
-
-	/*
-	 * Hack to get around some busted production M6's
-	 * reporting no ram
-	 */
-	if (rinfo->video_ram == 0) {
-		switch (pdev->device) {
-			case PCI_DEVICE_ID_ATI_RADEON_LY:
-			case PCI_DEVICE_ID_ATI_RADEON_LZ:
-				rinfo->video_ram = 8192 * 1024;
-				break;
-			default:
-				break;
-		}
-	}
-
-
-	RTRACE("radeonfb: probed %s %dk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024));
-
-#if !defined(__powerpc__)
-	radeon_get_moninfo(rinfo);
-#else
-	switch (pdev->device) {
-		case PCI_DEVICE_ID_ATI_RADEON_LW:
-		case PCI_DEVICE_ID_ATI_RADEON_LX:
-		case PCI_DEVICE_ID_ATI_RADEON_LY:
-		case PCI_DEVICE_ID_ATI_RADEON_LZ:
-			rinfo->dviDisp_type = MT_LCD;
-			break;
-		default:
-			radeon_get_moninfo(rinfo);
-			break;
-	}
-#endif
-
-	radeon_get_EDID(rinfo);
-
-	if ((rinfo->dviDisp_type == MT_DFP) || (rinfo->dviDisp_type == MT_LCD) ||
-	    (rinfo->crtDisp_type == MT_DFP)) {
-		if (!radeon_get_dfpinfo(rinfo)) {
-			iounmap(rinfo->mmio_base);
-			release_mem_region (rinfo->mmio_base_phys,
-					    pci_resource_len(pdev, 2));
-			release_mem_region (rinfo->fb_base_phys,
-					    pci_resource_len(pdev, 0));
-			kfree (rinfo);
-			return -ENODEV;
-		}
-	}
-
-	rinfo->fb_base = ioremap (rinfo->fb_base_phys, rinfo->video_ram);
-	if (!rinfo->fb_base) {
-		printk ("radeonfb: cannot map FB\n");
-		iounmap(rinfo->mmio_base);
-		release_mem_region (rinfo->mmio_base_phys,
-				    pci_resource_len(pdev, 2));
-		release_mem_region (rinfo->fb_base_phys,
-				    pci_resource_len(pdev, 0));
-		kfree (rinfo);
-		return -ENODEV;
-	}
-
-	/* I SHOULD FIX THAT CRAP ! I should probably mimmic XFree DRI
-	 * driver setup here.
-	 * 
-	 * On PPC, OF based cards setup the internal memory
-	 * mapping in strange ways. We change it so that the
-	 * framebuffer is mapped at 0 and given half of the card's
-	 * address space (2Gb). AGP is mapped high (0xe0000000) and
-	 * can use up to 512Mb. Once DRI is fully implemented, we
-	 * will have to setup the PCI remapper to remap the agp_special_page
-	 * memory page somewhere between those regions so that the card
-	 * use a normal PCI bus master cycle to access the ring read ptr.
-	 * --BenH.
-	 */
-#ifdef CONFIG_ALL_PPC
-	if (rinfo->hasCRTC2)
-		OUTREG(CRTC2_GEN_CNTL,
-			(INREG(CRTC2_GEN_CNTL) & ~CRTC2_EN) | CRTC2_DISP_REQ_EN_B);
-	OUTREG(CRTC_EXT_CNTL, INREG(CRTC_EXT_CNTL) | CRTC_DISPLAY_DIS);
-	OUTREG(MC_FB_LOCATION, 0x7fff0000);
-	OUTREG(MC_AGP_LOCATION, 0xffffe000);
-	OUTREG(DISPLAY_BASE_ADDR, 0x00000000);
-	if (rinfo->hasCRTC2)
-		OUTREG(CRTC2_DISPLAY_BASE_ADDR, 0x00000000);
-	OUTREG(SRC_OFFSET, 0x00000000);
-	OUTREG(DST_OFFSET, 0x00000000);
-	mdelay(10);
-	OUTREG(CRTC_EXT_CNTL, INREG(CRTC_EXT_CNTL) & ~CRTC_DISPLAY_DIS);
-#endif /* CONFIG_ALL_PPC */
-
-	/* save current mode regs before we switch into the new one
-	 * so we can restore this upon __exit
-	 */
-	radeon_save_state (rinfo, &rinfo->init_state);
-
-	/* set all the vital stuff */
-	radeon_set_fbinfo (rinfo);
-
-	pci_set_drvdata(pdev, rinfo);
-	rinfo->next = board_list;
-	board_list = rinfo;
-	((struct fb_info *) rinfo)->device = &pdev->dev;
-	if (register_framebuffer ((struct fb_info *) rinfo) < 0) {
-		printk ("radeonfb: could not register framebuffer\n");
-		iounmap(rinfo->fb_base);
-		iounmap(rinfo->mmio_base);
-		release_mem_region (rinfo->mmio_base_phys,
-				    pci_resource_len(pdev, 2));
-		release_mem_region (rinfo->fb_base_phys,
-				    pci_resource_len(pdev, 0));
-		kfree (rinfo);
-		return -ENODEV;
-	}
-
-#ifdef CONFIG_MTRR
-	rinfo->mtrr_hdl = nomtrr ? -1 : mtrr_add(rinfo->fb_base_phys,
-						 rinfo->video_ram,
-						 MTRR_TYPE_WRCOMB, 1);
-#endif
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-	if (rinfo->dviDisp_type == MT_LCD)
-		register_backlight_controller(&radeon_backlight_controller,
-					      rinfo, "ati");
-#endif
-
-#ifdef CONFIG_PMAC_PBOOK
-	if (rinfo->dviDisp_type == MT_LCD) {
-		rinfo->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
-		pmu_register_sleep_notifier(&radeon_sleep_notifier);
-	}
-#endif
-
-	printk ("radeonfb: ATI Radeon %s %s %d MB\n", rinfo->name, rinfo->ram_type,
-		(rinfo->video_ram/(1024*1024)));
-
-	if (rinfo->hasCRTC2) {
-		printk("radeonfb: DVI port %s monitor connected\n",
-			GET_MON_NAME(rinfo->dviDisp_type));
-		printk("radeonfb: CRT port %s monitor connected\n",
-			GET_MON_NAME(rinfo->crtDisp_type));
-	} else {
-		printk("radeonfb: CRT port %s monitor connected\n",
-			GET_MON_NAME(rinfo->crtDisp_type));
-	}
-
-	RTRACE("radeonfb_pci_register END\n");
-
-	return 0;
-}
-
-
-
-static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
-{
-        struct radeonfb_info *rinfo = pci_get_drvdata(pdev);
- 
-        if (!rinfo)
-                return;
- 
-	/* restore original state
-	 * 
-	 * Doesn't quite work yet, possibly because of the PPC hacking
-	 * I do on startup, disable for now. --BenH
-	 */
-        radeon_write_mode (rinfo, &rinfo->init_state);
- 
-#ifdef CONFIG_MTRR
-	if (rinfo->mtrr_hdl >= 0)
-		mtrr_del(rinfo->mtrr_hdl, 0, 0);
-#endif
-
-        unregister_framebuffer ((struct fb_info *) rinfo);
-                
-        iounmap(rinfo->mmio_base);
-        iounmap(rinfo->fb_base);
- 
-	release_mem_region (rinfo->mmio_base_phys,
-			    pci_resource_len(pdev, 2));
-	release_mem_region (rinfo->fb_base_phys,
-			    pci_resource_len(pdev, 0));
-        
-        kfree (rinfo);
-}
-
-
-static struct pci_driver radeonfb_driver = {
-	.name		= "radeonfb",
-	.id_table	= radeonfb_pci_table,
-	.probe		= radeonfb_pci_register,
-	.remove		= __devexit_p(radeonfb_pci_unregister),
-};
-
-#ifndef MODULE
-static int __init radeonfb_old_setup (char *options)
-{
-        char *this_opt;
-
-        if (!options || !*options)
-                return 0;
- 
-	while ((this_opt = strsep (&options, ",")) != NULL) {
-		if (!*this_opt)
-			continue;
-                if (!strncmp(this_opt, "noaccel", 7)) {
-			noaccel = 1;
-                } else if (!strncmp(this_opt, "mirror", 6)) {
-			mirror = 1;
-		} else if (!strncmp(this_opt, "dfp", 3)) {
-			force_dfp = 1;
-		} else if (!strncmp(this_opt, "panel_yres:", 11)) {
-			panel_yres = simple_strtoul((this_opt+11), NULL, 0);
-		} else if (!strncmp(this_opt, "nomtrr", 6)) {
-			nomtrr = 1;
-                } else
-			mode_option = this_opt;
-        }
-
-	return 0;
-}
-#endif  /*  MODULE  */
-
-static int __init radeonfb_old_init (void)
-{
-#ifndef MODULE
-	char *option = NULL;
-
-	if (fb_get_options("radeonfb_old", &option))
-		return -ENODEV;
-	radeonfb_old_setup(option);
-#endif
-	return pci_register_driver (&radeonfb_driver);
-}
-
-
-static void __exit radeonfb_old_exit (void)
-{
-	pci_unregister_driver (&radeonfb_driver);
-}
-
-module_init(radeonfb_old_init);
-module_exit(radeonfb_old_exit);
-
-
-MODULE_AUTHOR("Ani Joshi");
-MODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 6c19ab6..3e9308f 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -49,6 +49,7 @@
 #include <asm/pci-bridge.h>
 #endif
 #ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/machdep.h>
 #include <asm/backlight.h>
 #endif
 
@@ -1247,7 +1248,7 @@
 	CRTCout(par, 0x1a, vesa);
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if ( par->FlatPanel && _machine == _MACH_Pmac) {
+	if ( par->FlatPanel && machine_is(powermac)) {
 		set_backlight_enable(!blank);
 	}
 #endif
@@ -2037,9 +2038,9 @@
 		info->fix.smem_len / (1024 * 1024),
 		info->fix.smem_start);
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if (default_par->FlatPanel && _machine == _MACH_Pmac)
-	register_backlight_controller(&riva_backlight_controller,
-						default_par, "mnca");
+	if (default_par->FlatPanel && machine_is(powermac))
+		register_backlight_controller(&riva_backlight_controller,
+					      default_par, "mnca");
 #endif
 	NVTRACE_LEAVE();
 	return 0;
@@ -2072,8 +2073,6 @@
 	struct riva_par *par = info->par;
 	
 	NVTRACE_ENTER();
-	if (!info)
-		return;
 
 #ifdef CONFIG_FB_RIVA_I2C
 	riva_delete_i2c_busses(par);
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
index 00719a9..21debed 100644
--- a/drivers/video/savage/savagefb-i2c.c
+++ b/drivers/video/savage/savagefb-i2c.c
@@ -273,8 +273,7 @@
 		}
 	}
 
-	if (out_edid)
-		*out_edid = edid;
+	*out_edid = edid;
 
 	return (edid) ? 0 : 1;
 }
diff --git a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c
index 2d88f90..c3e070a 100644
--- a/drivers/video/sis/init301.c
+++ b/drivers/video/sis/init301.c
@@ -8564,11 +8564,9 @@
 static void
 SiS_ChrontelDoSomething2(struct SiS_Private *SiS_Pr)
 {
-     unsigned short temp,tempcl,tempch;
+     unsigned short temp;
 
      SiS_LongDelay(SiS_Pr, 1);
-     tempcl = 3;
-     tempch = 0;
 
      do {
        temp = SiS_GetCH701x(SiS_Pr,0x66);
@@ -8582,13 +8580,6 @@
 
        SiS_SetCH701xForLCD(SiS_Pr);
 
-       if(tempcl == 0) {
-           if(tempch == 3) break;
-	   SiS_ChrontelResetDB(SiS_Pr);
-	   tempcl = 3;
-	   tempch++;
-       }
-       tempcl--;
        temp = SiS_GetCH701x(SiS_Pr,0x76);
        temp &= 0xfb;  /* Reset PLL */
        SiS_SetCH701x(SiS_Pr,0x76,temp);
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
index 8c1a8b5..c44de90 100644
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -1194,10 +1194,11 @@
 static int __devinit sst_detect_dactype(struct fb_info *info, struct sstfb_par *par)
 {
 	int i, ret = 0;
-	
-	for (i=0; i<sizeof(dacs)/sizeof(dacs[0]); i++) {
+
+	for (i = 0; i < ARRAY_SIZE(dacs); i++) {
 		ret = dacs[i].detect(info);
-		if (ret) break;
+		if (ret)
+			break;
 	}
 	if (!ret)
 		return 0;
@@ -1604,8 +1605,8 @@
 		{FBZMODE,"fbzmode"},
 	};
 
-	const int pci_s = sizeof(pci_regs)/sizeof(pci_regs[0]);
-	const int sst_s = sizeof(sst_regs)/sizeof(sst_regs[0]);
+	const int pci_s = ARRAY_SIZE(pci_regs);
+	const int sst_s = ARRAY_SIZE(sst_regs);
 	struct sstfb_par *par = info->par;
 	struct pci_dev *dev = par->dev;
 	u32 pci_res[pci_s];
diff --git a/drivers/video/sticore.h b/drivers/video/sticore.h
index dc93336..1a9a60c 100644
--- a/drivers/video/sticore.h
+++ b/drivers/video/sticore.h
@@ -34,36 +34,20 @@
  * for them to fix it and steal their solution.   prumpf
  */
  
+#include <asm/io.h>
+
 #define STI_WAIT 1
 
-#include <asm/io.h> /* for USE_HPPA_IOREMAP */
-
-#if USE_HPPA_IOREMAP
-
-#define STI_PTR(p)	(p)
-#define PTR_STI(p)	(p)
-static inline int STI_CALL( unsigned long func, 
-		void *flags, void *inptr, void *outptr, void *glob_cfg )
-{
-       int (*f)(void *,void *,void *,void *);
-       f = (void*)func;
-       return f(flags, inptr, outptr, glob_cfg);
-}
-
-#else /* !USE_HPPA_IOREMAP */
-
 #define STI_PTR(p)	( virt_to_phys(p) )
-#define PTR_STI(p)	( phys_to_virt((long)p) )
-#define STI_CALL(func, flags, inptr, outptr, glob_cfg) \
-       ({                                                      \
-               pdc_sti_call( func, (unsigned long)STI_PTR(flags), \
-                                   (unsigned long)STI_PTR(inptr), \
-                                   (unsigned long)STI_PTR(outptr), \
-                                   (unsigned long)STI_PTR(glob_cfg)); \
+#define PTR_STI(p)	( phys_to_virt((unsigned long)p) )
+#define STI_CALL(func, flags, inptr, outptr, glob_cfg)	\
+       ({						\
+               pdc_sti_call( func, STI_PTR(flags),	\
+				   STI_PTR(inptr),	\
+				   STI_PTR(outptr),	\
+				   STI_PTR(glob_cfg));	\
        })
 
-#endif /* USE_HPPA_IOREMAP */
-
 
 #define sti_onscreen_x(sti) (sti->glob_cfg->onscreen_x)
 #define sti_onscreen_y(sti) (sti->glob_cfg->onscreen_y)
@@ -352,8 +336,9 @@
 	struct sti_conf_outptr outptr; /* configuration */
 	struct sti_conf_outptr_ext outptr_ext;
 
-	/* PCI data structures (pg. 17ff from sti.pdf) */
 	struct pci_dev *pd;
+
+	/* PCI data structures (pg. 17ff from sti.pdf) */
 	u8 rm_entry[16]; /* pci region mapper array == pci config space offset */
 
 	/* pointer to the fb_info where this STI device is used */
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
index 56d71d6..4a292aa 100644
--- a/drivers/video/stifb.c
+++ b/drivers/video/stifb.c
@@ -3,7 +3,7 @@
  * Low level Frame buffer driver for HP workstations with 
  * STI (standard text interface) video firmware.
  *
- * Copyright (C) 2001-2005 Helge Deller <deller@gmx.de>
+ * Copyright (C) 2001-2006 Helge Deller <deller@gmx.de>
  * Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
  * 
  * Based on:
@@ -514,7 +514,7 @@
 	SETUP_HW(fb);
 	WRITE_BYTE(1, fb, REG_16b1);
 
-	fb_memset(fb->info.fix.smem_start, 0xff,
+	fb_memset((void*)fb->info.fix.smem_start, 0xff,
 		fb->info.var.yres*fb->info.fix.line_length);
     
 	CRX24_SET_OVLY_MASK(fb);
@@ -908,83 +908,6 @@
 
 /* ------------------- driver specific functions --------------------------- */
 
-#define TMPBUFLEN 2048
-
-static ssize_t
-stifb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-{
-	unsigned long p = *ppos;
-	struct inode *inode = file->f_dentry->d_inode;
-	int fbidx = iminor(inode);
-	struct fb_info *info = registered_fb[fbidx];
-	char tmpbuf[TMPBUFLEN];
-
-	if (!info || ! info->screen_base)
-		return -ENODEV;
-
-	if (p >= info->fix.smem_len)
-	    return 0;
-	if (count >= info->fix.smem_len)
-	    count = info->fix.smem_len;
-	if (count + p > info->fix.smem_len)
-		count = info->fix.smem_len - p;
-	if (count > sizeof(tmpbuf))
-		count = sizeof(tmpbuf);
-	if (count) {
-	    char *base_addr;
-
-	    base_addr = info->screen_base;
-	    memcpy_fromio(&tmpbuf, base_addr+p, count);
-	    count -= copy_to_user(buf, &tmpbuf, count);
-	    if (!count)
-		return -EFAULT;
-	    *ppos += count;
-	}
-	return count;
-}
-
-static ssize_t
-stifb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-	int fbidx = iminor(inode);
-	struct fb_info *info = registered_fb[fbidx];
-	unsigned long p = *ppos;
-	size_t c;
-	int err;
-	char tmpbuf[TMPBUFLEN];
-
-	if (!info || !info->screen_base)
-		return -ENODEV;
-
-	if (p > info->fix.smem_len)
-	    return -ENOSPC;
-	if (count >= info->fix.smem_len)
-	    count = info->fix.smem_len;
-	err = 0;
-	if (count + p > info->fix.smem_len) {
-	    count = info->fix.smem_len - p;
-	    err = -ENOSPC;
-	}
-
-	p += (unsigned long)info->screen_base;
-	c = count;
-	while (c) {
-	    int len = c > sizeof(tmpbuf) ? sizeof(tmpbuf) : c;
-	    err = -EFAULT;
-	    if (copy_from_user(&tmpbuf, buf, len))
-		    break;
-	    memcpy_toio(p, &tmpbuf, len);
-	    c -= len;
-	    p += len;
-	    buf += len;
-	    *ppos += len;
-	}
-	if (count-c)
-		return (count-c);
-	return err;
-}
-
 static int
 stifb_setcolreg(u_int regno, u_int red, u_int green,
 	      u_int blue, u_int transp, struct fb_info *info)
@@ -1137,8 +1060,6 @@
 
 static struct fb_ops stifb_ops = {
 	.owner		= THIS_MODULE,
-	.fb_read	= stifb_read,
-	.fb_write	= stifb_write,
 	.fb_setcolreg	= stifb_setcolreg,
 	.fb_blank	= stifb_blank,
 	.fb_fillrect	= cfb_fillrect,
@@ -1162,7 +1083,7 @@
 	char *dev_name;
 	int bpp, xres, yres;
 
-	fb = kmalloc(sizeof(*fb), GFP_ATOMIC);
+	fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
 	if (!fb) {
 		printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
 		return -ENODEV;
@@ -1171,7 +1092,6 @@
 	info = &fb->info;
 
 	/* set struct to a known state */
-	memset(fb, 0, sizeof(*fb));
 	fix = &info->fix;
 	var = &info->var;
 
@@ -1234,7 +1154,7 @@
 	case S9000_ID_TOMCAT:	/* Dual CRX, behaves else like a CRX */
 		/* FIXME: TomCat supports two heads:
 		 * fb.iobase = REGION_BASE(fb_info,3);
-		 * fb.screen_base = (void*) REGION_BASE(fb_info,2);
+		 * fb.screen_base = ioremap_nocache(REGION_BASE(fb_info,2),xxx);
 		 * for now we only support the left one ! */
 		xres = fb->ngle_rom.x_size_visible;
 		yres = fb->ngle_rom.y_size_visible;
@@ -1327,7 +1247,8 @@
 
 	strcpy(fix->id, "stifb");
 	info->fbops = &stifb_ops;
-	info->screen_base = (void*) REGION_BASE(fb,1);
+	info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len);
+	info->screen_size = fix->smem_len;
 	info->flags = FBINFO_DEFAULT;
 	info->pseudo_palette = &fb->pseudo_palette;
 
@@ -1457,7 +1378,7 @@
 	int i;
 	
 	if (!options || !*options)
-		return 0;
+		return 1;
 	
 	if (strncmp(options, "off", 3) == 0) {
 		stifb_disabled = 1;
@@ -1472,7 +1393,7 @@
 			stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
 		}
 	}
-	return 0;
+	return 1;
 }
 
 __setup("stifb=", stifb_setup);
diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c
index ed78747..5ea2345 100644
--- a/drivers/video/virgefb.c
+++ b/drivers/video/virgefb.c
@@ -616,8 +616,7 @@
 #endif
 };
 
-#define arraysize(x)	(sizeof(x)/sizeof(*(x)))
-#define NUM_TOTAL_MODES	arraysize(virgefb_predefined)
+#define NUM_TOTAL_MODES	ARRAY_SIZE(virgefb_predefined)
 
 /*
  *    Default to 800x600 for video=virge8:, virge16: or virge32:
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
index f6e24ee..5fc86ea 100644
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -4,8 +4,9 @@
  * Frame Buffer Device for ATI Imageon w100 (Wallaby)
  *
  * Copyright (C) 2002, ATI Corp.
- * Copyright (C) 2004-2005 Richard Purdie
+ * Copyright (C) 2004-2006 Richard Purdie
  * Copyright (c) 2005 Ian Molton
+ * Copyright (c) 2006 Alberto Mardegan
  *
  * Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net>
  *
@@ -14,6 +15,9 @@
  *
  * w32xx support by Ian Molton
  *
+ * Hardware acceleration support by Alberto Mardegan
+ * <mardy@users.sourceforge.net>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -47,6 +51,7 @@
 static void w100_update_enable(void);
 static void w100_update_disable(void);
 static void calc_hsync(struct w100fb_par *par);
+static void w100_init_graphic_engine(struct w100fb_par *par);
 struct w100_pll_info *w100_get_xtal_table(unsigned int freq);
 
 /* Pseudo palette size */
@@ -248,6 +253,152 @@
 }
 
 
+static void w100_fifo_wait(int entries)
+{
+	union rbbm_status_u status;
+	int i;
+
+	for (i = 0; i < 2000000; i++) {
+		status.val = readl(remapped_regs + mmRBBM_STATUS);
+		if (status.f.cmdfifo_avail >= entries)
+			return;
+		udelay(1);
+	}
+	printk(KERN_ERR "w100fb: FIFO Timeout!\n");
+}
+
+
+static int w100fb_sync(struct fb_info *info)
+{
+	union rbbm_status_u status;
+	int i;
+
+	for (i = 0; i < 2000000; i++) {
+		status.val = readl(remapped_regs + mmRBBM_STATUS);
+		if (!status.f.gui_active)
+			return 0;
+		udelay(1);
+	}
+	printk(KERN_ERR "w100fb: Graphic engine timeout!\n");
+	return -EBUSY;
+}
+
+
+static void w100_init_graphic_engine(struct w100fb_par *par)
+{
+	union dp_gui_master_cntl_u gmc;
+	union dp_mix_u dp_mix;
+	union dp_datatype_u dp_datatype;
+	union dp_cntl_u dp_cntl;
+
+	w100_fifo_wait(4);
+	writel(W100_FB_BASE, remapped_regs + mmDST_OFFSET);
+	writel(par->xres, remapped_regs + mmDST_PITCH);
+	writel(W100_FB_BASE, remapped_regs + mmSRC_OFFSET);
+	writel(par->xres, remapped_regs + mmSRC_PITCH);
+
+	w100_fifo_wait(3);
+	writel(0, remapped_regs + mmSC_TOP_LEFT);
+	writel((par->yres << 16) | par->xres, remapped_regs + mmSC_BOTTOM_RIGHT);
+	writel(0x1fff1fff, remapped_regs + mmSRC_SC_BOTTOM_RIGHT);
+
+	w100_fifo_wait(4);
+	dp_cntl.val = 0;
+	dp_cntl.f.dst_x_dir = 1;
+	dp_cntl.f.dst_y_dir = 1;
+	dp_cntl.f.src_x_dir = 1;
+	dp_cntl.f.src_y_dir = 1;
+	dp_cntl.f.dst_major_x = 1;
+	dp_cntl.f.src_major_x = 1;
+	writel(dp_cntl.val, remapped_regs + mmDP_CNTL);
+
+	gmc.val = 0;
+	gmc.f.gmc_src_pitch_offset_cntl = 1;
+	gmc.f.gmc_dst_pitch_offset_cntl = 1;
+	gmc.f.gmc_src_clipping = 1;
+	gmc.f.gmc_dst_clipping = 1;
+	gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE;
+	gmc.f.gmc_dst_datatype = 3; /* from DstType_16Bpp_444 */
+	gmc.f.gmc_src_datatype = SRC_DATATYPE_EQU_DST;
+	gmc.f.gmc_byte_pix_order = 1;
+	gmc.f.gmc_default_sel = 0;
+	gmc.f.gmc_rop3 = ROP3_SRCCOPY;
+	gmc.f.gmc_dp_src_source = DP_SRC_MEM_RECTANGULAR;
+	gmc.f.gmc_clr_cmp_fcn_dis = 1;
+	gmc.f.gmc_wr_msk_dis = 1;
+	gmc.f.gmc_dp_op = DP_OP_ROP;
+	writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
+
+	dp_datatype.val = dp_mix.val = 0;
+	dp_datatype.f.dp_dst_datatype = gmc.f.gmc_dst_datatype;
+	dp_datatype.f.dp_brush_datatype = gmc.f.gmc_brush_datatype;
+	dp_datatype.f.dp_src2_type = 0;
+	dp_datatype.f.dp_src2_datatype = gmc.f.gmc_src_datatype;
+	dp_datatype.f.dp_src_datatype = gmc.f.gmc_src_datatype;
+	dp_datatype.f.dp_byte_pix_order = gmc.f.gmc_byte_pix_order;
+	writel(dp_datatype.val, remapped_regs + mmDP_DATATYPE);
+
+	dp_mix.f.dp_src_source = gmc.f.gmc_dp_src_source;
+	dp_mix.f.dp_src2_source = 1;
+	dp_mix.f.dp_rop3 = gmc.f.gmc_rop3;
+	dp_mix.f.dp_op = gmc.f.gmc_dp_op;
+	writel(dp_mix.val, remapped_regs + mmDP_MIX);
+}
+
+
+static void w100fb_fillrect(struct fb_info *info,
+                            const struct fb_fillrect *rect)
+{
+	union dp_gui_master_cntl_u gmc;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
+	if (info->flags & FBINFO_HWACCEL_DISABLED) {
+		cfb_fillrect(info, rect);
+		return;
+	}
+
+	gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL);
+	gmc.f.gmc_rop3 = ROP3_PATCOPY;
+	gmc.f.gmc_brush_datatype = GMC_BRUSH_SOLID_COLOR;
+	w100_fifo_wait(2);
+	writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
+	writel(rect->color, remapped_regs + mmDP_BRUSH_FRGD_CLR);
+
+	w100_fifo_wait(2);
+	writel((rect->dy << 16) | (rect->dx & 0xffff), remapped_regs + mmDST_Y_X);
+	writel((rect->width << 16) | (rect->height & 0xffff),
+	       remapped_regs + mmDST_WIDTH_HEIGHT);
+}
+
+
+static void w100fb_copyarea(struct fb_info *info,
+                            const struct fb_copyarea *area)
+{
+	u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
+	u32 h = area->height, w = area->width;
+	union dp_gui_master_cntl_u gmc;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
+	if (info->flags & FBINFO_HWACCEL_DISABLED) {
+		cfb_copyarea(info, area);
+		return;
+	}
+
+	gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL);
+	gmc.f.gmc_rop3 = ROP3_SRCCOPY;
+	gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE;
+	w100_fifo_wait(1);
+	writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
+
+	w100_fifo_wait(3);
+	writel((sy << 16) | (sx & 0xffff), remapped_regs + mmSRC_Y_X);
+	writel((dy << 16) | (dx & 0xffff), remapped_regs + mmDST_Y_X);
+	writel((w << 16) | (h & 0xffff), remapped_regs + mmDST_WIDTH_HEIGHT);
+}
+
+
 /*
  *  Change the resolution by calling the appropriate hardware functions
  */
@@ -265,6 +416,7 @@
 	w100_init_lcd(par);
 	w100_set_dispregs(par);
 	w100_update_enable();
+	w100_init_graphic_engine(par);
 
 	calc_hsync(par);
 
@@ -394,9 +546,10 @@
 	.fb_set_par   = w100fb_set_par,
 	.fb_setcolreg = w100fb_setcolreg,
 	.fb_blank     = w100fb_blank,
-	.fb_fillrect  = cfb_fillrect,
-	.fb_copyarea  = cfb_copyarea,
+	.fb_fillrect  = w100fb_fillrect,
+	.fb_copyarea  = w100fb_copyarea,
 	.fb_imageblit = cfb_imageblit,
+	.fb_sync      = w100fb_sync,
 };
 
 #ifdef CONFIG_PM
@@ -543,7 +696,8 @@
 	}
 
 	info->fbops = &w100fb_ops;
-	info->flags = FBINFO_DEFAULT;
+	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
+		FBINFO_HWACCEL_FILLRECT;
 	info->node = -1;
 	info->screen_base = remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE);
 	info->screen_size = REMAPPED_FB_LEN;
diff --git a/drivers/video/w100fb.h b/drivers/video/w100fb.h
index 7a58a1e..fffae7b 100644
--- a/drivers/video/w100fb.h
+++ b/drivers/video/w100fb.h
@@ -122,15 +122,32 @@
 /* Block DISPLAY End: */
 
 /* Block GFX Start: */
+#define mmDST_OFFSET          0x1004
+#define mmDST_PITCH           0x1008
+#define mmDST_Y_X             0x1038
+#define mmDST_WIDTH_HEIGHT    0x1198
+#define mmDP_GUI_MASTER_CNTL  0x106C
 #define mmBRUSH_OFFSET        0x108C
 #define mmBRUSH_Y_X           0x1074
+#define mmDP_BRUSH_FRGD_CLR   0x107C
+#define mmSRC_OFFSET          0x11AC
+#define mmSRC_PITCH           0x11B0
+#define mmSRC_Y_X             0x1034
 #define mmDEFAULT_PITCH_OFFSET      0x10A0
 #define mmDEFAULT_SC_BOTTOM_RIGHT   0x10A8
 #define mmDEFAULT2_SC_BOTTOM_RIGHT  0x10AC
+#define mmSC_TOP_LEFT         0x11BC
+#define mmSC_BOTTOM_RIGHT     0x11C0
+#define mmSRC_SC_BOTTOM_RIGHT 0x11C4
 #define mmGLOBAL_ALPHA        0x1210
 #define mmFILTER_COEF         0x1214
 #define mmMVC_CNTL_START      0x11E0
 #define mmE2_ARITHMETIC_CNTL  0x1220
+#define mmDP_CNTL             0x11C8
+#define mmDP_CNTL_DST_DIR     0x11CC
+#define mmDP_DATATYPE         0x12C4
+#define mmDP_MIX              0x12C8
+#define mmDP_WRITE_MSK        0x12CC
 #define mmENG_CNTL            0x13E8
 #define mmENG_PERF_CNT        0x13F0
 /* Block GFX End: */
@@ -179,6 +196,7 @@
 /* Block RBBM Start: */
 #define mmWAIT_UNTIL        0x1400
 #define mmISYNC_CNTL        0x1404
+#define mmRBBM_STATUS       0x0140
 #define mmRBBM_CNTL         0x0144
 #define mmNQWAIT_UNTIL      0x0150
 /* Block RBBM End: */
@@ -225,147 +243,147 @@
 /* Register structure definitions */
 
 struct wrap_top_dir_t {
-	unsigned long top_addr  : 23;
-	unsigned long           : 9;
+	u32 top_addr  : 23;
+	u32           : 9;
 } __attribute__((packed));
 
 union wrap_top_dir_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct wrap_top_dir_t f;
 } __attribute__((packed));
 
 struct wrap_start_dir_t {
-	unsigned long start_addr : 23;
-	unsigned long            : 9;
+	u32 start_addr : 23;
+	u32            : 9;
 } __attribute__((packed));
 
 union wrap_start_dir_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct wrap_start_dir_t f;
 } __attribute__((packed));
 
 struct cif_cntl_t {
-	unsigned long swap_reg                 : 2;
-	unsigned long swap_fbuf_1              : 2;
-	unsigned long swap_fbuf_2              : 2;
-	unsigned long swap_fbuf_3              : 2;
-	unsigned long pmi_int_disable          : 1;
-	unsigned long pmi_schmen_disable       : 1;
-	unsigned long intb_oe                  : 1;
-	unsigned long en_wait_to_compensate_dq_prop_dly  : 1;
-	unsigned long compensate_wait_rd_size  : 2;
-	unsigned long wait_asserted_timeout_val  : 2;
-	unsigned long wait_masked_val          : 2;
-	unsigned long en_wait_timeout          : 1;
-	unsigned long en_one_clk_setup_before_wait  : 1;
-	unsigned long interrupt_active_high    : 1;
-	unsigned long en_overwrite_straps      : 1;
-	unsigned long strap_wait_active_hi     : 1;
-	unsigned long lat_busy_count           : 2;
-	unsigned long lat_rd_pm4_sclk_busy     : 1;
-	unsigned long dis_system_bits          : 1;
-	unsigned long dis_mr                   : 1;
-	unsigned long cif_spare_1              : 4;
+	u32 swap_reg                 : 2;
+	u32 swap_fbuf_1              : 2;
+	u32 swap_fbuf_2              : 2;
+	u32 swap_fbuf_3              : 2;
+	u32 pmi_int_disable          : 1;
+	u32 pmi_schmen_disable       : 1;
+	u32 intb_oe                  : 1;
+	u32 en_wait_to_compensate_dq_prop_dly  : 1;
+	u32 compensate_wait_rd_size  : 2;
+	u32 wait_asserted_timeout_val  : 2;
+	u32 wait_masked_val          : 2;
+	u32 en_wait_timeout          : 1;
+	u32 en_one_clk_setup_before_wait  : 1;
+	u32 interrupt_active_high    : 1;
+	u32 en_overwrite_straps      : 1;
+	u32 strap_wait_active_hi     : 1;
+	u32 lat_busy_count           : 2;
+	u32 lat_rd_pm4_sclk_busy     : 1;
+	u32 dis_system_bits          : 1;
+	u32 dis_mr                   : 1;
+	u32 cif_spare_1              : 4;
 } __attribute__((packed));
 
 union cif_cntl_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct cif_cntl_t f;
 } __attribute__((packed));
 
 struct cfgreg_base_t {
-	unsigned long cfgreg_base  : 24;
-	unsigned long              : 8;
+	u32 cfgreg_base  : 24;
+	u32              : 8;
 } __attribute__((packed));
 
 union cfgreg_base_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct cfgreg_base_t f;
 } __attribute__((packed));
 
 struct cif_io_t {
-	unsigned long dq_srp     : 1;
-	unsigned long dq_srn     : 1;
-	unsigned long dq_sp      : 4;
-	unsigned long dq_sn      : 4;
-	unsigned long waitb_srp  : 1;
-	unsigned long waitb_srn  : 1;
-	unsigned long waitb_sp   : 4;
-	unsigned long waitb_sn   : 4;
-	unsigned long intb_srp   : 1;
-	unsigned long intb_srn   : 1;
-	unsigned long intb_sp    : 4;
-	unsigned long intb_sn    : 4;
-	unsigned long            : 2;
+	u32 dq_srp     : 1;
+	u32 dq_srn     : 1;
+	u32 dq_sp      : 4;
+	u32 dq_sn      : 4;
+	u32 waitb_srp  : 1;
+	u32 waitb_srn  : 1;
+	u32 waitb_sp   : 4;
+	u32 waitb_sn   : 4;
+	u32 intb_srp   : 1;
+	u32 intb_srn   : 1;
+	u32 intb_sp    : 4;
+	u32 intb_sn    : 4;
+	u32            : 2;
 } __attribute__((packed));
 
 union cif_io_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct cif_io_t f;
 } __attribute__((packed));
 
 struct cif_read_dbg_t {
-	unsigned long unpacker_pre_fetch_trig_gen  : 2;
-	unsigned long dly_second_rd_fetch_trig     : 1;
-	unsigned long rst_rd_burst_id              : 1;
-	unsigned long dis_rd_burst_id              : 1;
-	unsigned long en_block_rd_when_packer_is_not_emp : 1;
-	unsigned long dis_pre_fetch_cntl_sm        : 1;
-	unsigned long rbbm_chrncy_dis              : 1;
-	unsigned long rbbm_rd_after_wr_lat         : 2;
-	unsigned long dis_be_during_rd             : 1;
-	unsigned long one_clk_invalidate_pulse     : 1;
-	unsigned long dis_chnl_priority            : 1;
-	unsigned long rst_read_path_a_pls          : 1;
-	unsigned long rst_read_path_b_pls          : 1;
-	unsigned long dis_reg_rd_fetch_trig        : 1;
-	unsigned long dis_rd_fetch_trig_from_ind_addr : 1;
-	unsigned long dis_rd_same_byte_to_trig_fetch : 1;
-	unsigned long dis_dir_wrap                 : 1;
-	unsigned long dis_ring_buf_to_force_dec    : 1;
-	unsigned long dis_addr_comp_in_16bit       : 1;
-	unsigned long clr_w                        : 1;
-	unsigned long err_rd_tag_is_3              : 1;
-	unsigned long err_load_when_ful_a          : 1;
-	unsigned long err_load_when_ful_b          : 1;
-	unsigned long                              : 7;
+	u32 unpacker_pre_fetch_trig_gen  : 2;
+	u32 dly_second_rd_fetch_trig     : 1;
+	u32 rst_rd_burst_id              : 1;
+	u32 dis_rd_burst_id              : 1;
+	u32 en_block_rd_when_packer_is_not_emp : 1;
+	u32 dis_pre_fetch_cntl_sm        : 1;
+	u32 rbbm_chrncy_dis              : 1;
+	u32 rbbm_rd_after_wr_lat         : 2;
+	u32 dis_be_during_rd             : 1;
+	u32 one_clk_invalidate_pulse     : 1;
+	u32 dis_chnl_priority            : 1;
+	u32 rst_read_path_a_pls          : 1;
+	u32 rst_read_path_b_pls          : 1;
+	u32 dis_reg_rd_fetch_trig        : 1;
+	u32 dis_rd_fetch_trig_from_ind_addr : 1;
+	u32 dis_rd_same_byte_to_trig_fetch : 1;
+	u32 dis_dir_wrap                 : 1;
+	u32 dis_ring_buf_to_force_dec    : 1;
+	u32 dis_addr_comp_in_16bit       : 1;
+	u32 clr_w                        : 1;
+	u32 err_rd_tag_is_3              : 1;
+	u32 err_load_when_ful_a          : 1;
+	u32 err_load_when_ful_b          : 1;
+	u32                              : 7;
 } __attribute__((packed));
 
 union cif_read_dbg_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct cif_read_dbg_t f;
 } __attribute__((packed));
 
 struct cif_write_dbg_t {
-	unsigned long packer_timeout_count          : 2;
-	unsigned long en_upper_load_cond            : 1;
-	unsigned long en_chnl_change_cond           : 1;
-	unsigned long dis_addr_comp_cond            : 1;
-	unsigned long dis_load_same_byte_addr_cond  : 1;
-	unsigned long dis_timeout_cond              : 1;
-	unsigned long dis_timeout_during_rbbm       : 1;
-	unsigned long dis_packer_ful_during_rbbm_timeout : 1;
-	unsigned long en_dword_split_to_rbbm        : 1;
-	unsigned long en_dummy_val                  : 1;
-	unsigned long dummy_val_sel                 : 1;
-	unsigned long mask_pm4_wrptr_dec            : 1;
-	unsigned long dis_mc_clean_cond             : 1;
-	unsigned long err_two_reqi_during_ful       : 1;
-	unsigned long err_reqi_during_idle_clk      : 1;
-	unsigned long err_global                    : 1;
-	unsigned long en_wr_buf_dbg_load            : 1;
-	unsigned long en_wr_buf_dbg_path            : 1;
-	unsigned long sel_wr_buf_byte               : 3;
-	unsigned long dis_rd_flush_wr               : 1;
-	unsigned long dis_packer_ful_cond           : 1;
-	unsigned long dis_invalidate_by_ops_chnl    : 1;
-	unsigned long en_halt_when_reqi_err         : 1;
-	unsigned long cif_spare_2                   : 5;
-	unsigned long                               : 1;
+	u32 packer_timeout_count          : 2;
+	u32 en_upper_load_cond            : 1;
+	u32 en_chnl_change_cond           : 1;
+	u32 dis_addr_comp_cond            : 1;
+	u32 dis_load_same_byte_addr_cond  : 1;
+	u32 dis_timeout_cond              : 1;
+	u32 dis_timeout_during_rbbm       : 1;
+	u32 dis_packer_ful_during_rbbm_timeout : 1;
+	u32 en_dword_split_to_rbbm        : 1;
+	u32 en_dummy_val                  : 1;
+	u32 dummy_val_sel                 : 1;
+	u32 mask_pm4_wrptr_dec            : 1;
+	u32 dis_mc_clean_cond             : 1;
+	u32 err_two_reqi_during_ful       : 1;
+	u32 err_reqi_during_idle_clk      : 1;
+	u32 err_global                    : 1;
+	u32 en_wr_buf_dbg_load            : 1;
+	u32 en_wr_buf_dbg_path            : 1;
+	u32 sel_wr_buf_byte               : 3;
+	u32 dis_rd_flush_wr               : 1;
+	u32 dis_packer_ful_cond           : 1;
+	u32 dis_invalidate_by_ops_chnl    : 1;
+	u32 en_halt_when_reqi_err         : 1;
+	u32 cif_spare_2                   : 5;
+	u32                               : 1;
 } __attribute__((packed));
 
 union cif_write_dbg_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct cif_write_dbg_t f;
 } __attribute__((packed));
 
@@ -403,327 +421,327 @@
 } __attribute__((packed));
 
 struct crtc_total_t {
-	unsigned long crtc_h_total : 10;
-	unsigned long              : 6;
-	unsigned long crtc_v_total : 10;
-	unsigned long              : 6;
+	u32 crtc_h_total : 10;
+	u32              : 6;
+	u32 crtc_v_total : 10;
+	u32              : 6;
 } __attribute__((packed));
 
 union crtc_total_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct crtc_total_t f;
 } __attribute__((packed));
 
 struct crtc_ss_t {
-	unsigned long ss_start    : 10;
-	unsigned long             : 6;
-	unsigned long ss_end      : 10;
-	unsigned long             : 2;
-	unsigned long ss_align    : 1;
-	unsigned long ss_pol      : 1;
-	unsigned long ss_run_mode : 1;
-	unsigned long ss_en       : 1;
+	u32 ss_start    : 10;
+	u32             : 6;
+	u32 ss_end      : 10;
+	u32             : 2;
+	u32 ss_align    : 1;
+	u32 ss_pol      : 1;
+	u32 ss_run_mode : 1;
+	u32 ss_en       : 1;
 } __attribute__((packed));
 
 union crtc_ss_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct crtc_ss_t f;
 } __attribute__((packed));
 
 struct active_h_disp_t {
-	unsigned long active_h_start  : 10;
-	unsigned long                 : 6;
-	unsigned long active_h_end    : 10;
-	unsigned long                 : 6;
+	u32 active_h_start  : 10;
+	u32                 : 6;
+	u32 active_h_end    : 10;
+	u32                 : 6;
 } __attribute__((packed));
 
 union active_h_disp_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct active_h_disp_t f;
 } __attribute__((packed));
 
 struct active_v_disp_t {
-	unsigned long active_v_start  : 10;
-	unsigned long                 : 6;
-	unsigned long active_v_end    : 10;
-	unsigned long                 : 6;
+	u32 active_v_start  : 10;
+	u32                 : 6;
+	u32 active_v_end    : 10;
+	u32                 : 6;
 } __attribute__((packed));
 
 union active_v_disp_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct active_v_disp_t f;
 } __attribute__((packed));
 
 struct graphic_h_disp_t {
-	unsigned long graphic_h_start : 10;
-	unsigned long                 : 6;
-	unsigned long graphic_h_end   : 10;
-	unsigned long                 : 6;
+	u32 graphic_h_start : 10;
+	u32                 : 6;
+	u32 graphic_h_end   : 10;
+	u32                 : 6;
 } __attribute__((packed));
 
 union graphic_h_disp_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct graphic_h_disp_t f;
 } __attribute__((packed));
 
 struct graphic_v_disp_t {
-	unsigned long graphic_v_start : 10;
-	unsigned long                 : 6;
-	unsigned long graphic_v_end   : 10;
-	unsigned long                 : 6;
+	u32 graphic_v_start : 10;
+	u32                 : 6;
+	u32 graphic_v_end   : 10;
+	u32                 : 6;
 } __attribute__((packed));
 
 union graphic_v_disp_u{
-	unsigned long val : 32;
+	u32 val : 32;
 	struct graphic_v_disp_t f;
 } __attribute__((packed));
 
 struct graphic_ctrl_t_w100 {
-	unsigned long color_depth       : 3;
-	unsigned long portrait_mode     : 2;
-	unsigned long low_power_on      : 1;
-	unsigned long req_freq          : 4;
-	unsigned long en_crtc           : 1;
-	unsigned long en_graphic_req    : 1;
-	unsigned long en_graphic_crtc   : 1;
-	unsigned long total_req_graphic : 9;
-	unsigned long lcd_pclk_on       : 1;
-	unsigned long lcd_sclk_on       : 1;
-	unsigned long pclk_running      : 1;
-	unsigned long sclk_running      : 1;
-	unsigned long                   : 6;
+	u32 color_depth       : 3;
+	u32 portrait_mode     : 2;
+	u32 low_power_on      : 1;
+	u32 req_freq          : 4;
+	u32 en_crtc           : 1;
+	u32 en_graphic_req    : 1;
+	u32 en_graphic_crtc   : 1;
+	u32 total_req_graphic : 9;
+	u32 lcd_pclk_on       : 1;
+	u32 lcd_sclk_on       : 1;
+	u32 pclk_running      : 1;
+	u32 sclk_running      : 1;
+	u32                   : 6;
 } __attribute__((packed));
 
 struct graphic_ctrl_t_w32xx {
-	unsigned long color_depth       : 3;
-	unsigned long portrait_mode     : 2;
-	unsigned long low_power_on      : 1;
-	unsigned long req_freq          : 4;
-	unsigned long en_crtc           : 1;
-	unsigned long en_graphic_req    : 1;
-	unsigned long en_graphic_crtc   : 1;
-	unsigned long total_req_graphic : 10;
-	unsigned long lcd_pclk_on       : 1;
-	unsigned long lcd_sclk_on       : 1;
-	unsigned long pclk_running      : 1;
-	unsigned long sclk_running      : 1;
-	unsigned long                   : 5;
+	u32 color_depth       : 3;
+	u32 portrait_mode     : 2;
+	u32 low_power_on      : 1;
+	u32 req_freq          : 4;
+	u32 en_crtc           : 1;
+	u32 en_graphic_req    : 1;
+	u32 en_graphic_crtc   : 1;
+	u32 total_req_graphic : 10;
+	u32 lcd_pclk_on       : 1;
+	u32 lcd_sclk_on       : 1;
+	u32 pclk_running      : 1;
+	u32 sclk_running      : 1;
+	u32                   : 5;
 } __attribute__((packed));
 
 union graphic_ctrl_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct graphic_ctrl_t_w100 f_w100;
 	struct graphic_ctrl_t_w32xx f_w32xx;
 } __attribute__((packed));
 
 struct video_ctrl_t {
-	unsigned long video_mode       : 1;
-	unsigned long keyer_en         : 1;
-	unsigned long en_video_req     : 1;
-	unsigned long en_graphic_req_video  : 1;
-	unsigned long en_video_crtc    : 1;
-	unsigned long video_hor_exp    : 2;
-	unsigned long video_ver_exp    : 2;
-	unsigned long uv_combine       : 1;
-	unsigned long total_req_video  : 9;
-	unsigned long video_ch_sel     : 1;
-	unsigned long video_portrait   : 2;
-	unsigned long yuv2rgb_en       : 1;
-	unsigned long yuv2rgb_option   : 1;
-	unsigned long video_inv_hor    : 1;
-	unsigned long video_inv_ver    : 1;
-	unsigned long gamma_sel        : 2;
-	unsigned long dis_limit        : 1;
-	unsigned long en_uv_hblend     : 1;
-	unsigned long rgb_gamma_sel    : 2;
+	u32 video_mode       : 1;
+	u32 keyer_en         : 1;
+	u32 en_video_req     : 1;
+	u32 en_graphic_req_video  : 1;
+	u32 en_video_crtc    : 1;
+	u32 video_hor_exp    : 2;
+	u32 video_ver_exp    : 2;
+	u32 uv_combine       : 1;
+	u32 total_req_video  : 9;
+	u32 video_ch_sel     : 1;
+	u32 video_portrait   : 2;
+	u32 yuv2rgb_en       : 1;
+	u32 yuv2rgb_option   : 1;
+	u32 video_inv_hor    : 1;
+	u32 video_inv_ver    : 1;
+	u32 gamma_sel        : 2;
+	u32 dis_limit        : 1;
+	u32 en_uv_hblend     : 1;
+	u32 rgb_gamma_sel    : 2;
 } __attribute__((packed));
 
 union video_ctrl_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct video_ctrl_t f;
 } __attribute__((packed));
 
 struct disp_db_buf_cntl_rd_t {
-	unsigned long en_db_buf           : 1;
-	unsigned long update_db_buf_done  : 1;
-	unsigned long db_buf_cntl         : 6;
-	unsigned long                     : 24;
+	u32 en_db_buf           : 1;
+	u32 update_db_buf_done  : 1;
+	u32 db_buf_cntl         : 6;
+	u32                     : 24;
 } __attribute__((packed));
 
 union disp_db_buf_cntl_rd_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct disp_db_buf_cntl_rd_t f;
 } __attribute__((packed));
 
 struct disp_db_buf_cntl_wr_t {
-	unsigned long en_db_buf      : 1;
-	unsigned long update_db_buf  : 1;
-	unsigned long db_buf_cntl    : 6;
-	unsigned long                : 24;
+	u32 en_db_buf      : 1;
+	u32 update_db_buf  : 1;
+	u32 db_buf_cntl    : 6;
+	u32                : 24;
 } __attribute__((packed));
 
 union disp_db_buf_cntl_wr_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct disp_db_buf_cntl_wr_t f;
 } __attribute__((packed));
 
 struct gamma_value1_t {
-	unsigned long gamma1   : 8;
-	unsigned long gamma2   : 8;
-	unsigned long gamma3   : 8;
-	unsigned long gamma4   : 8;
+	u32 gamma1   : 8;
+	u32 gamma2   : 8;
+	u32 gamma3   : 8;
+	u32 gamma4   : 8;
 } __attribute__((packed));
 
 union gamma_value1_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct gamma_value1_t f;
 } __attribute__((packed));
 
 struct gamma_value2_t {
-	unsigned long gamma5   : 8;
-	unsigned long gamma6   : 8;
-	unsigned long gamma7   : 8;
-	unsigned long gamma8   : 8;
+	u32 gamma5   : 8;
+	u32 gamma6   : 8;
+	u32 gamma7   : 8;
+	u32 gamma8   : 8;
 } __attribute__((packed));
 
 union gamma_value2_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct gamma_value2_t f;
 } __attribute__((packed));
 
 struct gamma_slope_t {
-	unsigned long slope1   : 3;
-	unsigned long slope2   : 3;
-	unsigned long slope3   : 3;
-	unsigned long slope4   : 3;
-	unsigned long slope5   : 3;
-	unsigned long slope6   : 3;
-	unsigned long slope7   : 3;
-	unsigned long slope8   : 3;
-	unsigned long          : 8;
+	u32 slope1   : 3;
+	u32 slope2   : 3;
+	u32 slope3   : 3;
+	u32 slope4   : 3;
+	u32 slope5   : 3;
+	u32 slope6   : 3;
+	u32 slope7   : 3;
+	u32 slope8   : 3;
+	u32          : 8;
 } __attribute__((packed));
 
 union gamma_slope_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct gamma_slope_t f;
 } __attribute__((packed));
 
 struct mc_ext_mem_location_t {
-	unsigned long mc_ext_mem_start : 16;
-	unsigned long mc_ext_mem_top   : 16;
+	u32 mc_ext_mem_start : 16;
+	u32 mc_ext_mem_top   : 16;
 } __attribute__((packed));
 
 union mc_ext_mem_location_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct mc_ext_mem_location_t f;
 } __attribute__((packed));
 
 struct mc_fb_location_t {
-	unsigned long mc_fb_start      : 16;
-	unsigned long mc_fb_top        : 16;
+	u32 mc_fb_start      : 16;
+	u32 mc_fb_top        : 16;
 } __attribute__((packed));
 
 union mc_fb_location_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct mc_fb_location_t f;
 } __attribute__((packed));
 
 struct clk_pin_cntl_t {
-	unsigned long osc_en           : 1;
-	unsigned long osc_gain         : 5;
-	unsigned long dont_use_xtalin  : 1;
-	unsigned long xtalin_pm_en     : 1;
-	unsigned long xtalin_dbl_en    : 1;
-	unsigned long                  : 7;
-	unsigned long cg_debug         : 16;
+	u32 osc_en           : 1;
+	u32 osc_gain         : 5;
+	u32 dont_use_xtalin  : 1;
+	u32 xtalin_pm_en     : 1;
+	u32 xtalin_dbl_en    : 1;
+	u32                  : 7;
+	u32 cg_debug         : 16;
 } __attribute__((packed));
 
 union clk_pin_cntl_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct clk_pin_cntl_t f;
 } __attribute__((packed));
 
 struct pll_ref_fb_div_t {
-	unsigned long pll_ref_div      : 4;
-	unsigned long                  : 4;
-	unsigned long pll_fb_div_int   : 6;
-	unsigned long                  : 2;
-	unsigned long pll_fb_div_frac  : 3;
-	unsigned long                  : 1;
-	unsigned long pll_reset_time   : 4;
-	unsigned long pll_lock_time    : 8;
+	u32 pll_ref_div      : 4;
+	u32                  : 4;
+	u32 pll_fb_div_int   : 6;
+	u32                  : 2;
+	u32 pll_fb_div_frac  : 3;
+	u32                  : 1;
+	u32 pll_reset_time   : 4;
+	u32 pll_lock_time    : 8;
 } __attribute__((packed));
 
 union pll_ref_fb_div_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct pll_ref_fb_div_t f;
 } __attribute__((packed));
 
 struct pll_cntl_t {
-	unsigned long pll_pwdn        : 1;
-	unsigned long pll_reset       : 1;
-	unsigned long pll_pm_en       : 1;
-	unsigned long pll_mode        : 1;
-	unsigned long pll_refclk_sel  : 1;
-	unsigned long pll_fbclk_sel   : 1;
-	unsigned long pll_tcpoff      : 1;
-	unsigned long pll_pcp         : 3;
-	unsigned long pll_pvg         : 3;
-	unsigned long pll_vcofr       : 1;
-	unsigned long pll_ioffset     : 2;
-	unsigned long pll_pecc_mode   : 2;
-	unsigned long pll_pecc_scon   : 2;
-	unsigned long pll_dactal      : 4;
-	unsigned long pll_cp_clip     : 2;
-	unsigned long pll_conf        : 3;
-	unsigned long pll_mbctrl      : 2;
-	unsigned long pll_ring_off    : 1;
+	u32 pll_pwdn        : 1;
+	u32 pll_reset       : 1;
+	u32 pll_pm_en       : 1;
+	u32 pll_mode        : 1;
+	u32 pll_refclk_sel  : 1;
+	u32 pll_fbclk_sel   : 1;
+	u32 pll_tcpoff      : 1;
+	u32 pll_pcp         : 3;
+	u32 pll_pvg         : 3;
+	u32 pll_vcofr       : 1;
+	u32 pll_ioffset     : 2;
+	u32 pll_pecc_mode   : 2;
+	u32 pll_pecc_scon   : 2;
+	u32 pll_dactal      : 4;
+	u32 pll_cp_clip     : 2;
+	u32 pll_conf        : 3;
+	u32 pll_mbctrl      : 2;
+	u32 pll_ring_off    : 1;
 } __attribute__((packed));
 
 union pll_cntl_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct pll_cntl_t f;
 } __attribute__((packed));
 
 struct sclk_cntl_t {
-	unsigned long sclk_src_sel         : 2;
-	unsigned long                      : 2;
-	unsigned long sclk_post_div_fast   : 4;
-	unsigned long sclk_clkon_hys       : 3;
-	unsigned long sclk_post_div_slow   : 4;
-	unsigned long disp_cg_ok2switch_en : 1;
-	unsigned long sclk_force_reg       : 1;
-	unsigned long sclk_force_disp      : 1;
-	unsigned long sclk_force_mc        : 1;
-	unsigned long sclk_force_extmc     : 1;
-	unsigned long sclk_force_cp        : 1;
-	unsigned long sclk_force_e2        : 1;
-	unsigned long sclk_force_e3        : 1;
-	unsigned long sclk_force_idct      : 1;
-	unsigned long sclk_force_bist      : 1;
-	unsigned long busy_extend_cp       : 1;
-	unsigned long busy_extend_e2       : 1;
-	unsigned long busy_extend_e3       : 1;
-	unsigned long busy_extend_idct     : 1;
-	unsigned long                      : 3;
+	u32 sclk_src_sel         : 2;
+	u32                      : 2;
+	u32 sclk_post_div_fast   : 4;
+	u32 sclk_clkon_hys       : 3;
+	u32 sclk_post_div_slow   : 4;
+	u32 disp_cg_ok2switch_en : 1;
+	u32 sclk_force_reg       : 1;
+	u32 sclk_force_disp      : 1;
+	u32 sclk_force_mc        : 1;
+	u32 sclk_force_extmc     : 1;
+	u32 sclk_force_cp        : 1;
+	u32 sclk_force_e2        : 1;
+	u32 sclk_force_e3        : 1;
+	u32 sclk_force_idct      : 1;
+	u32 sclk_force_bist      : 1;
+	u32 busy_extend_cp       : 1;
+	u32 busy_extend_e2       : 1;
+	u32 busy_extend_e3       : 1;
+	u32 busy_extend_idct     : 1;
+	u32                      : 3;
 } __attribute__((packed));
 
 union sclk_cntl_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct sclk_cntl_t f;
 } __attribute__((packed));
 
 struct pclk_cntl_t {
-	unsigned long pclk_src_sel     : 2;
-	unsigned long                  : 2;
-	unsigned long pclk_post_div    : 4;
-	unsigned long                  : 8;
-	unsigned long pclk_force_disp  : 1;
-	unsigned long                  : 15;
+	u32 pclk_src_sel     : 2;
+	u32                  : 2;
+	u32 pclk_post_div    : 4;
+	u32                  : 8;
+	u32 pclk_force_disp  : 1;
+	u32                  : 15;
 } __attribute__((packed));
 
 union pclk_cntl_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct pclk_cntl_t f;
 } __attribute__((packed));
 
@@ -735,36 +753,176 @@
 #define TESTCLK_SRC_XTAL  0x06
 
 struct clk_test_cntl_t {
-	unsigned long testclk_sel      : 4;
-	unsigned long                  : 3;
-	unsigned long start_check_freq : 1;
-	unsigned long tstcount_rst     : 1;
-	unsigned long                  : 15;
-	unsigned long test_count       : 8;
+	u32 testclk_sel      : 4;
+	u32                  : 3;
+	u32 start_check_freq : 1;
+	u32 tstcount_rst     : 1;
+	u32                  : 15;
+	u32 test_count       : 8;
 } __attribute__((packed));
 
 union clk_test_cntl_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct clk_test_cntl_t f;
 } __attribute__((packed));
 
 struct pwrmgt_cntl_t {
-	unsigned long pwm_enable           : 1;
-	unsigned long                      : 1;
-	unsigned long pwm_mode_req         : 2;
-	unsigned long pwm_wakeup_cond      : 2;
-	unsigned long pwm_fast_noml_hw_en  : 1;
-	unsigned long pwm_noml_fast_hw_en  : 1;
-	unsigned long pwm_fast_noml_cond   : 4;
-	unsigned long pwm_noml_fast_cond   : 4;
-	unsigned long pwm_idle_timer       : 8;
-	unsigned long pwm_busy_timer       : 8;
+	u32 pwm_enable           : 1;
+	u32                      : 1;
+	u32 pwm_mode_req         : 2;
+	u32 pwm_wakeup_cond      : 2;
+	u32 pwm_fast_noml_hw_en  : 1;
+	u32 pwm_noml_fast_hw_en  : 1;
+	u32 pwm_fast_noml_cond   : 4;
+	u32 pwm_noml_fast_cond   : 4;
+	u32 pwm_idle_timer       : 8;
+	u32 pwm_busy_timer       : 8;
 } __attribute__((packed));
 
 union pwrmgt_cntl_u {
-	unsigned long val : 32;
+	u32 val : 32;
 	struct pwrmgt_cntl_t f;
 } __attribute__((packed));
 
+#define SRC_DATATYPE_EQU_DST	3
+
+#define ROP3_SRCCOPY	0xcc
+#define ROP3_PATCOPY	0xf0
+
+#define GMC_BRUSH_SOLID_COLOR	13
+#define GMC_BRUSH_NONE			15
+
+#define DP_SRC_MEM_RECTANGULAR	2
+
+#define DP_OP_ROP	0
+
+struct dp_gui_master_cntl_t {
+	u32 gmc_src_pitch_offset_cntl : 1;
+	u32 gmc_dst_pitch_offset_cntl : 1;
+	u32 gmc_src_clipping          : 1;
+	u32 gmc_dst_clipping          : 1;
+	u32 gmc_brush_datatype        : 4;
+	u32 gmc_dst_datatype          : 4;
+	u32 gmc_src_datatype          : 3;
+	u32 gmc_byte_pix_order        : 1;
+	u32 gmc_default_sel           : 1;
+	u32 gmc_rop3                  : 8;
+	u32 gmc_dp_src_source         : 3;
+	u32 gmc_clr_cmp_fcn_dis       : 1;
+	u32                           : 1;
+	u32 gmc_wr_msk_dis            : 1;
+	u32 gmc_dp_op                 : 1;
+} __attribute__((packed));
+
+union dp_gui_master_cntl_u {
+	u32 val : 32;
+	struct dp_gui_master_cntl_t f;
+} __attribute__((packed));
+
+struct rbbm_status_t {
+	u32 cmdfifo_avail   : 7;
+	u32                 : 1;
+	u32 hirq_on_rbb     : 1;
+	u32 cprq_on_rbb     : 1;
+	u32 cfrq_on_rbb     : 1;
+	u32 hirq_in_rtbuf   : 1;
+	u32 cprq_in_rtbuf   : 1;
+	u32 cfrq_in_rtbuf   : 1;
+	u32 cf_pipe_busy    : 1;
+	u32 eng_ev_busy     : 1;
+	u32 cp_cmdstrm_busy : 1;
+	u32 e2_busy         : 1;
+	u32 rb2d_busy       : 1;
+	u32 rb3d_busy       : 1;
+	u32 se_busy         : 1;
+	u32 re_busy         : 1;
+	u32 tam_busy        : 1;
+	u32 tdm_busy        : 1;
+	u32 pb_busy         : 1;
+	u32                 : 6;
+	u32 gui_active      : 1;
+} __attribute__((packed));
+
+union rbbm_status_u {
+	u32 val : 32;
+	struct rbbm_status_t f;
+} __attribute__((packed));
+
+struct dp_datatype_t {
+	u32 dp_dst_datatype   : 4;
+	u32                   : 4;
+	u32 dp_brush_datatype : 4;
+	u32 dp_src2_type      : 1;
+	u32 dp_src2_datatype  : 3;
+	u32 dp_src_datatype   : 3;
+	u32                   : 11;
+	u32 dp_byte_pix_order : 1;
+	u32                   : 1;
+} __attribute__((packed));
+
+union dp_datatype_u {
+	u32 val : 32;
+	struct dp_datatype_t f;
+} __attribute__((packed));
+
+struct dp_mix_t {
+	u32                : 8;
+	u32 dp_src_source  : 3;
+	u32 dp_src2_source : 3;
+	u32                : 2;
+	u32 dp_rop3        : 8;
+	u32 dp_op          : 1;
+	u32                : 7;
+} __attribute__((packed));
+
+union dp_mix_u {
+	u32 val : 32;
+	struct dp_mix_t f;
+} __attribute__((packed));
+
+struct eng_cntl_t {
+	u32 erc_reg_rd_ws            : 1;
+	u32 erc_reg_wr_ws            : 1;
+	u32 erc_idle_reg_wr          : 1;
+	u32 dis_engine_triggers      : 1;
+	u32 dis_rop_src_uses_dst_w_h : 1;
+	u32 dis_src_uses_dst_dirmaj  : 1;
+	u32                          : 6;
+	u32 force_3dclk_when_2dclk   : 1;
+	u32                          : 19;
+} __attribute__((packed));
+
+union eng_cntl_u {
+	u32 val : 32;
+	struct eng_cntl_t f;
+} __attribute__((packed));
+
+struct dp_cntl_t {
+	u32 dst_x_dir   : 1;
+	u32 dst_y_dir   : 1;
+	u32 src_x_dir   : 1;
+	u32 src_y_dir   : 1;
+	u32 dst_major_x : 1;
+	u32 src_major_x : 1;
+	u32             : 26;
+} __attribute__((packed));
+
+union dp_cntl_u {
+	u32 val : 32;
+	struct dp_cntl_t f;
+} __attribute__((packed));
+
+struct dp_cntl_dst_dir_t {
+	u32           : 15;
+	u32 dst_y_dir : 1;
+	u32           : 15;
+	u32 dst_x_dir : 1;
+} __attribute__((packed));
+
+union dp_cntl_dst_dir_u {
+	u32 val : 32;
+	struct dp_cntl_dst_dir_t f;
+} __attribute__((packed));
+
 #endif
 
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 43c9f7d..f867b8d 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -39,8 +39,8 @@
 
 extern struct file_system_type v9fs_fs_type;
 extern struct address_space_operations v9fs_addr_operations;
-extern struct file_operations v9fs_file_operations;
-extern struct file_operations v9fs_dir_operations;
+extern const struct file_operations v9fs_file_operations;
+extern const struct file_operations v9fs_dir_operations;
 extern struct dentry_operations v9fs_dentry_operations;
 
 struct inode *v9fs_get_inode(struct super_block *sb, int mode);
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 766f11f..e32d597 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -204,7 +204,7 @@
 	return 0;
 }
 
-struct file_operations v9fs_dir_operations = {
+const struct file_operations v9fs_dir_operations = {
 	.read = generic_read_dir,
 	.readdir = v9fs_dir_readdir,
 	.open = v9fs_file_open,
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 59e7441..083dcfc 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -266,7 +266,7 @@
 	return total;
 }
 
-struct file_operations v9fs_file_operations = {
+const struct file_operations v9fs_file_operations = {
 	.llseek = generic_file_llseek,
 	.read = v9fs_file_read,
 	.write = v9fs_file_write,
diff --git a/fs/Makefile b/fs/Makefile
index 080b386..83bf478 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -10,7 +10,7 @@
 		ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
 		attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
 		seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \
-		ioprio.o pnode.o drop_caches.o
+		ioprio.o pnode.o drop_caches.o splice.o sync.o
 
 obj-$(CONFIG_INOTIFY)		+= inotify.o
 obj-$(CONFIG_EPOLL)		+= eventpoll.o
diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index f6cd013..29217ff 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -85,7 +85,7 @@
 
 /* dir_*.c */
 extern struct inode_operations adfs_dir_inode_operations;
-extern struct file_operations adfs_dir_operations;
+extern const struct file_operations adfs_dir_operations;
 extern struct dentry_operations adfs_dentry_operations;
 extern struct adfs_dir_ops adfs_f_dir_ops;
 extern struct adfs_dir_ops adfs_fplus_dir_ops;
@@ -94,7 +94,7 @@
 
 /* file.c */
 extern struct inode_operations adfs_file_inode_operations;
-extern struct file_operations adfs_file_operations;
+extern const struct file_operations adfs_file_operations;
 
 static inline __u32 signed_asl(__u32 val, signed int shift)
 {
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 0b4c3a0..7b075fc 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -196,7 +196,7 @@
 	return ret;
 }
 
-struct file_operations adfs_dir_operations = {
+const struct file_operations adfs_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= adfs_readdir,
 	.fsync		= file_fsync,
diff --git a/fs/adfs/file.c b/fs/adfs/file.c
index 6af1088..1014b9f 100644
--- a/fs/adfs/file.c
+++ b/fs/adfs/file.c
@@ -25,7 +25,7 @@
 
 #include "adfs.h"
 
-struct file_operations adfs_file_operations = {
+const struct file_operations adfs_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
 	.mmap		= generic_file_mmap,
diff --git a/fs/affs/affs.h b/fs/affs/affs.h
index 0c6799f..a43a876 100644
--- a/fs/affs/affs.h
+++ b/fs/affs/affs.h
@@ -192,9 +192,9 @@
 extern struct inode_operations	 affs_file_inode_operations;
 extern struct inode_operations	 affs_dir_inode_operations;
 extern struct inode_operations   affs_symlink_inode_operations;
-extern struct file_operations	 affs_file_operations;
-extern struct file_operations	 affs_file_operations_ofs;
-extern struct file_operations	 affs_dir_operations;
+extern const struct file_operations	 affs_file_operations;
+extern const struct file_operations	 affs_file_operations_ofs;
+extern const struct file_operations	 affs_dir_operations;
 extern struct address_space_operations	 affs_symlink_aops;
 extern struct address_space_operations	 affs_aops;
 extern struct address_space_operations	 affs_aops_ofs;
diff --git a/fs/affs/dir.c b/fs/affs/dir.c
index 548efd0..5d9649f 100644
--- a/fs/affs/dir.c
+++ b/fs/affs/dir.c
@@ -17,7 +17,7 @@
 
 static int affs_readdir(struct file *, void *, filldir_t);
 
-struct file_operations affs_dir_operations = {
+const struct file_operations affs_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= affs_readdir,
 	.fsync		= file_fsync,
diff --git a/fs/affs/file.c b/fs/affs/file.c
index f72fb77..7076262 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -25,7 +25,7 @@
 static int affs_file_open(struct inode *inode, struct file *filp);
 static int affs_file_release(struct inode *inode, struct file *filp);
 
-struct file_operations affs_file_operations = {
+const struct file_operations affs_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
 	.write		= generic_file_write,
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 5c61c24..a6dff6a 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -32,7 +32,7 @@
 static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen,
 				  loff_t fpos, ino_t ino, unsigned dtype);
 
-struct file_operations afs_dir_file_operations = {
+const struct file_operations afs_dir_file_operations = {
 	.open		= afs_dir_open,
 	.readdir	= afs_dir_readdir,
 };
diff --git a/fs/afs/file.c b/fs/afs/file.c
index 150b192..7bb7168 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -28,7 +28,7 @@
 #endif
 
 static int afs_file_readpage(struct file *file, struct page *page);
-static int afs_file_invalidatepage(struct page *page, unsigned long offset);
+static void afs_file_invalidatepage(struct page *page, unsigned long offset);
 static int afs_file_releasepage(struct page *page, gfp_t gfp_flags);
 
 struct inode_operations afs_file_inode_operations = {
@@ -212,7 +212,7 @@
 /*
  * invalidate part or all of a page
  */
-static int afs_file_invalidatepage(struct page *page, unsigned long offset)
+static void afs_file_invalidatepage(struct page *page, unsigned long offset)
 {
 	int ret = 1;
 
@@ -238,11 +238,11 @@
 			if (!PageWriteback(page))
 				ret = page->mapping->a_ops->releasepage(page,
 									0);
+			/* possibly should BUG_ON(!ret); - neilb */
 		}
 	}
 
 	_leave(" = %d", ret);
-	return ret;
 } /* end afs_file_invalidatepage() */
 
 /*****************************************************************************/
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index ab8f87c..72febdf 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -64,7 +64,7 @@
  * dir.c
  */
 extern struct inode_operations afs_dir_inode_operations;
-extern struct file_operations afs_dir_file_operations;
+extern const struct file_operations afs_dir_file_operations;
 
 /*
  * file.c
@@ -105,7 +105,7 @@
  * mntpt.c
  */
 extern struct inode_operations afs_mntpt_inode_operations;
-extern struct file_operations afs_mntpt_file_operations;
+extern const struct file_operations afs_mntpt_file_operations;
 extern struct afs_timer afs_mntpt_expiry_timer;
 extern struct afs_timer_ops afs_mntpt_expiry_timer_ops;
 extern unsigned long afs_mntpt_expiry_timeout;
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 31ee065..4e6eeb5 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -32,7 +32,7 @@
 static int afs_mntpt_open(struct inode *inode, struct file *file);
 static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd);
 
-struct file_operations afs_mntpt_file_operations = {
+const struct file_operations afs_mntpt_file_operations = {
 	.open		= afs_mntpt_open,
 };
 
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 9c81b8f..101d21b 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -37,7 +37,7 @@
 	.show	= afs_proc_cells_show,
 };
 
-static struct file_operations afs_proc_cells_fops = {
+static const struct file_operations afs_proc_cells_fops = {
 	.open		= afs_proc_cells_open,
 	.read		= seq_read,
 	.write		= afs_proc_cells_write,
@@ -53,7 +53,7 @@
 				       const char __user *buf,
 				       size_t size, loff_t *_pos);
 
-static struct file_operations afs_proc_rootcell_fops = {
+static const struct file_operations afs_proc_rootcell_fops = {
 	.open		= afs_proc_rootcell_open,
 	.read		= afs_proc_rootcell_read,
 	.write		= afs_proc_rootcell_write,
@@ -77,7 +77,7 @@
 	.show	= afs_proc_cell_volumes_show,
 };
 
-static struct file_operations afs_proc_cell_volumes_fops = {
+static const struct file_operations afs_proc_cell_volumes_fops = {
 	.open		= afs_proc_cell_volumes_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
@@ -101,7 +101,7 @@
 	.show	= afs_proc_cell_vlservers_show,
 };
 
-static struct file_operations afs_proc_cell_vlservers_fops = {
+static const struct file_operations afs_proc_cell_vlservers_fops = {
 	.open		= afs_proc_cell_vlservers_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
@@ -124,7 +124,7 @@
 	.show	= afs_proc_cell_servers_show,
 };
 
-static struct file_operations afs_proc_cell_servers_fops = {
+static const struct file_operations afs_proc_cell_servers_fops = {
 	.open		= afs_proc_cell_servers_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
index 990c28d..a62327f 100644
--- a/fs/autofs/autofs_i.h
+++ b/fs/autofs/autofs_i.h
@@ -146,7 +146,7 @@
 
 extern struct inode_operations autofs_root_inode_operations;
 extern struct inode_operations autofs_symlink_inode_operations;
-extern struct file_operations autofs_root_operations;
+extern const struct file_operations autofs_root_operations;
 
 /* Initializing function */
 
diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c
index 5ccfcf2..3fded38 100644
--- a/fs/autofs/dirhash.c
+++ b/fs/autofs/dirhash.c
@@ -92,7 +92,7 @@
 			;
 		dput(dentry);
 
-		if ( may_umount(mnt) == 0 ) {
+		if ( may_umount(mnt) ) {
 			mntput(mnt);
 			DPRINTK(("autofs: signaling expire on %s\n", ent->name));
 			return ent; /* Expirable! */
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 870e2cf..9cac08d 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -26,7 +26,7 @@
 static int autofs_root_mkdir(struct inode *,struct dentry *,int);
 static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
 
-struct file_operations autofs_root_operations = {
+const struct file_operations autofs_root_operations = {
 	.read		= generic_read_dir,
 	.readdir	= autofs_root_readdir,
 	.ioctl		= autofs_root_ioctl,
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index f54c5b2..57c4903 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -3,6 +3,7 @@
  * linux/fs/autofs/autofs_i.h
  *
  *   Copyright 1997-1998 Transmeta Corporation - All Rights Reserved
+ *   Copyright 2005-2006 Ian Kent <raven@themaw.net>
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
@@ -41,14 +42,6 @@
 
 #define AUTOFS_SUPER_MAGIC 0x0187
 
-/*
- * If the daemon returns a negative response (AUTOFS_IOC_FAIL) then the
- * kernel will keep the negative response cached for up to the time given
- * here, although the time can be shorter if the kernel throws the dcache
- * entry away.  This probably should be settable from user space.
- */
-#define AUTOFS_NEGATIVE_TIMEOUT (60*HZ)	/* 1 minute */
-
 /* Unified info structure.  This is pointed to by both the dentry and
    inode structures.  Each file in the filesystem has an instance of this
    structure.  It holds a reference to the dentry, so dentries are never
@@ -63,6 +56,7 @@
 
 	struct autofs_sb_info *sbi;
 	unsigned long last_used;
+	atomic_t count;
 
 	mode_t	mode;
 	size_t	size;
@@ -83,23 +77,37 @@
 	int hash;
 	int len;
 	char *name;
+	u32 dev;
+	u64 ino;
+	uid_t uid;
+	gid_t gid;
+	pid_t pid;
+	pid_t tgid;
 	/* This is for status reporting upon return */
 	int status;
-	atomic_t notified;
+	atomic_t notify;
 	atomic_t wait_ctr;
 };
 
 #define AUTOFS_SBI_MAGIC 0x6d4a556d
 
+#define AUTOFS_TYPE_INDIRECT     0x0001
+#define AUTOFS_TYPE_DIRECT       0x0002
+#define AUTOFS_TYPE_OFFSET       0x0004
+
 struct autofs_sb_info {
 	u32 magic;
 	struct dentry *root;
+	int pipefd;
 	struct file *pipe;
 	pid_t oz_pgrp;
 	int catatonic;
 	int version;
 	int sub_version;
+	int min_proto;
+	int max_proto;
 	unsigned long exp_timeout;
+	unsigned int type;
 	int reghost_enabled;
 	int needs_reghost;
 	struct super_block *sb;
@@ -166,8 +174,10 @@
 extern struct inode_operations autofs4_symlink_inode_operations;
 extern struct inode_operations autofs4_dir_inode_operations;
 extern struct inode_operations autofs4_root_inode_operations;
-extern struct file_operations autofs4_dir_operations;
-extern struct file_operations autofs4_root_operations;
+extern struct inode_operations autofs4_indirect_root_inode_operations;
+extern struct inode_operations autofs4_direct_root_inode_operations;
+extern const struct file_operations autofs4_dir_operations;
+extern const struct file_operations autofs4_root_operations;
 
 /* Initializing function */
 
@@ -176,13 +186,6 @@
 
 /* Queue management functions */
 
-enum autofs_notify
-{
-	NFY_NONE,
-	NFY_MOUNT,
-	NFY_EXPIRE
-};
-
 int autofs4_wait(struct autofs_sb_info *,struct dentry *, enum autofs_notify);
 int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int);
 void autofs4_catatonic_mode(struct autofs_sb_info *);
@@ -200,12 +203,22 @@
 	return res;
 }
 
+static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi)
+{
+	return new_encode_dev(sbi->sb->s_dev);
+}
+
+static inline u64 autofs4_get_ino(struct autofs_sb_info *sbi)
+{
+	return sbi->sb->s_root->d_inode->i_ino;
+}
+
 static inline int simple_positive(struct dentry *dentry)
 {
 	return dentry->d_inode && !d_unhashed(dentry);
 }
 
-static inline int simple_empty_nolock(struct dentry *dentry)
+static inline int __simple_empty(struct dentry *dentry)
 {
 	struct dentry *child;
 	int ret = 0;
@@ -217,3 +230,6 @@
 out:
 	return ret;
 }
+
+void autofs4_dentry_release(struct dentry *);
+
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index dc39589..b8ce026 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -4,7 +4,7 @@
  *
  *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *  Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
- *  Copyright 2001-2003 Ian Kent <raven@themaw.net>
+ *  Copyright 2001-2006 Ian Kent <raven@themaw.net>
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
@@ -16,7 +16,7 @@
 
 static unsigned long now;
 
-/* Check if a dentry can be expired return 1 if it can else return 0 */
+/* Check if a dentry can be expired */
 static inline int autofs4_can_expire(struct dentry *dentry,
 					unsigned long timeout, int do_now)
 {
@@ -41,14 +41,14 @@
 		     attempts if expire fails the first time */
 		ino->last_used = now;
 	}
-
 	return 1;
 }
 
-/* Check a mount point for busyness return 1 if not busy, otherwise */
-static int autofs4_check_mount(struct vfsmount *mnt, struct dentry *dentry)
+/* Check a mount point for busyness */
+static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
 {
-	int status = 0;
+	struct dentry *top = dentry;
+	int status = 1;
 
 	DPRINTK("dentry %p %.*s",
 		dentry, (int)dentry->d_name.len, dentry->d_name.name);
@@ -63,9 +63,14 @@
 	if (is_autofs4_dentry(dentry))
 		goto done;
 
-	/* The big question */
-	if (may_umount_tree(mnt) == 0)
-		status = 1;
+	/* Update the expiry counter if fs is busy */
+	if (!may_umount_tree(mnt)) {
+		struct autofs_info *ino = autofs4_dentry_ino(top);
+		ino->last_used = jiffies;
+		goto done;
+	}
+
+	status = 0;
 done:
 	DPRINTK("returning = %d", status);
 	mntput(mnt);
@@ -73,78 +78,124 @@
 	return status;
 }
 
+/*
+ * Calculate next entry in top down tree traversal.
+ * From next_mnt in namespace.c - elegant.
+ */
+static struct dentry *next_dentry(struct dentry *p, struct dentry *root)
+{
+	struct list_head *next = p->d_subdirs.next;
+
+	if (next == &p->d_subdirs) {
+		while (1) {
+			if (p == root)
+				return NULL;
+			next = p->d_u.d_child.next;
+			if (next != &p->d_parent->d_subdirs)
+				break;
+			p = p->d_parent;
+		}
+	}
+	return list_entry(next, struct dentry, d_u.d_child);
+}
+
+/*
+ * Check a direct mount point for busyness.
+ * Direct mounts have similar expiry semantics to tree mounts.
+ * The tree is not busy iff no mountpoints are busy and there are no
+ * autofs submounts.
+ */
+static int autofs4_direct_busy(struct vfsmount *mnt,
+				struct dentry *top,
+				unsigned long timeout,
+				int do_now)
+{
+	DPRINTK("top %p %.*s",
+		top, (int) top->d_name.len, top->d_name.name);
+
+	/* If it's busy update the expiry counters */
+	if (!may_umount_tree(mnt)) {
+		struct autofs_info *ino = autofs4_dentry_ino(top);
+		if (ino)
+			ino->last_used = jiffies;
+		return 1;
+	}
+
+	/* Timeout of a direct mount is determined by its top dentry */
+	if (!autofs4_can_expire(top, timeout, do_now))
+		return 1;
+
+	return 0;
+}
+
 /* Check a directory tree of mount points for busyness
  * The tree is not busy iff no mountpoints are busy
- * Return 1 if the tree is busy or 0 otherwise
  */
-static int autofs4_check_tree(struct vfsmount *mnt,
-	       		      struct dentry *top,
-			      unsigned long timeout,
-			      int do_now)
+static int autofs4_tree_busy(struct vfsmount *mnt,
+	       		     struct dentry *top,
+			     unsigned long timeout,
+			     int do_now)
 {
-	struct dentry *this_parent = top;
-	struct list_head *next;
+	struct autofs_info *top_ino = autofs4_dentry_ino(top);
+	struct dentry *p;
 
-	DPRINTK("parent %p %.*s",
+	DPRINTK("top %p %.*s",
 		top, (int)top->d_name.len, top->d_name.name);
 
 	/* Negative dentry - give up */
 	if (!simple_positive(top))
-		return 0;
-
-	/* Timeout of a tree mount is determined by its top dentry */
-	if (!autofs4_can_expire(top, timeout, do_now))
-		return 0;
-
-	/* Is someone visiting anywhere in the tree ? */
-	if (may_umount_tree(mnt))
-		return 0;
+		return 1;
 
 	spin_lock(&dcache_lock);
-repeat:
-	next = this_parent->d_subdirs.next;
-resume:
-	while (next != &this_parent->d_subdirs) {
-		struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
-
+	for (p = top; p; p = next_dentry(p, top)) {
 		/* Negative dentry - give up */
-		if (!simple_positive(dentry)) {
-			next = next->next;
+		if (!simple_positive(p))
 			continue;
-		}
 
 		DPRINTK("dentry %p %.*s",
-			dentry, (int)dentry->d_name.len, dentry->d_name.name);
+			p, (int) p->d_name.len, p->d_name.name);
 
-		if (!simple_empty_nolock(dentry)) {
-			this_parent = dentry;
-			goto repeat;
-		}
-
-		dentry = dget(dentry);
+		p = dget(p);
 		spin_unlock(&dcache_lock);
 
-		if (d_mountpoint(dentry)) {
-			/* First busy => tree busy */
-			if (!autofs4_check_mount(mnt, dentry)) {
-				dput(dentry);
-				return 0;
+		/*
+		 * Is someone visiting anywhere in the subtree ?
+		 * If there's no mount we need to check the usage
+		 * count for the autofs dentry.
+		 * If the fs is busy update the expiry counter.
+		 */
+		if (d_mountpoint(p)) {
+			if (autofs4_mount_busy(mnt, p)) {
+				top_ino->last_used = jiffies;
+				dput(p);
+				return 1;
+			}
+		} else {
+			struct autofs_info *ino = autofs4_dentry_ino(p);
+			unsigned int ino_count = atomic_read(&ino->count);
+
+			/* allow for dget above and top is already dgot */
+			if (p == top)
+				ino_count += 2;
+			else
+				ino_count++;
+
+			if (atomic_read(&p->d_count) > ino_count) {
+				top_ino->last_used = jiffies;
+				dput(p);
+				return 1;
 			}
 		}
-
-		dput(dentry);
+		dput(p);
 		spin_lock(&dcache_lock);
-		next = next->next;
-	}
-
-	if (this_parent != top) {
-		next = this_parent->d_u.d_child.next;
-		this_parent = this_parent->d_parent;
-		goto resume;
 	}
 	spin_unlock(&dcache_lock);
 
-	return 1;
+	/* Timeout of a tree mount is ultimately determined by its top dentry */
+	if (!autofs4_can_expire(top, timeout, do_now))
+		return 1;
+
+	return 0;
 }
 
 static struct dentry *autofs4_check_leaves(struct vfsmount *mnt,
@@ -152,58 +203,68 @@
 					   unsigned long timeout,
 					   int do_now)
 {
-	struct dentry *this_parent = parent;
-	struct list_head *next;
+	struct dentry *p;
 
 	DPRINTK("parent %p %.*s",
 		parent, (int)parent->d_name.len, parent->d_name.name);
 
 	spin_lock(&dcache_lock);
-repeat:
-	next = this_parent->d_subdirs.next;
-resume:
-	while (next != &this_parent->d_subdirs) {
-		struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
-
+	for (p = parent; p; p = next_dentry(p, parent)) {
 		/* Negative dentry - give up */
-		if (!simple_positive(dentry)) {
-			next = next->next;
+		if (!simple_positive(p))
 			continue;
-		}
 
 		DPRINTK("dentry %p %.*s",
-			dentry, (int)dentry->d_name.len, dentry->d_name.name);
+			p, (int) p->d_name.len, p->d_name.name);
 
-		if (!list_empty(&dentry->d_subdirs)) {
-			this_parent = dentry;
-			goto repeat;
-		}
-
-		dentry = dget(dentry);
+		p = dget(p);
 		spin_unlock(&dcache_lock);
 
-		if (d_mountpoint(dentry)) {
-			/* Can we expire this guy */
-			if (!autofs4_can_expire(dentry, timeout, do_now))
+		if (d_mountpoint(p)) {
+			/* Can we umount this guy */
+			if (autofs4_mount_busy(mnt, p))
 				goto cont;
 
-			/* Can we umount this guy */
-			if (autofs4_check_mount(mnt, dentry))
-				return dentry;
-
+			/* Can we expire this guy */
+			if (autofs4_can_expire(p, timeout, do_now))
+				return p;
 		}
 cont:
-		dput(dentry);
+		dput(p);
 		spin_lock(&dcache_lock);
-		next = next->next;
-	}
-
-	if (this_parent != parent) {
-		next = this_parent->d_u.d_child.next;
-		this_parent = this_parent->d_parent;
-		goto resume;
 	}
 	spin_unlock(&dcache_lock);
+	return NULL;
+}
+
+/* Check if we can expire a direct mount (possibly a tree) */
+static struct dentry *autofs4_expire_direct(struct super_block *sb,
+					    struct vfsmount *mnt,
+					    struct autofs_sb_info *sbi,
+					    int how)
+{
+	unsigned long timeout;
+	struct dentry *root = dget(sb->s_root);
+	int do_now = how & AUTOFS_EXP_IMMEDIATE;
+
+	if (!sbi->exp_timeout || !root)
+		return NULL;
+
+	now = jiffies;
+	timeout = sbi->exp_timeout;
+
+	/* Lock the tree as we must expire as a whole */
+	spin_lock(&sbi->fs_lock);
+	if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
+		struct autofs_info *ino = autofs4_dentry_ino(root);
+
+		/* Set this flag early to catch sys_chdir and the like */
+		ino->flags |= AUTOFS_INF_EXPIRING;
+		spin_unlock(&sbi->fs_lock);
+		return root;
+	}
+	spin_unlock(&sbi->fs_lock);
+	dput(root);
 
 	return NULL;
 }
@@ -214,10 +275,10 @@
  *  - it is unused by any user process
  *  - it has been unused for exp_timeout time
  */
-static struct dentry *autofs4_expire(struct super_block *sb,
-				     struct vfsmount *mnt,
-				     struct autofs_sb_info *sbi,
-				     int how)
+static struct dentry *autofs4_expire_indirect(struct super_block *sb,
+					      struct vfsmount *mnt,
+					      struct autofs_sb_info *sbi,
+					      int how)
 {
 	unsigned long timeout;
 	struct dentry *root = sb->s_root;
@@ -241,7 +302,7 @@
 		struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
 
 		/* Negative dentry - give up */
-		if ( !simple_positive(dentry) ) {
+		if (!simple_positive(dentry)) {
 			next = next->next;
 			continue;
 		}
@@ -249,31 +310,36 @@
 		dentry = dget(dentry);
 		spin_unlock(&dcache_lock);
 
-		/* Case 1: indirect mount or top level direct mount */
+		/*
+		 * Case 1: (i) indirect mount or top level pseudo direct mount
+		 *	   (autofs-4.1).
+		 *	   (ii) indirect mount with offset mount, check the "/"
+		 *	   offset (autofs-5.0+).
+		 */
 		if (d_mountpoint(dentry)) {
 			DPRINTK("checking mountpoint %p %.*s",
 				dentry, (int)dentry->d_name.len, dentry->d_name.name);
 
-			/* Can we expire this guy */
-			if (!autofs4_can_expire(dentry, timeout, do_now))
+			/* Can we umount this guy */
+			if (autofs4_mount_busy(mnt, dentry))
 				goto next;
 
-			/* Can we umount this guy */
-			if (autofs4_check_mount(mnt, dentry)) {
+			/* Can we expire this guy */
+			if (autofs4_can_expire(dentry, timeout, do_now)) {
 				expired = dentry;
 				break;
 			}
 			goto next;
 		}
 
-		if ( simple_empty(dentry) )
+		if (simple_empty(dentry))
 			goto next;
 
 		/* Case 2: tree mount, expire iff entire tree is not busy */
 		if (!exp_leaves) {
 			/* Lock the tree as we must expire as a whole */
 			spin_lock(&sbi->fs_lock);
-			if (autofs4_check_tree(mnt, dentry, timeout, do_now)) {
+			if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) {
 				struct autofs_info *inf = autofs4_dentry_ino(dentry);
 
 				/* Set this flag early to catch sys_chdir and the like */
@@ -283,7 +349,10 @@
 				break;
 			}
 			spin_unlock(&sbi->fs_lock);
-		/* Case 3: direct mount, expire individual leaves */
+		/*
+		 * Case 3: pseudo direct mount, expire individual leaves
+		 *	   (autofs-4.1).
+		 */
 		} else {
 			expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
 			if (expired) {
@@ -297,7 +366,7 @@
 		next = next->next;
 	}
 
-	if ( expired ) {
+	if (expired) {
 		DPRINTK("returning %p %.*s",
 			expired, (int)expired->d_name.len, expired->d_name.name);
 		spin_lock(&dcache_lock);
@@ -325,7 +394,7 @@
 	pkt.hdr.proto_version = sbi->version;
 	pkt.hdr.type = autofs_ptype_expire;
 
-	if ((dentry = autofs4_expire(sb, mnt, sbi, 0)) == NULL)
+	if ((dentry = autofs4_expire_indirect(sb, mnt, sbi, 0)) == NULL)
 		return -EAGAIN;
 
 	pkt.len = dentry->d_name.len;
@@ -351,17 +420,22 @@
 	if (arg && get_user(do_now, arg))
 		return -EFAULT;
 
-	if ((dentry = autofs4_expire(sb, mnt, sbi, do_now)) != NULL) {
-		struct autofs_info *de_info = autofs4_dentry_ino(dentry);
+	if (sbi->type & AUTOFS_TYPE_DIRECT)
+		dentry = autofs4_expire_direct(sb, mnt, sbi, do_now);
+	else
+		dentry = autofs4_expire_indirect(sb, mnt, sbi, do_now);
+
+	if (dentry) {
+		struct autofs_info *ino = autofs4_dentry_ino(dentry);
 
 		/* This is synchronous because it makes the daemon a
                    little easier */
-		de_info->flags |= AUTOFS_INF_EXPIRING;
+		ino->flags |= AUTOFS_INF_EXPIRING;
 		ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
-		de_info->flags &= ~AUTOFS_INF_EXPIRING;
+		ino->flags &= ~AUTOFS_INF_EXPIRING;
 		dput(dentry);
 	}
-		
+
 	return ret;
 }
 
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 1ad98d4..fde78b1 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -3,6 +3,7 @@
  * linux/fs/autofs/inode.c
  *
  *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
+ *  Copyright 2005-2006 Ian Kent <raven@themaw.net>
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
@@ -13,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/file.h>
+#include <linux/seq_file.h>
 #include <linux/pagemap.h>
 #include <linux/parser.h>
 #include <linux/bitops.h>
@@ -46,6 +48,7 @@
 	ino->size = 0;
 
 	ino->last_used = jiffies;
+	atomic_set(&ino->count, 0);
 
 	ino->sbi = sbi;
 
@@ -64,10 +67,19 @@
 
 void autofs4_free_ino(struct autofs_info *ino)
 {
+	struct autofs_info *p_ino;
+
 	if (ino->dentry) {
 		ino->dentry->d_fsdata = NULL;
-		if (ino->dentry->d_inode)
+		if (ino->dentry->d_inode) {
+			struct dentry *parent = ino->dentry->d_parent;
+			if (atomic_dec_and_test(&ino->count)) {
+				p_ino = autofs4_dentry_ino(parent);
+				if (p_ino && parent != ino->dentry)
+					atomic_dec(&p_ino->count);
+			}
 			dput(ino->dentry);
+		}
 		ino->dentry = NULL;
 	}
 	if (ino->free)
@@ -145,20 +157,44 @@
 		autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */
 
 	/* Clean up and release dangling references */
-	if (sbi)
-		autofs4_force_release(sbi);
+	autofs4_force_release(sbi);
 
 	kfree(sbi);
 
 	DPRINTK("shutting down");
 }
 
+static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+	struct autofs_sb_info *sbi = autofs4_sbi(mnt->mnt_sb);
+
+	if (!sbi)
+		return 0;
+
+	seq_printf(m, ",fd=%d", sbi->pipefd);
+	seq_printf(m, ",pgrp=%d", sbi->oz_pgrp);
+	seq_printf(m, ",timeout=%lu", sbi->exp_timeout/HZ);
+	seq_printf(m, ",minproto=%d", sbi->min_proto);
+	seq_printf(m, ",maxproto=%d", sbi->max_proto);
+
+	if (sbi->type & AUTOFS_TYPE_OFFSET)
+		seq_printf(m, ",offset");
+	else if (sbi->type & AUTOFS_TYPE_DIRECT)
+		seq_printf(m, ",direct");
+	else
+		seq_printf(m, ",indirect");
+
+	return 0;
+}
+
 static struct super_operations autofs4_sops = {
 	.put_super	= autofs4_put_super,
 	.statfs		= simple_statfs,
+	.show_options	= autofs4_show_options,
 };
 
-enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto};
+enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto,
+	Opt_indirect, Opt_direct, Opt_offset};
 
 static match_table_t tokens = {
 	{Opt_fd, "fd=%u"},
@@ -167,11 +203,15 @@
 	{Opt_pgrp, "pgrp=%u"},
 	{Opt_minproto, "minproto=%u"},
 	{Opt_maxproto, "maxproto=%u"},
+	{Opt_indirect, "indirect"},
+	{Opt_direct, "direct"},
+	{Opt_offset, "offset"},
 	{Opt_err, NULL}
 };
 
 static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
-			 pid_t *pgrp, int *minproto, int *maxproto)
+			 pid_t *pgrp, unsigned int *type,
+			 int *minproto, int *maxproto)
 {
 	char *p;
 	substring_t args[MAX_OPT_ARGS];
@@ -225,6 +265,15 @@
 				return 1;
 			*maxproto = option;
 			break;
+		case Opt_indirect:
+			*type = AUTOFS_TYPE_INDIRECT;
+			break;
+		case Opt_direct:
+			*type = AUTOFS_TYPE_DIRECT;
+			break;
+		case Opt_offset:
+			*type = AUTOFS_TYPE_DIRECT | AUTOFS_TYPE_OFFSET;
+			break;
 		default:
 			return 1;
 		}
@@ -243,6 +292,10 @@
 	return ino;
 }
 
+static struct dentry_operations autofs4_sb_dentry_operations = {
+	.d_release      = autofs4_dentry_release,
+};
+
 int autofs4_fill_super(struct super_block *s, void *data, int silent)
 {
 	struct inode * root_inode;
@@ -251,7 +304,6 @@
 	int pipefd;
 	struct autofs_sb_info *sbi;
 	struct autofs_info *ino;
-	int minproto, maxproto;
 
 	sbi = (struct autofs_sb_info *) kmalloc(sizeof(*sbi), GFP_KERNEL);
 	if ( !sbi )
@@ -263,12 +315,16 @@
 	s->s_fs_info = sbi;
 	sbi->magic = AUTOFS_SBI_MAGIC;
 	sbi->root = NULL;
+	sbi->pipefd = -1;
 	sbi->catatonic = 0;
 	sbi->exp_timeout = 0;
 	sbi->oz_pgrp = process_group(current);
 	sbi->sb = s;
 	sbi->version = 0;
 	sbi->sub_version = 0;
+	sbi->type = 0;
+	sbi->min_proto = 0;
+	sbi->max_proto = 0;
 	mutex_init(&sbi->wq_mutex);
 	spin_lock_init(&sbi->fs_lock);
 	sbi->queues = NULL;
@@ -285,38 +341,46 @@
 	if (!ino)
 		goto fail_free;
 	root_inode = autofs4_get_inode(s, ino);
-	kfree(ino);
 	if (!root_inode)
-		goto fail_free;
+		goto fail_ino;
 
-	root_inode->i_op = &autofs4_root_inode_operations;
-	root_inode->i_fop = &autofs4_root_operations;
 	root = d_alloc_root(root_inode);
-	pipe = NULL;
-
 	if (!root)
 		goto fail_iput;
+	pipe = NULL;
+
+	root->d_op = &autofs4_sb_dentry_operations;
+	root->d_fsdata = ino;
 
 	/* Can this call block? */
 	if (parse_options(data, &pipefd,
 			  &root_inode->i_uid, &root_inode->i_gid,
-			  &sbi->oz_pgrp,
-			  &minproto, &maxproto)) {
+			  &sbi->oz_pgrp, &sbi->type,
+			  &sbi->min_proto, &sbi->max_proto)) {
 		printk("autofs: called with bogus options\n");
 		goto fail_dput;
 	}
 
+	root_inode->i_fop = &autofs4_root_operations;
+	root_inode->i_op = sbi->type & AUTOFS_TYPE_DIRECT ?
+			&autofs4_direct_root_inode_operations :
+			&autofs4_indirect_root_inode_operations;
+
 	/* Couldn't this be tested earlier? */
-	if (maxproto < AUTOFS_MIN_PROTO_VERSION ||
-	    minproto > AUTOFS_MAX_PROTO_VERSION) {
+	if (sbi->max_proto < AUTOFS_MIN_PROTO_VERSION ||
+	    sbi->min_proto > AUTOFS_MAX_PROTO_VERSION) {
 		printk("autofs: kernel does not match daemon version "
 		       "daemon (%d, %d) kernel (%d, %d)\n",
-			minproto, maxproto,
+			sbi->min_proto, sbi->max_proto,
 			AUTOFS_MIN_PROTO_VERSION, AUTOFS_MAX_PROTO_VERSION);
 		goto fail_dput;
 	}
 
-	sbi->version = maxproto > AUTOFS_MAX_PROTO_VERSION ? AUTOFS_MAX_PROTO_VERSION : maxproto;
+	/* Establish highest kernel protocol version */
+	if (sbi->max_proto > AUTOFS_MAX_PROTO_VERSION)
+		sbi->version = AUTOFS_MAX_PROTO_VERSION;
+	else
+		sbi->version = sbi->max_proto;
 	sbi->sub_version = AUTOFS_PROTO_SUBVERSION;
 
 	DPRINTK("pipe fd = %d, pgrp = %u", pipefd, sbi->oz_pgrp);
@@ -329,6 +393,7 @@
 	if ( !pipe->f_op || !pipe->f_op->write )
 		goto fail_fput;
 	sbi->pipe = pipe;
+	sbi->pipefd = pipefd;
 
 	/*
 	 * Take a reference to the root dentry so we get a chance to
@@ -356,6 +421,8 @@
 fail_iput:
 	printk("autofs: get root dentry failed\n");
 	iput(root_inode);
+fail_ino:
+	kfree(ino);
 fail_free:
 	kfree(sbi);
 fail_unlock:
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 62d8d4a..84e030c 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -4,7 +4,7 @@
  *
  *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *  Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
- *  Copyright 2001-2003 Ian Kent <raven@themaw.net>
+ *  Copyright 2001-2006 Ian Kent <raven@themaw.net>
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
@@ -30,9 +30,9 @@
 static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir);
 static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir);
 static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
-static int autofs4_dcache_readdir(struct file *, void *, filldir_t);
+static void *autofs4_follow_link(struct dentry *, struct nameidata *);
 
-struct file_operations autofs4_root_operations = {
+const struct file_operations autofs4_root_operations = {
 	.open		= dcache_dir_open,
 	.release	= dcache_dir_close,
 	.read		= generic_read_dir,
@@ -40,14 +40,14 @@
 	.ioctl		= autofs4_root_ioctl,
 };
 
-struct file_operations autofs4_dir_operations = {
+const struct file_operations autofs4_dir_operations = {
 	.open		= autofs4_dir_open,
 	.release	= autofs4_dir_close,
 	.read		= generic_read_dir,
 	.readdir	= autofs4_dir_readdir,
 };
 
-struct inode_operations autofs4_root_inode_operations = {
+struct inode_operations autofs4_indirect_root_inode_operations = {
 	.lookup		= autofs4_lookup,
 	.unlink		= autofs4_dir_unlink,
 	.symlink	= autofs4_dir_symlink,
@@ -55,6 +55,14 @@
 	.rmdir		= autofs4_dir_rmdir,
 };
 
+struct inode_operations autofs4_direct_root_inode_operations = {
+	.lookup		= autofs4_lookup,
+	.unlink		= autofs4_dir_unlink,
+	.mkdir		= autofs4_dir_mkdir,
+	.rmdir		= autofs4_dir_rmdir,
+	.follow_link	= autofs4_follow_link,
+};
+
 struct inode_operations autofs4_dir_inode_operations = {
 	.lookup		= autofs4_lookup,
 	.unlink		= autofs4_dir_unlink,
@@ -82,87 +90,7 @@
 
 	DPRINTK("needs_reghost = %d", sbi->needs_reghost);
 
-	return autofs4_dcache_readdir(file, dirent, filldir);
-}
-
-/* Update usage from here to top of tree, so that scan of
-   top-level directories will give a useful result */
-static void autofs4_update_usage(struct vfsmount *mnt, struct dentry *dentry)
-{
-	struct dentry *top = dentry->d_sb->s_root;
-
-	spin_lock(&dcache_lock);
-	for(; dentry != top; dentry = dentry->d_parent) {
-		struct autofs_info *ino = autofs4_dentry_ino(dentry);
-
-		if (ino) {
-			touch_atime(mnt, dentry);
-			ino->last_used = jiffies;
-		}
-	}
-	spin_unlock(&dcache_lock);
-}
-
-/*
- * From 2.4 kernel readdir.c
- */
-static int autofs4_dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
-{
-	int i;
-	struct dentry *dentry = filp->f_dentry;
-
-	i = filp->f_pos;
-	switch (i) {
-		case 0:
-			if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino, DT_DIR) < 0)
-				break;
-			i++;
-			filp->f_pos++;
-			/* fallthrough */
-		case 1:
-			if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
-				break;
-			i++;
-			filp->f_pos++;
-			/* fallthrough */
-		default: {
-			struct list_head *list;
-			int j = i-2;
-
-			spin_lock(&dcache_lock);
-			list = dentry->d_subdirs.next;
-
-			for (;;) {
-				if (list == &dentry->d_subdirs) {
-					spin_unlock(&dcache_lock);
-					return 0;
-				}
-				if (!j)
-					break;
-				j--;
-				list = list->next;
-			}
-
-			while(1) {
-				struct dentry *de = list_entry(list,
-						struct dentry, d_u.d_child);
-
-				if (!d_unhashed(de) && de->d_inode) {
-					spin_unlock(&dcache_lock);
-					if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino, DT_UNKNOWN) < 0)
-						break;
-					spin_lock(&dcache_lock);
-				}
-				filp->f_pos++;
-				list = list->next;
-				if (list != &dentry->d_subdirs)
-					continue;
-				spin_unlock(&dcache_lock);
-				break;
-			}
-		}
-	}
-	return 0;
+	return dcache_readdir(file, dirent, filldir);
 }
 
 static int autofs4_dir_open(struct inode *inode, struct file *file)
@@ -170,8 +98,16 @@
 	struct dentry *dentry = file->f_dentry;
 	struct vfsmount *mnt = file->f_vfsmnt;
 	struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+	struct dentry *cursor;
 	int status;
 
+	status = dcache_dir_open(inode, file);
+	if (status)
+		goto out;
+
+	cursor = file->private_data;
+	cursor->d_fsdata = NULL;
+
 	DPRINTK("file=%p dentry=%p %.*s",
 		file, dentry, dentry->d_name.len, dentry->d_name.name);
 
@@ -180,12 +116,15 @@
 
 	if (autofs4_ispending(dentry)) {
 		DPRINTK("dentry busy");
-		return -EBUSY;
+		dcache_dir_close(inode, file);
+		status = -EBUSY;
+		goto out;
 	}
 
+	status = -ENOENT;
 	if (!d_mountpoint(dentry) && dentry->d_op && dentry->d_op->d_revalidate) {
 		struct nameidata nd;
-		int empty;
+		int empty, ret;
 
 		/* In case there are stale directory dentrys from a failed mount */
 		spin_lock(&dcache_lock);
@@ -195,13 +134,13 @@
 		if (!empty)
 			d_invalidate(dentry);
 
-		nd.dentry = dentry;
-		nd.mnt = mnt;
 		nd.flags = LOOKUP_DIRECTORY;
-		status = (dentry->d_op->d_revalidate)(dentry, &nd);
+		ret = (dentry->d_op->d_revalidate)(dentry, &nd);
 
-		if (!status)
-			return -ENOENT;
+		if (!ret) {
+			dcache_dir_close(inode, file);
+			goto out;
+		}
 	}
 
 	if (d_mountpoint(dentry)) {
@@ -212,25 +151,29 @@
 		if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) {
 			dput(fp_dentry);
 			mntput(fp_mnt);
-			return -ENOENT;
+			dcache_dir_close(inode, file);
+			goto out;
 		}
 
 		fp = dentry_open(fp_dentry, fp_mnt, file->f_flags);
 		status = PTR_ERR(fp);
 		if (IS_ERR(fp)) {
-			file->private_data = NULL;
-			return status;
+			dcache_dir_close(inode, file);
+			goto out;
 		}
-		file->private_data = fp;
+		cursor->d_fsdata = fp;
 	}
-out:
 	return 0;
+out:
+	return status;
 }
 
 static int autofs4_dir_close(struct inode *inode, struct file *file)
 {
 	struct dentry *dentry = file->f_dentry;
 	struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+	struct dentry *cursor = file->private_data;
+	int status = 0;
 
 	DPRINTK("file=%p dentry=%p %.*s",
 		file, dentry, dentry->d_name.len, dentry->d_name.name);
@@ -240,26 +183,28 @@
 
 	if (autofs4_ispending(dentry)) {
 		DPRINTK("dentry busy");
-		return -EBUSY;
+		status = -EBUSY;
+		goto out;
 	}
 
 	if (d_mountpoint(dentry)) {
-		struct file *fp = file->private_data;
-
-		if (!fp)
-			return -ENOENT;
-
+		struct file *fp = cursor->d_fsdata;
+		if (!fp) {
+			status = -ENOENT;
+			goto out;
+		}
 		filp_close(fp, current->files);
-		file->private_data = NULL;
 	}
 out:
-	return 0;
+	dcache_dir_close(inode, file);
+	return status;
 }
 
 static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldir)
 {
 	struct dentry *dentry = file->f_dentry;
 	struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+	struct dentry *cursor = file->private_data;
 	int status;
 
 	DPRINTK("file=%p dentry=%p %.*s",
@@ -274,7 +219,7 @@
 	}
 
 	if (d_mountpoint(dentry)) {
-		struct file *fp = file->private_data;
+		struct file *fp = cursor->d_fsdata;
 
 		if (!fp)
 			return -ENOENT;
@@ -289,27 +234,26 @@
 		return status;
 	}
 out:
-	return autofs4_dcache_readdir(file, dirent, filldir);
+	return dcache_readdir(file, dirent, filldir);
 }
 
-static int try_to_fill_dentry(struct vfsmount *mnt, struct dentry *dentry, int flags)
+static int try_to_fill_dentry(struct dentry *dentry, int flags)
 {
-	struct super_block *sb = mnt->mnt_sb;
-	struct autofs_sb_info *sbi = autofs4_sbi(sb);
-	struct autofs_info *de_info = autofs4_dentry_ino(dentry);
+	struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+	struct autofs_info *ino = autofs4_dentry_ino(dentry);
 	int status = 0;
 
 	/* Block on any pending expiry here; invalidate the dentry
            when expiration is done to trigger mount request with a new
            dentry */
-	if (de_info && (de_info->flags & AUTOFS_INF_EXPIRING)) {
+	if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) {
 		DPRINTK("waiting for expire %p name=%.*s",
 			 dentry, dentry->d_name.len, dentry->d_name.name);
 
 		status = autofs4_wait(sbi, dentry, NFY_NONE);
-		
+
 		DPRINTK("expire done status=%d", status);
-		
+
 		/*
 		 * If the directory still exists the mount request must
 		 * continue otherwise it can't be followed at the right
@@ -317,34 +261,36 @@
 		 */
 		status = d_invalidate(dentry);
 		if (status != -EBUSY)
-			return 0;
+			return -ENOENT;
 	}
 
 	DPRINTK("dentry=%p %.*s ino=%p",
 		 dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
 
-	/* Wait for a pending mount, triggering one if there isn't one already */
+	/*
+	 * Wait for a pending mount, triggering one if there
+	 * isn't one already
+	 */
 	if (dentry->d_inode == NULL) {
 		DPRINTK("waiting for mount name=%.*s",
 			 dentry->d_name.len, dentry->d_name.name);
 
 		status = autofs4_wait(sbi, dentry, NFY_MOUNT);
-		 
+
 		DPRINTK("mount done status=%d", status);
 
 		if (status && dentry->d_inode)
-			return 0; /* Try to get the kernel to invalidate this dentry */
-		
+			return status; /* Try to get the kernel to invalidate this dentry */
+
 		/* Turn this into a real negative dentry? */
 		if (status == -ENOENT) {
-			dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT;
 			spin_lock(&dentry->d_lock);
 			dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
 			spin_unlock(&dentry->d_lock);
-			return 1;
+			return status;
 		} else if (status) {
 			/* Return a negative dentry, but leave it "pending" */
-			return 1;
+			return status;
 		}
 	/* Trigger mount for path component or follow link */
 	} else if (flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) ||
@@ -363,19 +309,87 @@
 			spin_lock(&dentry->d_lock);
 			dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
 			spin_unlock(&dentry->d_lock);
-			return 0;
+			return status;
 		}
 	}
 
-	/* We don't update the usages for the autofs daemon itself, this
-	   is necessary for recursive autofs mounts */
-	if (!autofs4_oz_mode(sbi))
-		autofs4_update_usage(mnt, dentry);
+	/* Initialize expiry counter after successful mount */
+	if (ino)
+		ino->last_used = jiffies;
 
 	spin_lock(&dentry->d_lock);
 	dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
 	spin_unlock(&dentry->d_lock);
-	return 1;
+	return status;
+}
+
+/* For autofs direct mounts the follow link triggers the mount */
+static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+	int oz_mode = autofs4_oz_mode(sbi);
+	unsigned int lookup_type;
+	int status;
+
+	DPRINTK("dentry=%p %.*s oz_mode=%d nd->flags=%d",
+		dentry, dentry->d_name.len, dentry->d_name.name, oz_mode,
+		nd->flags);
+
+	/* If it's our master or we shouldn't trigger a mount we're done */
+	lookup_type = nd->flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY);
+	if (oz_mode || !lookup_type)
+		goto done;
+
+	/*
+	 * If a request is pending wait for it.
+	 * If it's a mount then it won't be expired till at least
+	 * a liitle later and if it's an expire then we might need
+	 * to mount it again.
+	 */
+	if (autofs4_ispending(dentry)) {
+		DPRINTK("waiting for active request %p name=%.*s",
+			dentry, dentry->d_name.len, dentry->d_name.name);
+
+		status = autofs4_wait(sbi, dentry, NFY_NONE);
+
+		DPRINTK("request done status=%d", status);
+	}
+
+	/*
+	 * If the dentry contains directories then it is an
+	 * autofs multi-mount with no root mount offset. So
+	 * don't try to mount it again.
+	 */
+	spin_lock(&dcache_lock);
+	if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
+		spin_unlock(&dcache_lock);
+
+		status = try_to_fill_dentry(dentry, 0);
+		if (status)
+			goto out_error;
+
+		/*
+		 * The mount succeeded but if there is no root mount
+		 * it must be an autofs multi-mount with no root offset
+		 * so we don't need to follow the mount.
+		 */
+		if (d_mountpoint(dentry)) {
+			if (!autofs4_follow_mount(&nd->mnt, &nd->dentry)) {
+				status = -ENOENT;
+				goto out_error;
+			}
+		}
+
+		goto done;
+	}
+	spin_unlock(&dcache_lock);
+
+done:
+	return NULL;
+
+out_error:
+	path_release(nd);
+	return ERR_PTR(status);
 }
 
 /*
@@ -384,47 +398,43 @@
  * yet completely filled in, and revalidate has to delay such
  * lookups..
  */
-static int autofs4_revalidate(struct dentry * dentry, struct nameidata *nd)
+static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
-	struct inode * dir = dentry->d_parent->d_inode;
+	struct inode *dir = dentry->d_parent->d_inode;
 	struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
 	int oz_mode = autofs4_oz_mode(sbi);
 	int flags = nd ? nd->flags : 0;
-	int status = 1;
+	int status = 0;
 
 	/* Pending dentry */
 	if (autofs4_ispending(dentry)) {
 		if (!oz_mode)
-			status = try_to_fill_dentry(nd->mnt, dentry, flags);
-		return status;
+			status = try_to_fill_dentry(dentry, flags);
+		return !status;
 	}
 
 	/* Negative dentry.. invalidate if "old" */
 	if (dentry->d_inode == NULL)
-		return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT);
+		return 0;
 
 	/* Check for a non-mountpoint directory with no contents */
 	spin_lock(&dcache_lock);
 	if (S_ISDIR(dentry->d_inode->i_mode) &&
 	    !d_mountpoint(dentry) && 
-	    list_empty(&dentry->d_subdirs)) {
+	    __simple_empty(dentry)) {
 		DPRINTK("dentry=%p %.*s, emptydir",
 			 dentry, dentry->d_name.len, dentry->d_name.name);
 		spin_unlock(&dcache_lock);
 		if (!oz_mode)
-			status = try_to_fill_dentry(nd->mnt, dentry, flags);
-		return status;
+			status = try_to_fill_dentry(dentry, flags);
+		return !status;
 	}
 	spin_unlock(&dcache_lock);
 
-	/* Update the usage list */
-	if (!oz_mode)
-		autofs4_update_usage(nd->mnt, dentry);
-
 	return 1;
 }
 
-static void autofs4_dentry_release(struct dentry *de)
+void autofs4_dentry_release(struct dentry *de)
 {
 	struct autofs_info *inf;
 
@@ -462,12 +472,13 @@
 	DPRINTK("name = %.*s",
 		dentry->d_name.len, dentry->d_name.name);
 
+	/* File name too long to exist */
 	if (dentry->d_name.len > NAME_MAX)
-		return ERR_PTR(-ENAMETOOLONG);/* File name too long to exist */
+		return ERR_PTR(-ENAMETOOLONG);
 
 	sbi = autofs4_sbi(dir->i_sb);
-
 	oz_mode = autofs4_oz_mode(sbi);
+
 	DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d",
 		 current->pid, process_group(current), sbi->catatonic, oz_mode);
 
@@ -519,7 +530,7 @@
 	 * doesn't do the right thing for all system calls, but it should
 	 * be OK for the operations we permit from an autofs.
 	 */
-	if ( dentry->d_inode && d_unhashed(dentry) )
+	if (dentry->d_inode && d_unhashed(dentry))
 		return ERR_PTR(-ENOENT);
 
 	return NULL;
@@ -531,6 +542,7 @@
 {
 	struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
 	struct autofs_info *ino = autofs4_dentry_ino(dentry);
+	struct autofs_info *p_ino;
 	struct inode *inode;
 	char *cp;
 
@@ -564,6 +576,10 @@
 
 	dentry->d_fsdata = ino;
 	ino->dentry = dget(dentry);
+	atomic_inc(&ino->count);
+	p_ino = autofs4_dentry_ino(dentry->d_parent);
+	if (p_ino && dentry->d_parent != dentry)
+		atomic_inc(&p_ino->count);
 	ino->inode = inode;
 
 	dir->i_mtime = CURRENT_TIME;
@@ -590,11 +606,17 @@
 {
 	struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
 	struct autofs_info *ino = autofs4_dentry_ino(dentry);
+	struct autofs_info *p_ino;
 	
 	/* This allows root to remove symlinks */
 	if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
 		return -EACCES;
 
+	if (atomic_dec_and_test(&ino->count)) {
+		p_ino = autofs4_dentry_ino(dentry->d_parent);
+		if (p_ino && dentry->d_parent != dentry)
+			atomic_dec(&p_ino->count);
+	}
 	dput(ino->dentry);
 
 	dentry->d_inode->i_size = 0;
@@ -611,6 +633,7 @@
 {
 	struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
 	struct autofs_info *ino = autofs4_dentry_ino(dentry);
+	struct autofs_info *p_ino;
 	
 	if (!autofs4_oz_mode(sbi))
 		return -EACCES;
@@ -625,8 +648,12 @@
 	spin_unlock(&dentry->d_lock);
 	spin_unlock(&dcache_lock);
 
+	if (atomic_dec_and_test(&ino->count)) {
+		p_ino = autofs4_dentry_ino(dentry->d_parent);
+		if (p_ino && dentry->d_parent != dentry)
+			atomic_dec(&p_ino->count);
+	}
 	dput(ino->dentry);
-
 	dentry->d_inode->i_size = 0;
 	dentry->d_inode->i_nlink = 0;
 
@@ -640,6 +667,7 @@
 {
 	struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
 	struct autofs_info *ino = autofs4_dentry_ino(dentry);
+	struct autofs_info *p_ino;
 	struct inode *inode;
 
 	if ( !autofs4_oz_mode(sbi) )
@@ -662,6 +690,10 @@
 
 	dentry->d_fsdata = ino;
 	ino->dentry = dget(dentry);
+	atomic_inc(&ino->count);
+	p_ino = autofs4_dentry_ino(dentry->d_parent);
+	if (p_ino && dentry->d_parent != dentry)
+		atomic_inc(&p_ino->count);
 	ino->inode = inode;
 	dir->i_nlink++;
 	dir->i_mtime = CURRENT_TIME;
@@ -745,7 +777,7 @@
 {
 	int status = 0;
 
-	if (may_umount(mnt) == 0)
+	if (may_umount(mnt))
 		status = 1;
 
 	DPRINTK("returning %d", status);
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index be78e93..142ab6a 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -3,7 +3,7 @@
  * linux/fs/autofs/waitq.c
  *
  *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
- *  Copyright 2001-2003 Ian Kent <raven@themaw.net>
+ *  Copyright 2001-2006 Ian Kent <raven@themaw.net>
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
@@ -33,7 +33,7 @@
 	sbi->catatonic = 1;
 	wq = sbi->queues;
 	sbi->queues = NULL;	/* Erase all wait queues */
-	while ( wq ) {
+	while (wq) {
 		nwq = wq->next;
 		wq->status = -ENOENT; /* Magic is gone - report failure */
 		kfree(wq->name);
@@ -45,7 +45,6 @@
 		fput(sbi->pipe);	/* Close the pipe */
 		sbi->pipe = NULL;
 	}
-
 	shrink_dcache_sb(sbi->sb);
 }
 
@@ -98,7 +97,10 @@
 
 	pkt.hdr.proto_version = sbi->version;
 	pkt.hdr.type = type;
-	if (type == autofs_ptype_missing) {
+	switch (type) {
+	/* Kernel protocol v4 missing and expire packets */
+	case autofs_ptype_missing:
+	{
 		struct autofs_packet_missing *mp = &pkt.missing;
 
 		pktsz = sizeof(*mp);
@@ -107,7 +109,10 @@
 		mp->len = wq->len;
 		memcpy(mp->name, wq->name, wq->len);
 		mp->name[wq->len] = '\0';
-	} else if (type == autofs_ptype_expire_multi) {
+		break;
+	}
+	case autofs_ptype_expire_multi:
+	{
 		struct autofs_packet_expire_multi *ep = &pkt.expire_multi;
 
 		pktsz = sizeof(*ep);
@@ -116,7 +121,34 @@
 		ep->len = wq->len;
 		memcpy(ep->name, wq->name, wq->len);
 		ep->name[wq->len] = '\0';
-	} else {
+		break;
+	}
+	/*
+	 * Kernel protocol v5 packet for handling indirect and direct
+	 * mount missing and expire requests
+	 */
+	case autofs_ptype_missing_indirect:
+	case autofs_ptype_expire_indirect:
+	case autofs_ptype_missing_direct:
+	case autofs_ptype_expire_direct:
+	{
+		struct autofs_v5_packet *packet = &pkt.v5_packet;
+
+		pktsz = sizeof(*packet);
+
+		packet->wait_queue_token = wq->wait_queue_token;
+		packet->len = wq->len;
+		memcpy(packet->name, wq->name, wq->len);
+		packet->name[wq->len] = '\0';
+		packet->dev = wq->dev;
+		packet->ino = wq->ino;
+		packet->uid = wq->uid;
+		packet->gid = wq->gid;
+		packet->pid = wq->pid;
+		packet->tgid = wq->tgid;
+		break;
+	}
+	default:
 		printk("autofs4_notify_daemon: bad type %d!\n", type);
 		return;
 	}
@@ -162,21 +194,29 @@
 {
 	struct autofs_wait_queue *wq;
 	char *name;
-	int len, status;
+	unsigned int len = 0;
+	unsigned int hash = 0;
+	int status;
 
 	/* In catatonic mode, we don't wait for nobody */
-	if ( sbi->catatonic )
+	if (sbi->catatonic)
 		return -ENOENT;
 	
 	name = kmalloc(NAME_MAX + 1, GFP_KERNEL);
 	if (!name)
 		return -ENOMEM;
 
-	len = autofs4_getpath(sbi, dentry, &name);
-	if (!len) {
-		kfree(name);
-		return -ENOENT;
+	/* If this is a direct mount request create a dummy name */
+	if (IS_ROOT(dentry) && (sbi->type & AUTOFS_TYPE_DIRECT))
+		len = sprintf(name, "%p", dentry);
+	else {
+		len = autofs4_getpath(sbi, dentry, &name);
+		if (!len) {
+			kfree(name);
+			return -ENOENT;
+		}
 	}
+	hash = full_name_hash(name, len);
 
 	if (mutex_lock_interruptible(&sbi->wq_mutex)) {
 		kfree(name);
@@ -190,7 +230,7 @@
 			break;
 	}
 
-	if ( !wq ) {
+	if (!wq) {
 		/* Can't wait for an expire if there's no mount */
 		if (notify == NFY_NONE && !d_mountpoint(dentry)) {
 			kfree(name);
@@ -200,7 +240,7 @@
 
 		/* Create a new wait queue */
 		wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL);
-		if ( !wq ) {
+		if (!wq) {
 			kfree(name);
 			mutex_unlock(&sbi->wq_mutex);
 			return -ENOMEM;
@@ -212,12 +252,18 @@
 		wq->next = sbi->queues;
 		sbi->queues = wq;
 		init_waitqueue_head(&wq->queue);
-		wq->hash = dentry->d_name.hash;
+		wq->hash = hash;
 		wq->name = name;
 		wq->len = len;
+		wq->dev = autofs4_get_dev(sbi);
+		wq->ino = autofs4_get_ino(sbi);
+		wq->uid = current->uid;
+		wq->gid = current->gid;
+		wq->pid = current->pid;
+		wq->tgid = current->tgid;
 		wq->status = -EINTR; /* Status return if interrupted */
 		atomic_set(&wq->wait_ctr, 2);
-		atomic_set(&wq->notified, 1);
+		atomic_set(&wq->notify, 1);
 		mutex_unlock(&sbi->wq_mutex);
 	} else {
 		atomic_inc(&wq->wait_ctr);
@@ -227,9 +273,26 @@
 			(unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
 	}
 
-	if (notify != NFY_NONE && atomic_dec_and_test(&wq->notified)) {
-		int type = (notify == NFY_MOUNT ?
-			autofs_ptype_missing : autofs_ptype_expire_multi);
+	if (notify != NFY_NONE && atomic_read(&wq->notify)) {
+		int type;
+
+		atomic_dec(&wq->notify);
+
+		if (sbi->version < 5) {
+			if (notify == NFY_MOUNT)
+				type = autofs_ptype_missing;
+			else
+				type = autofs_ptype_expire_multi;
+		} else {
+			if (notify == NFY_MOUNT)
+				type = (sbi->type & AUTOFS_TYPE_DIRECT) ?
+					autofs_ptype_missing_direct :
+					 autofs_ptype_missing_indirect;
+			else
+				type = (sbi->type & AUTOFS_TYPE_DIRECT) ?
+					autofs_ptype_expire_direct :
+					autofs_ptype_expire_indirect;
+		}
 
 		DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
 			(unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
@@ -240,14 +303,14 @@
 
 	/* wq->name is NULL if and only if the lock is already released */
 
-	if ( sbi->catatonic ) {
+	if (sbi->catatonic) {
 		/* We might have slept, so check again for catatonic mode */
 		wq->status = -ENOENT;
 		kfree(wq->name);
 		wq->name = NULL;
 	}
 
-	if ( wq->name ) {
+	if (wq->name) {
 		/* Block all but "shutdown" signals while waiting */
 		sigset_t oldset;
 		unsigned long irqflags;
@@ -283,12 +346,12 @@
 	struct autofs_wait_queue *wq, **wql;
 
 	mutex_lock(&sbi->wq_mutex);
-	for ( wql = &sbi->queues ; (wq = *wql) != 0 ; wql = &wq->next ) {
-		if ( wq->wait_queue_token == wait_queue_token )
+	for (wql = &sbi->queues ; (wq = *wql) != 0 ; wql = &wq->next) {
+		if (wq->wait_queue_token == wait_queue_token)
 			break;
 	}
 
-	if ( !wq ) {
+	if (!wq) {
 		mutex_unlock(&sbi->wq_mutex);
 		return -EINVAL;
 	}
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index e172180..80599ae 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -22,7 +22,7 @@
 
 #define EIO_ERROR ((void *) (return_EIO))
 
-static struct file_operations bad_file_ops =
+static const struct file_operations bad_file_ops =
 {
 	.llseek		= EIO_ERROR,
 	.aio_read	= EIO_ERROR,
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 044a595..68ebd10 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -64,7 +64,7 @@
 /* slab cache for befs_inode_info objects */
 static kmem_cache_t *befs_inode_cachep;
 
-static struct file_operations befs_dir_operations = {
+static const struct file_operations befs_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= befs_readdir,
 };
diff --git a/fs/bfs/bfs.h b/fs/bfs/bfs.h
index 1fbc53f..9d79100 100644
--- a/fs/bfs/bfs.h
+++ b/fs/bfs/bfs.h
@@ -49,11 +49,11 @@
 
 /* file.c */
 extern struct inode_operations bfs_file_inops;
-extern struct file_operations bfs_file_operations;
+extern const struct file_operations bfs_file_operations;
 extern struct address_space_operations bfs_aops;
 
 /* dir.c */
 extern struct inode_operations bfs_dir_inops;
-extern struct file_operations bfs_dir_operations;
+extern const struct file_operations bfs_dir_operations;
 
 #endif /* _FS_BFS_BFS_H */
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 5af928f..26fad96 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -70,7 +70,7 @@
 	return 0;	
 }
 
-struct file_operations bfs_dir_operations = {
+const struct file_operations bfs_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= bfs_readdir,
 	.fsync		= file_fsync,
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index 807723b..d83cd74 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -17,7 +17,7 @@
 #define dprintf(x...)
 #endif
 
-struct file_operations bfs_file_operations = {
+const struct file_operations bfs_file_operations = {
 	.llseek 	= generic_file_llseek,
 	.read		= generic_file_read,
 	.write		= generic_file_write,
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 6a7b730..d73d755 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -600,7 +600,7 @@
 	return count;
 }
 
-static struct file_operations bm_entry_operations = {
+static const struct file_operations bm_entry_operations = {
 	.read		= bm_entry_read,
 	.write		= bm_entry_write,
 };
@@ -668,7 +668,7 @@
 	return count;
 }
 
-static struct file_operations bm_register_operations = {
+static const struct file_operations bm_register_operations = {
 	.write		= bm_register_write,
 };
 
@@ -715,7 +715,7 @@
 	return count;
 }
 
-static struct file_operations bm_status_operations = {
+static const struct file_operations bm_status_operations = {
 	.read		= bm_status_read,
 	.write		= bm_status_write,
 };
diff --git a/fs/bio.c b/fs/bio.c
index 73e664c..eb8fbc5 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -30,7 +30,7 @@
 
 #define BIO_POOL_SIZE 256
 
-static kmem_cache_t *bio_slab;
+static kmem_cache_t *bio_slab __read_mostly;
 
 #define BIOVEC_NR_POOLS 6
 
@@ -39,7 +39,7 @@
  * basically we just need to survive
  */
 #define BIO_SPLIT_ENTRIES 8	
-mempool_t *bio_split_pool;
+mempool_t *bio_split_pool __read_mostly;
 
 struct biovec_slab {
 	int nr_vecs;
@@ -1125,16 +1125,6 @@
 	return bp;
 }
 
-static void *bio_pair_alloc(gfp_t gfp_flags, void *data)
-{
-	return kmalloc(sizeof(struct bio_pair), gfp_flags);
-}
-
-static void bio_pair_free(void *bp, void *data)
-{
-	kfree(bp);
-}
-
 
 /*
  * create memory pools for biovec's in a bio_set.
@@ -1151,8 +1141,7 @@
 		if (i >= scale)
 			pool_entries >>= 1;
 
-		*bvp = mempool_create(pool_entries, mempool_alloc_slab,
-					mempool_free_slab, bp->slab);
+		*bvp = mempool_create_slab_pool(pool_entries, bp->slab);
 		if (!*bvp)
 			return -ENOMEM;
 	}
@@ -1189,9 +1178,7 @@
 	if (!bs)
 		return NULL;
 
-	bs->bio_pool = mempool_create(bio_pool_size, mempool_alloc_slab,
-			mempool_free_slab, bio_slab);
-
+	bs->bio_pool = mempool_create_slab_pool(bio_pool_size, bio_slab);
 	if (!bs->bio_pool)
 		goto bad;
 
@@ -1254,8 +1241,8 @@
 	if (!fs_bio_set)
 		panic("bio: can't allocate bios\n");
 
-	bio_split_pool = mempool_create(BIO_SPLIT_ENTRIES,
-				bio_pair_alloc, bio_pair_free, NULL);
+	bio_split_pool = mempool_create_kmalloc_pool(BIO_SPLIT_ENTRIES,
+						     sizeof(struct bio_pair));
 	if (!bio_split_pool)
 		panic("bio: can't create split pool\n");
 
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 573fc8e..af88c43 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -131,9 +131,10 @@
 
 static int
 blkdev_get_blocks(struct inode *inode, sector_t iblock,
-		unsigned long max_blocks, struct buffer_head *bh, int create)
+		struct buffer_head *bh, int create)
 {
 	sector_t end_block = max_block(I_BDEV(inode));
+	unsigned long max_blocks = bh->b_size >> inode->i_blkbits;
 
 	if ((iblock + max_blocks) > end_block) {
 		max_blocks = end_block - iblock;
@@ -234,7 +235,7 @@
  */
 
 static  __cacheline_aligned_in_smp DEFINE_SPINLOCK(bdev_lock);
-static kmem_cache_t * bdev_cachep;
+static kmem_cache_t * bdev_cachep __read_mostly;
 
 static struct inode *bdev_alloc_inode(struct super_block *sb)
 {
@@ -265,6 +266,9 @@
 		mutex_init(&bdev->bd_mount_mutex);
 		INIT_LIST_HEAD(&bdev->bd_inodes);
 		INIT_LIST_HEAD(&bdev->bd_list);
+#ifdef CONFIG_SYSFS
+		INIT_LIST_HEAD(&bdev->bd_holder_list);
+#endif
 		inode_init_once(&ei->vfs_inode);
 	}
 }
@@ -308,7 +312,7 @@
 	.kill_sb	= kill_anon_super,
 };
 
-static struct vfsmount *bd_mnt;
+static struct vfsmount *bd_mnt __read_mostly;
 struct super_block *blockdev_superblock;
 
 void __init bdev_cache_init(void)
@@ -489,6 +493,300 @@
 
 EXPORT_SYMBOL(bd_release);
 
+#ifdef CONFIG_SYSFS
+/*
+ * Functions for bd_claim_by_kobject / bd_release_from_kobject
+ *
+ *     If a kobject is passed to bd_claim_by_kobject()
+ *     and the kobject has a parent directory,
+ *     following symlinks are created:
+ *        o from the kobject to the claimed bdev
+ *        o from "holders" directory of the bdev to the parent of the kobject
+ *     bd_release_from_kobject() removes these symlinks.
+ *
+ *     Example:
+ *        If /dev/dm-0 maps to /dev/sda, kobject corresponding to
+ *        /sys/block/dm-0/slaves is passed to bd_claim_by_kobject(), then:
+ *           /sys/block/dm-0/slaves/sda --> /sys/block/sda
+ *           /sys/block/sda/holders/dm-0 --> /sys/block/dm-0
+ */
+
+static struct kobject *bdev_get_kobj(struct block_device *bdev)
+{
+	if (bdev->bd_contains != bdev)
+		return kobject_get(&bdev->bd_part->kobj);
+	else
+		return kobject_get(&bdev->bd_disk->kobj);
+}
+
+static struct kobject *bdev_get_holder(struct block_device *bdev)
+{
+	if (bdev->bd_contains != bdev)
+		return kobject_get(bdev->bd_part->holder_dir);
+	else
+		return kobject_get(bdev->bd_disk->holder_dir);
+}
+
+static void add_symlink(struct kobject *from, struct kobject *to)
+{
+	if (!from || !to)
+		return;
+	sysfs_create_link(from, to, kobject_name(to));
+}
+
+static void del_symlink(struct kobject *from, struct kobject *to)
+{
+	if (!from || !to)
+		return;
+	sysfs_remove_link(from, kobject_name(to));
+}
+
+/*
+ * 'struct bd_holder' contains pointers to kobjects symlinked by
+ * bd_claim_by_kobject.
+ * It's connected to bd_holder_list which is protected by bdev->bd_sem.
+ */
+struct bd_holder {
+	struct list_head list;	/* chain of holders of the bdev */
+	int count;		/* references from the holder */
+	struct kobject *sdir;	/* holder object, e.g. "/block/dm-0/slaves" */
+	struct kobject *hdev;	/* e.g. "/block/dm-0" */
+	struct kobject *hdir;	/* e.g. "/block/sda/holders" */
+	struct kobject *sdev;	/* e.g. "/block/sda" */
+};
+
+/*
+ * Get references of related kobjects at once.
+ * Returns 1 on success. 0 on failure.
+ *
+ * Should call bd_holder_release_dirs() after successful use.
+ */
+static int bd_holder_grab_dirs(struct block_device *bdev,
+			struct bd_holder *bo)
+{
+	if (!bdev || !bo)
+		return 0;
+
+	bo->sdir = kobject_get(bo->sdir);
+	if (!bo->sdir)
+		return 0;
+
+	bo->hdev = kobject_get(bo->sdir->parent);
+	if (!bo->hdev)
+		goto fail_put_sdir;
+
+	bo->sdev = bdev_get_kobj(bdev);
+	if (!bo->sdev)
+		goto fail_put_hdev;
+
+	bo->hdir = bdev_get_holder(bdev);
+	if (!bo->hdir)
+		goto fail_put_sdev;
+
+	return 1;
+
+fail_put_sdev:
+	kobject_put(bo->sdev);
+fail_put_hdev:
+	kobject_put(bo->hdev);
+fail_put_sdir:
+	kobject_put(bo->sdir);
+
+	return 0;
+}
+
+/* Put references of related kobjects at once. */
+static void bd_holder_release_dirs(struct bd_holder *bo)
+{
+	kobject_put(bo->hdir);
+	kobject_put(bo->sdev);
+	kobject_put(bo->hdev);
+	kobject_put(bo->sdir);
+}
+
+static struct bd_holder *alloc_bd_holder(struct kobject *kobj)
+{
+	struct bd_holder *bo;
+
+	bo = kzalloc(sizeof(*bo), GFP_KERNEL);
+	if (!bo)
+		return NULL;
+
+	bo->count = 1;
+	bo->sdir = kobj;
+
+	return bo;
+}
+
+static void free_bd_holder(struct bd_holder *bo)
+{
+	kfree(bo);
+}
+
+/**
+ * add_bd_holder - create sysfs symlinks for bd_claim() relationship
+ *
+ * @bdev:	block device to be bd_claimed
+ * @bo:		preallocated and initialized by alloc_bd_holder()
+ *
+ * If there is no matching entry with @bo in @bdev->bd_holder_list,
+ * add @bo to the list, create symlinks.
+ *
+ * Returns 1 if @bo was added to the list.
+ * Returns 0 if @bo wasn't used by any reason and should be freed.
+ */
+static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo)
+{
+	struct bd_holder *tmp;
+
+	if (!bo)
+		return 0;
+
+	list_for_each_entry(tmp, &bdev->bd_holder_list, list) {
+		if (tmp->sdir == bo->sdir) {
+			tmp->count++;
+			return 0;
+		}
+	}
+
+	if (!bd_holder_grab_dirs(bdev, bo))
+		return 0;
+
+	add_symlink(bo->sdir, bo->sdev);
+	add_symlink(bo->hdir, bo->hdev);
+	list_add_tail(&bo->list, &bdev->bd_holder_list);
+	return 1;
+}
+
+/**
+ * del_bd_holder - delete sysfs symlinks for bd_claim() relationship
+ *
+ * @bdev:	block device to be bd_claimed
+ * @kobj:	holder's kobject
+ *
+ * If there is matching entry with @kobj in @bdev->bd_holder_list
+ * and no other bd_claim() from the same kobject,
+ * remove the struct bd_holder from the list, delete symlinks for it.
+ *
+ * Returns a pointer to the struct bd_holder when it's removed from the list
+ * and ready to be freed.
+ * Returns NULL if matching claim isn't found or there is other bd_claim()
+ * by the same kobject.
+ */
+static struct bd_holder *del_bd_holder(struct block_device *bdev,
+					struct kobject *kobj)
+{
+	struct bd_holder *bo;
+
+	list_for_each_entry(bo, &bdev->bd_holder_list, list) {
+		if (bo->sdir == kobj) {
+			bo->count--;
+			BUG_ON(bo->count < 0);
+			if (!bo->count) {
+				list_del(&bo->list);
+				del_symlink(bo->sdir, bo->sdev);
+				del_symlink(bo->hdir, bo->hdev);
+				bd_holder_release_dirs(bo);
+				return bo;
+			}
+			break;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * bd_claim_by_kobject - bd_claim() with additional kobject signature
+ *
+ * @bdev:	block device to be claimed
+ * @holder:	holder's signature
+ * @kobj:	holder's kobject
+ *
+ * Do bd_claim() and if it succeeds, create sysfs symlinks between
+ * the bdev and the holder's kobject.
+ * Use bd_release_from_kobject() when relesing the claimed bdev.
+ *
+ * Returns 0 on success. (same as bd_claim())
+ * Returns errno on failure.
+ */
+static int bd_claim_by_kobject(struct block_device *bdev, void *holder,
+				struct kobject *kobj)
+{
+	int res;
+	struct bd_holder *bo;
+
+	if (!kobj)
+		return -EINVAL;
+
+	bo = alloc_bd_holder(kobj);
+	if (!bo)
+		return -ENOMEM;
+
+	mutex_lock(&bdev->bd_mutex);
+	res = bd_claim(bdev, holder);
+	if (res || !add_bd_holder(bdev, bo))
+		free_bd_holder(bo);
+	mutex_unlock(&bdev->bd_mutex);
+
+	return res;
+}
+
+/**
+ * bd_release_from_kobject - bd_release() with additional kobject signature
+ *
+ * @bdev:	block device to be released
+ * @kobj:	holder's kobject
+ *
+ * Do bd_release() and remove sysfs symlinks created by bd_claim_by_kobject().
+ */
+static void bd_release_from_kobject(struct block_device *bdev,
+					struct kobject *kobj)
+{
+	struct bd_holder *bo;
+
+	if (!kobj)
+		return;
+
+	mutex_lock(&bdev->bd_mutex);
+	bd_release(bdev);
+	if ((bo = del_bd_holder(bdev, kobj)))
+		free_bd_holder(bo);
+	mutex_unlock(&bdev->bd_mutex);
+}
+
+/**
+ * bd_claim_by_disk - wrapper function for bd_claim_by_kobject()
+ *
+ * @bdev:	block device to be claimed
+ * @holder:	holder's signature
+ * @disk:	holder's gendisk
+ *
+ * Call bd_claim_by_kobject() with getting @disk->slave_dir.
+ */
+int bd_claim_by_disk(struct block_device *bdev, void *holder,
+			struct gendisk *disk)
+{
+	return bd_claim_by_kobject(bdev, holder, kobject_get(disk->slave_dir));
+}
+EXPORT_SYMBOL_GPL(bd_claim_by_disk);
+
+/**
+ * bd_release_from_disk - wrapper function for bd_release_from_kobject()
+ *
+ * @bdev:	block device to be claimed
+ * @disk:	holder's gendisk
+ *
+ * Call bd_release_from_kobject() and put @disk->slave_dir.
+ */
+void bd_release_from_disk(struct block_device *bdev, struct gendisk *disk)
+{
+	bd_release_from_kobject(bdev, disk->slave_dir);
+	kobject_put(disk->slave_dir);
+}
+EXPORT_SYMBOL_GPL(bd_release_from_disk);
+#endif
+
 /*
  * Tries to open block device by device number.  Use it ONLY if you
  * really do not have anything better - i.e. when you are behind a
@@ -789,7 +1087,7 @@
 	.direct_IO	= blkdev_direct_IO,
 };
 
-struct file_operations def_blk_fops = {
+const struct file_operations def_blk_fops = {
 	.open		= blkdev_open,
 	.release	= blkdev_close,
 	.llseek		= block_llseek,
diff --git a/fs/buffer.c b/fs/buffer.c
index 3b3ab52..23f1f3a 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -426,8 +426,10 @@
 	if (all_mapped) {
 		printk("__find_get_block_slow() failed. "
 			"block=%llu, b_blocknr=%llu\n",
-			(unsigned long long)block, (unsigned long long)bh->b_blocknr);
-		printk("b_state=0x%08lx, b_size=%u\n", bh->b_state, bh->b_size);
+			(unsigned long long)block,
+			(unsigned long long)bh->b_blocknr);
+		printk("b_state=0x%08lx, b_size=%zu\n",
+			bh->b_state, bh->b_size);
 		printk("device blocksize: %d\n", 1 << bd_inode->i_blkbits);
 	}
 out_unlock:
@@ -491,7 +493,7 @@
 	wakeup_pdflush(1024);
 	yield();
 
-	for_each_pgdat(pgdat) {
+	for_each_online_pgdat(pgdat) {
 		zones = pgdat->node_zonelists[gfp_zone(GFP_NOFS)].zones;
 		if (*zones)
 			try_to_free_pages(zones, GFP_NOFS);
@@ -796,8 +798,7 @@
 	if (!mapping->assoc_mapping) {
 		mapping->assoc_mapping = buffer_mapping;
 	} else {
-		if (mapping->assoc_mapping != buffer_mapping)
-			BUG();
+		BUG_ON(mapping->assoc_mapping != buffer_mapping);
 	}
 	if (list_empty(&bh->b_assoc_buffers)) {
 		spin_lock(&buffer_mapping->private_lock);
@@ -1114,8 +1115,7 @@
 	if (!page)
 		return NULL;
 
-	if (!PageLocked(page))
-		BUG();
+	BUG_ON(!PageLocked(page));
 
 	if (page_has_buffers(page)) {
 		bh = page_buffers(page);
@@ -1522,8 +1522,7 @@
 		struct page *page, unsigned long offset)
 {
 	bh->b_page = page;
-	if (offset >= PAGE_SIZE)
-		BUG();
+	BUG_ON(offset >= PAGE_SIZE);
 	if (PageHighMem(page))
 		/*
 		 * This catches illegal uses and preserves the offset:
@@ -1593,11 +1592,10 @@
  * point.  Because the caller is about to free (and possibly reuse) those
  * blocks on-disk.
  */
-int block_invalidatepage(struct page *page, unsigned long offset)
+void block_invalidatepage(struct page *page, unsigned long offset)
 {
 	struct buffer_head *head, *bh, *next;
 	unsigned int curr_off = 0;
-	int ret = 1;
 
 	BUG_ON(!PageLocked(page));
 	if (!page_has_buffers(page))
@@ -1624,19 +1622,18 @@
 	 * so real IO is not possible anymore.
 	 */
 	if (offset == 0)
-		ret = try_to_release_page(page, 0);
+		try_to_release_page(page, 0);
 out:
-	return ret;
+	return;
 }
 EXPORT_SYMBOL(block_invalidatepage);
 
-int do_invalidatepage(struct page *page, unsigned long offset)
+void do_invalidatepage(struct page *page, unsigned long offset)
 {
-	int (*invalidatepage)(struct page *, unsigned long);
-	invalidatepage = page->mapping->a_ops->invalidatepage;
-	if (invalidatepage == NULL)
-		invalidatepage = block_invalidatepage;
-	return (*invalidatepage)(page, offset);
+	void (*invalidatepage)(struct page *, unsigned long);
+	invalidatepage = page->mapping->a_ops->invalidatepage ? :
+		block_invalidatepage;
+	(*invalidatepage)(page, offset);
 }
 
 /*
@@ -1738,6 +1735,7 @@
 	sector_t block;
 	sector_t last_block;
 	struct buffer_head *bh, *head;
+	const unsigned blocksize = 1 << inode->i_blkbits;
 	int nr_underway = 0;
 
 	BUG_ON(!PageLocked(page));
@@ -1745,7 +1743,7 @@
 	last_block = (i_size_read(inode) - 1) >> inode->i_blkbits;
 
 	if (!page_has_buffers(page)) {
-		create_empty_buffers(page, 1 << inode->i_blkbits,
+		create_empty_buffers(page, blocksize,
 					(1 << BH_Dirty)|(1 << BH_Uptodate));
 	}
 
@@ -1780,6 +1778,7 @@
 			clear_buffer_dirty(bh);
 			set_buffer_uptodate(bh);
 		} else if (!buffer_mapped(bh) && buffer_dirty(bh)) {
+			WARN_ON(bh->b_size != blocksize);
 			err = get_block(inode, block, bh, 1);
 			if (err)
 				goto recover;
@@ -1933,6 +1932,7 @@
 		if (buffer_new(bh))
 			clear_buffer_new(bh);
 		if (!buffer_mapped(bh)) {
+			WARN_ON(bh->b_size != blocksize);
 			err = get_block(inode, block, bh, 1);
 			if (err)
 				break;
@@ -2088,6 +2088,7 @@
 
 			fully_mapped = 0;
 			if (iblock < lblock) {
+				WARN_ON(bh->b_size != blocksize);
 				err = get_block(inode, iblock, bh, 0);
 				if (err)
 					SetPageError(page);
@@ -2409,6 +2410,7 @@
 		create = 1;
 		if (block_start >= to)
 			create = 0;
+		map_bh.b_size = blocksize;
 		ret = get_block(inode, block_in_file + block_in_page,
 					&map_bh, create);
 		if (ret)
@@ -2669,6 +2671,7 @@
 
 	err = 0;
 	if (!buffer_mapped(bh)) {
+		WARN_ON(bh->b_size != blocksize);
 		err = get_block(inode, iblock, bh, 0);
 		if (err)
 			goto unlock;
@@ -2755,6 +2758,7 @@
 	struct inode *inode = mapping->host;
 	tmp.b_state = 0;
 	tmp.b_blocknr = 0;
+	tmp.b_size = 1 << inode->i_blkbits;
 	get_block(inode, block, &tmp, 0);
 	return tmp.b_blocknr;
 }
@@ -3007,7 +3011,7 @@
 }
 EXPORT_SYMBOL(try_to_free_buffers);
 
-int block_sync_page(struct page *page)
+void block_sync_page(struct page *page)
 {
 	struct address_space *mapping;
 
@@ -3015,7 +3019,6 @@
 	mapping = page_mapping(page);
 	if (mapping)
 		blk_run_backing_dev(mapping->backing_dev_info, page);
-	return 0;
 }
 
 /*
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 8c6eb04..f3418f7 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/seq_file.h>
 
 #include <linux/kobject.h>
 #include <linux/kobj_map.h>
@@ -27,8 +28,6 @@
 
 static struct kobj_map *cdev_map;
 
-#define MAX_PROBE_HASH 255	/* random */
-
 static DEFINE_MUTEX(chrdevs_lock);
 
 static struct char_device_struct {
@@ -39,93 +38,29 @@
 	char name[64];
 	struct file_operations *fops;
 	struct cdev *cdev;		/* will die */
-} *chrdevs[MAX_PROBE_HASH];
+} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
 
 /* index in the above */
 static inline int major_to_index(int major)
 {
-	return major % MAX_PROBE_HASH;
+	return major % CHRDEV_MAJOR_HASH_SIZE;
 }
 
-struct chrdev_info {
-	int index;
-	struct char_device_struct *cd;
-};
+#ifdef CONFIG_PROC_FS
 
-void *get_next_chrdev(void *dev)
-{
-	struct chrdev_info *info;
-
-	if (dev == NULL) {
-		info = kmalloc(sizeof(*info), GFP_KERNEL);
-		if (!info)
-			goto out;
-		info->index=0;
-		info->cd = chrdevs[info->index];
-		if (info->cd)
-			goto out;
-	} else {
-		info = dev;
-	}
-
-	while (info->index < ARRAY_SIZE(chrdevs)) {
-		if (info->cd)
-			info->cd = info->cd->next;
-		if (info->cd)
-			goto out;
-		/*
-		 * No devices on this chain, move to the next
-		 */
-		info->index++;
-		info->cd = (info->index < ARRAY_SIZE(chrdevs)) ?
-			chrdevs[info->index] : NULL;
-		if (info->cd)
-			goto out;
-	}
-
-out:
-	return info;
-}
-
-void *acquire_chrdev_list(void)
-{
-	mutex_lock(&chrdevs_lock);
-	return get_next_chrdev(NULL);
-}
-
-void release_chrdev_list(void *dev)
-{
-	mutex_unlock(&chrdevs_lock);
-	kfree(dev);
-}
-
-
-int count_chrdev_list(void)
+void chrdev_show(struct seq_file *f, off_t offset)
 {
 	struct char_device_struct *cd;
-	int i, count;
 
-	count = 0;
-
-	for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
-		for (cd = chrdevs[i]; cd; cd = cd->next)
-			count++;
+	if (offset < CHRDEV_MAJOR_HASH_SIZE) {
+		mutex_lock(&chrdevs_lock);
+		for (cd = chrdevs[offset]; cd; cd = cd->next)
+			seq_printf(f, "%3d %s\n", cd->major, cd->name);
+		mutex_unlock(&chrdevs_lock);
 	}
-
-	return count;
 }
 
-int get_chrdev_info(void *dev, int *major, char **name)
-{
-	struct chrdev_info *info = dev;
-
-	if (info->cd == NULL)
-		return 1;
-
-	*major = info->cd->major;
-	*name = info->cd->name;
-	return 0;
-}
+#endif /* CONFIG_PROC_FS */
 
 /*
  * Register a single major with a specified minor range.
@@ -250,7 +185,7 @@
 }
 
 int register_chrdev(unsigned int major, const char *name,
-		    struct file_operations *fops)
+		    const struct file_operations *fops)
 {
 	struct char_device_struct *cd;
 	struct cdev *cdev;
@@ -406,7 +341,7 @@
  * is contain the open that then fills in the correct operations
  * depending on the special file...
  */
-struct file_operations def_chr_fops = {
+const struct file_operations def_chr_fops = {
 	.open = chrdev_open,
 };
 
@@ -473,7 +408,7 @@
 	return p;
 }
 
-void cdev_init(struct cdev *cdev, struct file_operations *fops)
+void cdev_init(struct cdev *cdev, const struct file_operations *fops)
 {
 	memset(cdev, 0, sizeof *cdev);
 	INIT_LIST_HEAD(&cdev->list);
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index cb68efb..8a2de03 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,21 @@
+Version 1.42
+------------
+Fix slow oplock break when mounted to different servers at the same time and
+the tids match and we try to find matching fid on wrong server.
+
+Version 1.41
+------------
+Fix NTLMv2 security (can be enabled in /proc/fs/cifs) so customers can
+configure stronger authentication.  Fix sfu symlinks so they can
+be followed (not just recognized).  Fix wraparound of bcc on
+read responses when buffer size over 64K and also fix wrap of
+max smb buffer size when CIFSMaxBufSize over 64K.  Fix oops in
+cifs_user_read and cifs_readpages (when EAGAIN on send of smb
+on socket is returned over and over).  Add POSIX (advisory) byte range
+locking support (requires server with newest CIFS UNIX Extensions
+to the protocol implemented). Slow down negprot slightly in port 139
+RFC1001 case to give session_init time on buggy servers.
+
 Version 1.40
 ------------
 Use fsuid (fsgid) more consistently instead of uid (gid). Improve performance
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index 7384947..58c7725 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -3,4 +3,4 @@
 #
 obj-$(CONFIG_CIFS) += cifs.o
 
-cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o
+cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o ntlmssp.o
diff --git a/fs/cifs/README b/fs/cifs/README
index b0070d1..b2b4d08 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -422,6 +422,13 @@
  nomapchars     Do not translate any of these seven characters (default).
  nocase         Request case insensitive path name matching (case
 		sensitive is the default if the server suports it).
+ posixpaths     If CIFS Unix extensions are supported, attempt to
+		negotiate posix path name support which allows certain
+		characters forbidden in typical CIFS filenames, without
+		requiring remapping. (default)
+ noposixpaths   If CIFS Unix extensions are supported, do not request
+		posix path name support (this may cause servers to
+		reject creatingfile with certain reserved characters).
  nobrl          Do not send byte range lock requests to the server.
 		This is necessary for certain applications that break
 		with cifs style mandatory byte range locks (and most
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index a2c2485..e7d6373 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsencrypt.c
  *
- *   Copyright (C) International Business Machines  Corp., 2005
+ *   Copyright (C) International Business Machines  Corp., 2005,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -36,7 +36,8 @@
 extern void mdfour(unsigned char *out, unsigned char *in, int n);
 extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
 	
-static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature)
+static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, 
+				    const char * key, char * signature)
 {
 	struct	MD5Context context;
 
@@ -56,9 +57,6 @@
 	int rc = 0;
 	char smb_signature[20];
 
-	/* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */
-	/* BB remember to add code to save expected sequence number in midQ entry BB */
-
 	if((cifs_pdu == NULL) || (server == NULL))
 		return -EINVAL;
 
@@ -85,20 +83,33 @@
 static int cifs_calc_signature2(const struct kvec * iov, int n_vec,
 				const char * key, char * signature)
 {
-        struct  MD5Context context;
+	struct  MD5Context context;
+	int i;
 
-        if((iov == NULL) || (signature == NULL))
-                return -EINVAL;
+	if((iov == NULL) || (signature == NULL))
+		return -EINVAL;
 
-        MD5Init(&context);
-        MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
+	MD5Init(&context);
+	MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
+	for(i=0;i<n_vec;i++) {
+		if(iov[i].iov_base == NULL) {
+			cERROR(1,("null iovec entry"));
+			return -EIO;
+		} else if(iov[i].iov_len == 0)
+			break; /* bail out if we are sent nothing to sign */
+		/* The first entry includes a length field (which does not get 
+		   signed that occupies the first 4 bytes before the header */
+		if(i==0) {
+			if (iov[0].iov_len <= 8 ) /* cmd field at offset 9 */
+				break; /* nothing to sign or corrupt header */
+			MD5Update(&context,iov[0].iov_base+4, iov[0].iov_len-4);
+		} else
+			MD5Update(&context,iov[i].iov_base, iov[i].iov_len);
+	}
 
-/*        MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); */ /* BB FIXME BB */
+	MD5Final(signature,&context);
 
-        MD5Final(signature,&context);
-
-	return -EOPNOTSUPP;
-/*        return 0; */
+	return 0;
 }
 
 
@@ -259,4 +270,5 @@
 /*	hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
 
 	hmac_md5_final(v2_session_response,&context);
+	cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); /* BB removeme BB */
 }
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 221b333..d4b713e 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -93,13 +93,10 @@
 	int rc = 0;
 
 	sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */
-	sb->s_fs_info = kmalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
+	sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
 	cifs_sb = CIFS_SB(sb);
 	if(cifs_sb == NULL)
 		return -ENOMEM;
-	else
-		memset(cifs_sb,0,sizeof(struct cifs_sb_info));
-	
 
 	rc = cifs_mount(sb, cifs_sb, data, devname);
 
@@ -583,7 +580,7 @@
 #endif 
 };
 
-struct file_operations cifs_file_ops = {
+const struct file_operations cifs_file_ops = {
 	.read = do_sync_read,
 	.write = do_sync_write,
 	.readv = generic_file_readv,
@@ -607,7 +604,7 @@
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
 };
 
-struct file_operations cifs_file_direct_ops = {
+const struct file_operations cifs_file_direct_ops = {
 	/* no mmap, no aio, no readv - 
 	   BB reevaluate whether they can be done with directio, no cache */
 	.read = cifs_user_read,
@@ -626,7 +623,7 @@
 	.dir_notify = cifs_dir_notify,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
 };
-struct file_operations cifs_file_nobrl_ops = {
+const struct file_operations cifs_file_nobrl_ops = {
 	.read = do_sync_read,
 	.write = do_sync_write,
 	.readv = generic_file_readv,
@@ -649,7 +646,7 @@
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
 };
 
-struct file_operations cifs_file_direct_nobrl_ops = {
+const struct file_operations cifs_file_direct_nobrl_ops = {
 	/* no mmap, no aio, no readv - 
 	   BB reevaluate whether they can be done with directio, no cache */
 	.read = cifs_user_read,
@@ -668,7 +665,7 @@
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
 };
 
-struct file_operations cifs_dir_ops = {
+const struct file_operations cifs_dir_ops = {
 	.readdir = cifs_readdir,
 	.release = cifs_closedir,
 	.read    = generic_read_dir,
@@ -738,10 +735,8 @@
 		cERROR(1,("cifs_min_rcv set to maximum (64)"));
 	}
 
-	cifs_req_poolp = mempool_create(cifs_min_rcv,
-					mempool_alloc_slab,
-					mempool_free_slab,
-					cifs_req_cachep);
+	cifs_req_poolp = mempool_create_slab_pool(cifs_min_rcv,
+						  cifs_req_cachep);
 
 	if(cifs_req_poolp == NULL) {
 		kmem_cache_destroy(cifs_req_cachep);
@@ -771,10 +766,8 @@
 		cFYI(1,("cifs_min_small set to maximum (256)"));
 	}
 
-	cifs_sm_req_poolp = mempool_create(cifs_min_small,
-				mempool_alloc_slab,
-				mempool_free_slab,
-				cifs_sm_req_cachep);
+	cifs_sm_req_poolp = mempool_create_slab_pool(cifs_min_small,
+						     cifs_sm_req_cachep);
 
 	if(cifs_sm_req_poolp == NULL) {
 		mempool_destroy(cifs_req_poolp);
@@ -808,10 +801,8 @@
 	if (cifs_mid_cachep == NULL)
 		return -ENOMEM;
 
-	cifs_mid_poolp = mempool_create(3 /* a reasonable min simultan opers */,
-					mempool_alloc_slab,
-					mempool_free_slab,
-					cifs_mid_cachep);
+	/* 3 is a reasonable minimum number of simultaneous operations */
+	cifs_mid_poolp = mempool_create_slab_pool(3, cifs_mid_cachep);
 	if(cifs_mid_poolp == NULL) {
 		kmem_cache_destroy(cifs_mid_cachep);
 		return -ENOMEM;
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 821a8eb..4e829dc 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -61,10 +61,10 @@
 extern struct inode_operations cifs_symlink_inode_ops;
 
 /* Functions related to files and directories */
-extern struct file_operations cifs_file_ops;
-extern struct file_operations cifs_file_direct_ops; /* if directio mount */
-extern struct file_operations cifs_file_nobrl_ops;
-extern struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */
+extern const struct file_operations cifs_file_ops;
+extern const struct file_operations cifs_file_direct_ops; /* if directio mount */
+extern const struct file_operations cifs_file_nobrl_ops;
+extern const struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */
 extern int cifs_open(struct inode *inode, struct file *file);
 extern int cifs_close(struct inode *inode, struct file *file);
 extern int cifs_closedir(struct inode *inode, struct file *file);
@@ -76,7 +76,7 @@
 extern int cifs_fsync(struct file *, struct dentry *, int);
 extern int cifs_flush(struct file *);
 extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
-extern struct file_operations cifs_dir_ops;
+extern const struct file_operations cifs_dir_ops;
 extern int cifs_dir_open(struct inode *inode, struct file *file);
 extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
 extern int cifs_dir_notify(struct file *, unsigned long arg);
@@ -99,5 +99,5 @@
 extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
 extern int cifs_ioctl (struct inode * inode, struct file * filep,
 		       unsigned int command, unsigned long arg);
-#define CIFS_VERSION   "1.40"
+#define CIFS_VERSION   "1.42"
 #endif				/* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 7bed276..006eb33 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsglob.h
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   Copyright (C) International Business Machines  Corp., 2002,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -430,6 +430,15 @@
 #define   CIFS_LARGE_BUFFER     2
 #define   CIFS_IOVEC            4    /* array of response buffers */
 
+/* Type of session setup needed */
+#define   CIFS_PLAINTEXT	0
+#define   CIFS_LANMAN		1
+#define   CIFS_NTLM		2
+#define   CIFS_NTLMSSP_NEG	3
+#define   CIFS_NTLMSSP_AUTH	4
+#define   CIFS_SPNEGO_INIT	5
+#define   CIFS_SPNEGO_TARG	6
+
 /*
  *****************************************************************
  * All constants go here
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index cc24710..b2233ac 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -859,7 +859,10 @@
 	LOCKING_ANDX_RANGE Locks[1];
 } __attribute__((packed)) LOCK_REQ;
 
-
+/* lock type */
+#define CIFS_RDLCK	0
+#define CIFS_WRLCK	1
+#define CIFS_UNLCK      2
 typedef struct cifs_posix_lock {
 	__le16  lock_type;  /* 0 = Read, 1 = Write, 2 = Unlock */
 	__le16  lock_flags; /* 1 = Wait (only valid for setlock) */
@@ -1786,7 +1789,13 @@
 #define CIFS_UNIX_POSIX_ACL_CAP         0x00000002 /* support getfacl/setfacl */
 #define CIFS_UNIX_XATTR_CAP             0x00000004 /* support new namespace   */
 #define CIFS_UNIX_EXTATTR_CAP           0x00000008 /* support chattr/chflag   */
-#define CIFS_UNIX_POSIX_PATHNAMES_CAP   0x00000010 /* Use POSIX pathnames on the wire. */
+#define CIFS_UNIX_POSIX_PATHNAMES_CAP   0x00000010 /* Allow POSIX path chars  */
+#ifdef CONFIG_CIFS_POSIX
+#define CIFS_UNIX_CAP_MASK              0x0000001b
+#else 
+#define CIFS_UNIX_CAP_MASK              0x00000013
+#endif /* CONFIG_CIFS_POSIX */
+
 
 #define CIFS_POSIX_EXTENSIONS           0x00000010 /* support for new QFSInfo */
 
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 7b25463..2879ba3 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsproto.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002,2005
+ *   Copyright (c) International Business Machines  Corp., 2002,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -64,6 +64,14 @@
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
 			    const struct cifsTconInfo *, int /* length of
 			    fixed section (word count) in two byte units */);
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
+				struct cifsSesInfo *ses,
+				void ** request_buf);
+extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
+			     const int stage, int * pNTLMv2_flg,
+			     const struct nls_table *nls_cp);
+#endif
 extern __u16 GetNextMid(struct TCP_Server_Info *server);
 extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, 
 						 struct cifsTconInfo *);
@@ -257,7 +265,10 @@
 			const __u64 offset, const __u32 numUnlock,
 			const __u32 numLock, const __u8 lockType,
 			const int waitFlag);
-
+extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
+			const __u16 smb_file_id, const int get_flag,
+			const __u64 len, const __u64 offset, 
+			const __u16 lock_type, const int waitFlag);
 extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
 extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
 
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index a243fe2..d705500 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifssmb.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   Copyright (C) International Business Machines  Corp., 2002,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   Contains the routines for constructing the SMB PDUs themselves
@@ -186,7 +186,35 @@
                 cifs_stats_inc(&tcon->num_smbs_sent);
 
 	return rc;
-}  
+}
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL  
+int
+small_smb_init_no_tc(const int smb_command, const int wct, 
+		     struct cifsSesInfo *ses, void **request_buf)
+{
+	int rc;
+	struct smb_hdr * buffer;
+
+	rc = small_smb_init(smb_command, wct, NULL, request_buf);
+	if(rc)
+		return rc;
+
+	buffer = (struct smb_hdr *)*request_buf;
+	buffer->Mid = GetNextMid(ses->server);
+	if (ses->capabilities & CAP_UNICODE)
+		buffer->Flags2 |= SMBFLG2_UNICODE;
+	if (ses->capabilities & CAP_STATUS32)
+		buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+
+	/* uid, tid can stay at zero as set in header assemble */
+
+	/* BB add support for turning on the signing when 
+	this function is used after 1st of session setup requests */
+
+	return rc;
+}
+#endif  /* CONFIG_CIFS_EXPERIMENTAL */
 
 /* If the return code is zero, this function must fill in request_buf pointer */
 static int
@@ -1042,7 +1070,7 @@
 		}
 	}
 
-	cifs_small_buf_release(pSMB);
+/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
 	if(*buf) {
 		if(resp_buf_type == CIFS_SMALL_BUFFER)
 			cifs_small_buf_release(iov[0].iov_base);
@@ -1246,7 +1274,7 @@
 		*nbytes += le16_to_cpu(pSMBr->Count);
 	} 
 
-	cifs_small_buf_release(pSMB);
+/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
 	if(resp_buf_type == CIFS_SMALL_BUFFER)
 		cifs_small_buf_release(iov[0].iov_base);
 	else if(resp_buf_type == CIFS_LARGE_BUFFER)
@@ -1325,6 +1353,85 @@
 }
 
 int
+CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
+		const __u16 smb_file_id, const int get_flag, const __u64 len,
+		const __u64 lkoffset, const __u16 lock_type, const int waitFlag)
+{
+	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
+	char *data_offset;
+	struct cifs_posix_lock *parm_data;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, param_offset, offset, byte_count, count;
+
+	cFYI(1, ("Posix Lock"));
+	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
+	if (rc)
+		return rc;
+
+	pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
+
+	params = 6; 
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+	offset = param_offset + params;
+
+	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+
+	count = sizeof(struct cifs_posix_lock);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	if(get_flag)
+		pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+	else
+		pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+	byte_count = 3 /* pad */  + params + count;
+	pSMB->DataCount = cpu_to_le16(count);
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	parm_data = (struct cifs_posix_lock *) 
+			(((char *) &pSMB->hdr.Protocol) + offset);
+
+	parm_data->lock_type = cpu_to_le16(lock_type);
+	if(waitFlag)
+		parm_data->lock_flags = 1;
+	parm_data->pid = cpu_to_le32(current->tgid);
+	parm_data->start = lkoffset;
+	parm_data->length = len;  /* normalize negative numbers */
+
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->Fid = smb_file_id;
+	pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in Posix Lock = %d", rc));
+	}
+
+	if (pSMB)
+		cifs_small_buf_release(pSMB);
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls
+	   since file handle passed in no longer valid */
+
+	return rc;
+}
+
+
+int
 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 {
 	int rc = 0;
@@ -2578,7 +2685,7 @@
 		cifs_small_buf_release(iov[0].iov_base);
 	else if(buf_type == CIFS_LARGE_BUFFER)
 		cifs_buf_release(iov[0].iov_base);
-	cifs_small_buf_release(pSMB);
+/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
 	return rc;
 }
 
@@ -2954,7 +3061,8 @@
 	pSMB->TotalParameterCount = cpu_to_le16(params);
 	pSMB->ParameterCount = pSMB->TotalParameterCount;
 	pSMB->ParameterOffset = cpu_to_le16(
-	  offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
+	      offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
+		- 4);
 	pSMB->DataCount = 0;
 	pSMB->DataOffset = 0;
 	pSMB->SetupCount = 1;	/* one byte, no need to make endian neutral */
@@ -2977,12 +3085,12 @@
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 	cifs_stats_inc(&tcon->num_ffirst);
 
-	if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
+	if (rc) {/* BB add logic to retry regular search if Unix search
+			rejected unexpectedly by server */
 		/* BB Add code to handle unsupported level rc */
 		cFYI(1, ("Error in FindFirst = %d", rc));
 
-		if (pSMB)
-			cifs_buf_release(pSMB);
+		cifs_buf_release(pSMB);
 
 		/* BB eventually could optimize out free and realloc of buf */
 		/*    for this case */
@@ -2998,6 +3106,7 @@
 				psrch_inf->unicode = FALSE;
 
 			psrch_inf->ntwrk_buf_start = (char *)pSMBr;
+			psrch_inf->smallBuf = 0;
 			psrch_inf->srch_entries_start = 
 				(char *) &pSMBr->hdr.Protocol + 
 					le16_to_cpu(pSMBr->t2.DataOffset);
@@ -3118,9 +3227,14 @@
 			parms = (T2_FNEXT_RSP_PARMS *)response_data;
 			response_data = (char *)&pSMBr->hdr.Protocol +
 				le16_to_cpu(pSMBr->t2.DataOffset);
-			cifs_buf_release(psrch_inf->ntwrk_buf_start);
+			if(psrch_inf->smallBuf)
+				cifs_small_buf_release(
+					psrch_inf->ntwrk_buf_start);
+			else
+				cifs_buf_release(psrch_inf->ntwrk_buf_start);
 			psrch_inf->srch_entries_start = response_data;
 			psrch_inf->ntwrk_buf_start = (char *)pSMB;
+			psrch_inf->smallBuf = 0;
 			if(parms->EndofSearch)
 				psrch_inf->endOfSearch = TRUE;
 			else
@@ -3834,6 +3948,7 @@
 
 	cFYI(1, ("In SETFSUnixInfo"));
 SETFSUnixRetry:
+	/* BB switch to small buf init to save memory */
 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
 	if (rc)
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 2a0c1f4..0b86d5c 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/connect.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   Copyright (C) International Business Machines  Corp., 2002,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -564,7 +564,7 @@
 	
 
 		dump_smb(smb_buffer, length);
-		if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
+		if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
 			cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
 			continue;
 		}
@@ -1476,6 +1476,14 @@
 			rc = smb_send(*csocket, smb_buf, 0x44,
 				(struct sockaddr *)psin_server);
 			kfree(ses_init_buf);
+			msleep(1); /* RFC1001 layer in at least one server 
+				      requires very short break before negprot
+				      presumably because not expecting negprot
+				      to follow so fast.  This is a simple
+				      solution that works without 
+				      complicating the code and causes no
+				      significant slowing down on mount
+				      for everyone else */
 		}
 		/* else the negprot may still work without this 
 		even though malloc failed */
@@ -1920,27 +1928,34 @@
 		cifs_sb->tcon = tcon;
 		tcon->ses = pSesInfo;
 
-		/* do not care if following two calls succeed - informational only */
+		/* do not care if following two calls succeed - informational */
 		CIFSSMBQFSDeviceInfo(xid, tcon);
 		CIFSSMBQFSAttributeInfo(xid, tcon);
+
 		if (tcon->ses->capabilities & CAP_UNIX) {
 			if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
-				if(!volume_info.no_psx_acl) {
-					if(CIFS_UNIX_POSIX_ACL_CAP & 
-					   le64_to_cpu(tcon->fsUnixInfo.Capability))
-						cFYI(1,("server negotiated posix acl support"));
-						sb->s_flags |= MS_POSIXACL;
+				__u64 cap = 
+				       le64_to_cpu(tcon->fsUnixInfo.Capability);
+				cap &= CIFS_UNIX_CAP_MASK;
+				if(volume_info.no_psx_acl)
+					cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
+				else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
+					cFYI(1,("negotiated posix acl support"));
+					sb->s_flags |= MS_POSIXACL;
 				}
 
-				/* Try and negotiate POSIX pathnames if we can. */
-				if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
-				    le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-					if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP))  {
-						cFYI(1,("negotiated posix pathnames support"));
-						cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
-					} else {
-						cFYI(1,("posix pathnames support requested but not supported"));
-					}
+				if(volume_info.posix_paths == 0)
+					cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
+				else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+					cFYI(1,("negotiate posix pathnames"));
+					cifs_sb->mnt_cifs_flags |= 
+						CIFS_MOUNT_POSIX_PATHS;
+				}
+					
+				cFYI(1,("Negotiate caps 0x%x",(int)cap));
+
+				if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
+					cFYI(1,("setting capabilities failed"));
 				}
 			}
 		}
@@ -2278,6 +2293,8 @@
 	smb_buffer->Mid = GetNextMid(ses->server);
 	pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
 	pSMB->req.AndXCommand = 0xFF;
+	if(ses->server->maxBuf > 64*1024)
+		ses->server->maxBuf = (64*1023);
 	pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
 	pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
 
@@ -2525,7 +2542,7 @@
 	__u32 negotiate_flags, capabilities;
 	__u16 count;
 
-	cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
+	cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
 	if(ses == NULL)
 		return -EINVAL;
 	domain = ses->domainName;
@@ -2575,7 +2592,8 @@
 	SecurityBlob->MessageType = NtLmNegotiate;
 	negotiate_flags =
 	    NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
-	    NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
+	    NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
+	    NTLMSSP_NEGOTIATE_56 |
 	    /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
 	if(sign_CIFS_PDUs)
 		negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
@@ -2588,26 +2606,11 @@
 	SecurityBlob->WorkstationName.Length = 0;
 	SecurityBlob->WorkstationName.MaximumLength = 0;
 
-	if (domain == NULL) {
-		SecurityBlob->DomainName.Buffer = 0;
-		SecurityBlob->DomainName.Length = 0;
-		SecurityBlob->DomainName.MaximumLength = 0;
-	} else {
-		__u16 len;
-		negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
-		strncpy(bcc_ptr, domain, 63);
-		len = strnlen(domain, 64);
-		SecurityBlob->DomainName.MaximumLength =
-		    cpu_to_le16(len);
-		SecurityBlob->DomainName.Buffer =
-		    cpu_to_le32((long) &SecurityBlob->
-				DomainString -
-				(long) &SecurityBlob->Signature);
-		bcc_ptr += len;
-		SecurityBlobLength += len;
-		SecurityBlob->DomainName.Length =
-		    cpu_to_le16(len);
-	}
+	/* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
+	along with username on auth request (ie the response to challenge) */
+	SecurityBlob->DomainName.Buffer = 0;
+	SecurityBlob->DomainName.Length = 0;
+	SecurityBlob->DomainName.MaximumLength = 0;
 	if (ses->capabilities & CAP_UNICODE) {
 		if ((long) bcc_ptr % 2) {
 			*bcc_ptr = 0;
@@ -2677,7 +2680,7 @@
 			      SecurityBlob2->MessageType));
 		} else if (ses) {
 			ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ 
-			cFYI(1, ("UID = %d ", ses->Suid));
+			cFYI(1, ("UID = %d", ses->Suid));
 			if ((pSMBr->resp.hdr.WordCount == 3)
 			    || ((pSMBr->resp.hdr.WordCount == 4)
 				&& (blob_len <
@@ -2685,17 +2688,17 @@
 
 				if (pSMBr->resp.hdr.WordCount == 4) {
 					bcc_ptr += blob_len;
-					cFYI(1,
-					     ("Security Blob Length %d ",
+					cFYI(1, ("Security Blob Length %d",
 					      blob_len));
 				}
 
-				cFYI(1, ("NTLMSSP Challenge rcvd "));
+				cFYI(1, ("NTLMSSP Challenge rcvd"));
 
 				memcpy(ses->server->cryptKey,
 				       SecurityBlob2->Challenge,
 				       CIFS_CRYPTO_KEY_SIZE);
-				if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
+				if(SecurityBlob2->NegotiateFlags & 
+					cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
 					*pNTLMv2_flag = TRUE;
 
 				if((SecurityBlob2->NegotiateFlags & 
@@ -2818,7 +2821,7 @@
 						bcc_ptr++;
 					} else
 						cFYI(1,
-						     ("Variable field of length %d extends beyond end of smb ",
+						     ("Variable field of length %d extends beyond end of smb",
 						      len));
 				}
 			} else {
@@ -2830,7 +2833,7 @@
 		}
 	} else {
 		cERROR(1,
-		       (" Invalid Word count %d: ",
+		       (" Invalid Word count %d:",
 			smb_buffer_response->WordCount));
 		rc = -EIO;
 	}
@@ -3447,7 +3450,7 @@
 		if (extended_security
 				&& (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
 				&& (pSesInfo->server->secType == NTLMSSP)) {
-			cFYI(1, ("New style sesssetup "));
+			cFYI(1, ("New style sesssetup"));
 			rc = CIFSSpnegoSessSetup(xid, pSesInfo,
 				NULL /* security blob */, 
 				0 /* blob length */,
@@ -3455,7 +3458,7 @@
 		} else if (extended_security
 			   && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
 			   && (pSesInfo->server->secType == RawNTLMSSP)) {
-			cFYI(1, ("NTLMSSP sesssetup "));
+			cFYI(1, ("NTLMSSP sesssetup"));
 			rc = CIFSNTLMSSPNegotiateSessSetup(xid,
 						pSesInfo,
 						&ntlmv2_flag,
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 632561d..1d0ca3e 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -48,13 +48,14 @@
 	struct dentry *temp;
 	int namelen = 0;
 	char *full_path;
-	char dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
+	char dirsep;
 
 	if(direntry == NULL)
 		return NULL;  /* not much we can do if dentry is freed and
 		we need to reopen the file after it was closed implicitly
 		when the server crashed */
 
+	dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
 cifs_bp_rename_retry:
 	for (temp = direntry; !IS_ROOT(temp);) {
 		namelen += (1 + temp->d_name.len);
@@ -255,12 +256,10 @@
 			CIFSSMBClose(xid, pTcon, fileHandle);
 		} else if(newinode) {
 			pCifsFile =
-			   kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
+			   kzalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
 			
 			if(pCifsFile == NULL)
 				goto cifs_create_out;
-			memset((char *)pCifsFile, 0,
-			       sizeof (struct cifsFileInfo));
 			pCifsFile->netfid = fileHandle;
 			pCifsFile->pid = current->tgid;
 			pCifsFile->pInode = newinode;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 165d674..5c497c5 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -555,7 +555,10 @@
 		if (ptmp) {
 			cFYI(1, ("closedir free smb buf in srch struct"));
 			pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
-			cifs_buf_release(ptmp);
+			if(pCFileStruct->srch_inf.smallBuf)
+				cifs_small_buf_release(ptmp);
+			else
+				cifs_buf_release(ptmp);
 		}
 		ptmp = pCFileStruct->search_resume_name;
 		if (ptmp) {
@@ -574,13 +577,14 @@
 int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 {
 	int rc, xid;
-	__u32 lockType = LOCKING_ANDX_LARGE_FILES;
 	__u32 numLock = 0;
 	__u32 numUnlock = 0;
 	__u64 length;
 	int wait_flag = FALSE;
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
+	__u16 netfid;
+	__u8 lockType = LOCKING_ANDX_LARGE_FILES;
 
 	length = 1 + pfLock->fl_end - pfLock->fl_start;
 	rc = -EACCES;
@@ -592,11 +596,11 @@
 	        pfLock->fl_end));
 
 	if (pfLock->fl_flags & FL_POSIX)
-		cFYI(1, ("Posix "));
+		cFYI(1, ("Posix"));
 	if (pfLock->fl_flags & FL_FLOCK)
-		cFYI(1, ("Flock "));
+		cFYI(1, ("Flock"));
 	if (pfLock->fl_flags & FL_SLEEP) {
-		cFYI(1, ("Blocking lock "));
+		cFYI(1, ("Blocking lock"));
 		wait_flag = TRUE;
 	}
 	if (pfLock->fl_flags & FL_ACCESS)
@@ -612,21 +616,23 @@
 		cFYI(1, ("F_WRLCK "));
 		numLock = 1;
 	} else if (pfLock->fl_type == F_UNLCK) {
-		cFYI(1, ("F_UNLCK "));
+		cFYI(1, ("F_UNLCK"));
 		numUnlock = 1;
+		/* Check if unlock includes more than
+		one lock range */
 	} else if (pfLock->fl_type == F_RDLCK) {
-		cFYI(1, ("F_RDLCK "));
+		cFYI(1, ("F_RDLCK"));
 		lockType |= LOCKING_ANDX_SHARED_LOCK;
 		numLock = 1;
 	} else if (pfLock->fl_type == F_EXLCK) {
-		cFYI(1, ("F_EXLCK "));
+		cFYI(1, ("F_EXLCK"));
 		numLock = 1;
 	} else if (pfLock->fl_type == F_SHLCK) {
-		cFYI(1, ("F_SHLCK "));
+		cFYI(1, ("F_SHLCK"));
 		lockType |= LOCKING_ANDX_SHARED_LOCK;
 		numLock = 1;
 	} else
-		cFYI(1, ("Unknown type of lock "));
+		cFYI(1, ("Unknown type of lock"));
 
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	pTcon = cifs_sb->tcon;
@@ -635,27 +641,41 @@
 		FreeXid(xid);
 		return -EBADF;
 	}
+	netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
 
+
+	/* BB add code here to normalize offset and length to
+	account for negative length which we can not accept over the
+	wire */
 	if (IS_GETLK(cmd)) {
-		rc = CIFSSMBLock(xid, pTcon,
-				 ((struct cifsFileInfo *)file->
-				  private_data)->netfid,
-				 length,
-				 pfLock->fl_start, 0, 1, lockType,
-				 0 /* wait flag */ );
+		if(experimEnabled && 
+		   (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
+		   (CIFS_UNIX_FCNTL_CAP & 
+			le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
+			int posix_lock_type;
+			if(lockType & LOCKING_ANDX_SHARED_LOCK)
+				posix_lock_type = CIFS_RDLCK;
+			else
+				posix_lock_type = CIFS_WRLCK;
+			rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,
+					length,	pfLock->fl_start,
+					posix_lock_type, wait_flag);
+			FreeXid(xid);
+			return rc;
+		}
+
+		/* BB we could chain these into one lock request BB */
+		rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+				 0, 1, lockType, 0 /* wait flag */ );
 		if (rc == 0) {
-			rc = CIFSSMBLock(xid, pTcon,
-					 ((struct cifsFileInfo *) file->
-					  private_data)->netfid,
-					 length,
+			rc = CIFSSMBLock(xid, pTcon, netfid, length, 
 					 pfLock->fl_start, 1 /* numUnlock */ ,
 					 0 /* numLock */ , lockType,
 					 0 /* wait flag */ );
 			pfLock->fl_type = F_UNLCK;
 			if (rc != 0)
 				cERROR(1, ("Error unlocking previously locked "
-					   "range %d during test of lock ",
-					   rc));
+					   "range %d during test of lock", rc));
 			rc = 0;
 
 		} else {
@@ -667,12 +687,30 @@
 		FreeXid(xid);
 		return rc;
 	}
-
-	rc = CIFSSMBLock(xid, pTcon,
-			 ((struct cifsFileInfo *) file->private_data)->
-			 netfid, length,
-			 pfLock->fl_start, numUnlock, numLock, lockType,
-			 wait_flag);
+	if (experimEnabled &&
+		(cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
+		(CIFS_UNIX_FCNTL_CAP &
+			 le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
+		int posix_lock_type;
+		if(lockType & LOCKING_ANDX_SHARED_LOCK)
+			posix_lock_type = CIFS_RDLCK;
+		else
+			posix_lock_type = CIFS_WRLCK;
+		
+		if(numUnlock == 1)
+			posix_lock_type = CIFS_UNLCK;
+		else if(numLock == 0) {
+			/* if no lock or unlock then nothing
+			to do since we do not know what it is */
+			FreeXid(xid);
+			return -EOPNOTSUPP;
+		}
+		rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
+				      length, pfLock->fl_start,
+				      posix_lock_type, wait_flag);
+	} else
+		rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+				numUnlock, numLock, lockType, wait_flag);
 	if (pfLock->fl_flags & FL_POSIX)
 		posix_lock_file_wait(file, pfLock);
 	FreeXid(xid);
@@ -1339,7 +1377,7 @@
 	return rc;
 }
 
-/* static int cifs_sync_page(struct page *page)
+/* static void cifs_sync_page(struct page *page)
 {
 	struct address_space *mapping;
 	struct inode *inode;
@@ -1353,16 +1391,18 @@
 		return 0;
 	inode = mapping->host;
 	if (!inode)
-		return 0; */
+		return; */
 
 /*	fill in rpages then 
 	result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
 
 /*	cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
 
+#if 0
 	if (rc < 0)
 		return rc;
 	return 0;
+#endif
 } */
 
 /*
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index ff93a9f..957ddd1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -163,9 +163,9 @@
 
 		if (num_of_bytes < end_of_file)
 			cFYI(1, ("allocation size less than end of file"));
-		cFYI(1,
-		     ("Size %ld and blocks %ld",
-		      (unsigned long) inode->i_size, inode->i_blocks));
+		cFYI(1, ("Size %ld and blocks %llu",
+			(unsigned long) inode->i_size,
+			(unsigned long long)inode->i_blocks));
 		if (S_ISREG(inode->i_mode)) {
 			cFYI(1, ("File inode"));
 			inode->i_op = &cifs_file_inode_ops;
@@ -565,11 +565,14 @@
 	struct cifsInodeInfo *cifsInode;
 	FILE_BASIC_INFO *pinfo_buf;
 
-	cFYI(1, ("cifs_unlink, inode = 0x%p with ", inode));
+	cFYI(1, ("cifs_unlink, inode = 0x%p", inode));
 
 	xid = GetXid();
 
-	cifs_sb = CIFS_SB(inode->i_sb);
+	if(inode)
+		cifs_sb = CIFS_SB(inode->i_sb);
+	else
+		cifs_sb = CIFS_SB(direntry->d_sb);
 	pTcon = cifs_sb->tcon;
 
 	/* Unlink can be called from rename so we can not grab the sem here
@@ -609,9 +612,8 @@
 		}
 	} else if (rc == -EACCES) {
 		/* try only if r/o attribute set in local lookup data? */
-		pinfo_buf = kmalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
+		pinfo_buf = kzalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
 		if (pinfo_buf) {
-			memset(pinfo_buf, 0, sizeof(FILE_BASIC_INFO));
 			/* ATTRS set to normal clears r/o bit */
 			pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
 			if (!(pTcon->ses->flags & CIFS_SES_NT4))
@@ -693,9 +695,11 @@
 					   when needed */
 		direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
 	}
-	inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
-	cifsInode = CIFS_I(inode);
-	cifsInode->time = 0;	/* force revalidate of dir as well */
+	if(inode) {
+		inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
+		cifsInode = CIFS_I(inode);
+		cifsInode->time = 0;	/* force revalidate of dir as well */
+	}
 
 	kfree(full_path);
 	FreeXid(xid);
@@ -1167,7 +1171,7 @@
 						nfid, npid, FALSE);
 			atomic_dec(&open_file->wrtPending);
 			cFYI(1,("SetFSize for attrs rc = %d", rc));
-			if(rc == -EINVAL) {
+			if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
 				int bytes_written;
 				rc = CIFSSMBWrite(xid, pTcon,
 						  nfid, 0, attrs->ia_size,
@@ -1189,7 +1193,7 @@
 					   cifs_sb->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
-			if(rc == -EINVAL) {
+			if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
 				__u16 netfid;
 				int oplock = FALSE;
 
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 8d0da7c..9562f5b 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -67,7 +67,7 @@
 					cifs_sb_target->local_nls, 
 					cifs_sb_target->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
-		if(rc == -EIO)
+		if((rc == -EIO) || (rc == -EINVAL))
 			rc = -EOPNOTSUPP;  
 	}
 
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 432ba15..fafd056 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -72,10 +72,9 @@
 	struct cifsSesInfo *ret_buf;
 
 	ret_buf =
-	    (struct cifsSesInfo *) kmalloc(sizeof (struct cifsSesInfo),
+	    (struct cifsSesInfo *) kzalloc(sizeof (struct cifsSesInfo),
 					   GFP_KERNEL);
 	if (ret_buf) {
-		memset(ret_buf, 0, sizeof (struct cifsSesInfo));
 		write_lock(&GlobalSMBSeslock);
 		atomic_inc(&sesInfoAllocCount);
 		ret_buf->status = CifsNew;
@@ -110,10 +109,9 @@
 {
 	struct cifsTconInfo *ret_buf;
 	ret_buf =
-	    (struct cifsTconInfo *) kmalloc(sizeof (struct cifsTconInfo),
+	    (struct cifsTconInfo *) kzalloc(sizeof (struct cifsTconInfo),
 					    GFP_KERNEL);
 	if (ret_buf) {
-		memset(ret_buf, 0, sizeof (struct cifsTconInfo));
 		write_lock(&GlobalSMBSeslock);
 		atomic_inc(&tconInfoAllocCount);
 		list_add(&ret_buf->cifsConnectionList,
@@ -423,9 +421,7 @@
 {
 	__u32 len = smb->smb_buf_length;
 	__u32 clc_len;  /* calculated length */
-	cFYI(0,
-	     ("Entering checkSMB with Length: %x, smb_buf_length: %x",
-	      length, len));
+	cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));
 	if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
 	    (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
 		if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) {
@@ -433,29 +429,36 @@
 				sizeof (struct smb_hdr) - 1)
 			    && (smb->Status.CifsError != 0)) {
 				smb->WordCount = 0;
-				return 0;	/* some error cases do not return wct and bcc */
+				/* some error cases do not return wct and bcc */
+				return 0;
 			} else {
 				cERROR(1, ("Length less than smb header size"));
 			}
-
 		}
 		if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)
-			cERROR(1,
-			       ("smb_buf_length greater than MaxBufSize"));
-		cERROR(1,
-		       ("bad smb detected. Illegal length. mid=%d",
-			smb->Mid));
+			cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
+				   smb->Mid));
 		return 1;
 	}
 
 	if (checkSMBhdr(smb, mid))
 		return 1;
 	clc_len = smbCalcSize_LE(smb);
-	if ((4 + len != clc_len)
-	    || (4 + len != (unsigned int)length)) {
-		cERROR(1, ("Calculated size 0x%x vs actual length 0x%x",
-				clc_len, 4 + len));
-		cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid));
+
+	if(4 + len != (unsigned int)length) {
+		cERROR(1, ("Length read does not match RFC1001 length %d",len));
+		return 1;
+	}
+
+	if (4 + len != clc_len) {
+		/* check if bcc wrapped around for large read responses */
+		if((len > 64 * 1024) && (len > clc_len)) {
+			/* check if lengths match mod 64K */
+			if(((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
+				return 0; /* bcc wrapped */			
+		}
+		cFYI(1, ("Calculated size %d vs length %d mismatch for mid %d",
+				clc_len, 4 + len, smb->Mid));
 		/* Windows XP can return a few bytes too much, presumably
 		an illegal pad, at the end of byte range lock responses 
 		so we allow for that three byte pad, as long as actual
@@ -469,8 +472,11 @@
 		wct and bcc to minimum size and drop the t2 parms and data */
 		if((4+len > clc_len) && (len <= clc_len + 512))
 			return 0;
-		else
+		else {
+			cERROR(1, ("RFC1001 size %d bigger than SMB for Mid=%d",
+					len, smb->Mid));
 			return 1;
+		}
 	}
 	return 0;
 }
diff --git a/fs/cifs/ntlmssp.c b/fs/cifs/ntlmssp.c
new file mode 100644
index 0000000..78866f9
--- /dev/null
+++ b/fs/cifs/ntlmssp.c
@@ -0,0 +1,129 @@
+/*
+ *   fs/cifs/ntlmssp.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2006
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+#include "ntlmssp.h"
+#include "nterr.h"
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
+{
+	__u32 capabilities = 0;
+
+	/* init fields common to all four types of SessSetup */
+	/* note that header is initialized to zero in header_assemble */
+	pSMB->req.AndXCommand = 0xFF;
+	pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
+	pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
+
+	/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
+
+	/* BB verify whether signing required on neg or just on auth frame 
+	   (and NTLM case) */
+
+	capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+			CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
+
+	if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+		pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	if (ses->capabilities & CAP_UNICODE) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
+		capabilities |= CAP_UNICODE;
+	}
+	if (ses->capabilities & CAP_STATUS32) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
+		capabilities |= CAP_STATUS32;
+	}
+	if (ses->capabilities & CAP_DFS) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
+		capabilities |= CAP_DFS;
+	}
+
+	/* BB check whether to init vcnum BB */
+	return capabilities;
+}
+int 
+CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int type,
+		  int * pNTLMv2_flg, const struct nls_table *nls_cp)
+{
+	int rc = 0;
+	int wct;
+	struct smb_hdr *smb_buffer;
+	char *bcc_ptr;
+	SESSION_SETUP_ANDX *pSMB;
+	__u32 capabilities;
+
+	if(ses == NULL)
+		return -EINVAL;
+
+	cFYI(1,("SStp type: %d",type));
+	if(type < CIFS_NTLM) {
+#ifndef CONFIG_CIFS_WEAK_PW_HASH
+		/* LANMAN and plaintext are less secure and off by default.
+		So we make this explicitly be turned on in kconfig (in the
+		build) and turned on at runtime (changed from the default)
+		in proc/fs/cifs or via mount parm.  Unfortunately this is
+		needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
+		return -EOPNOTSUPP;
+#endif
+		wct = 10; /* lanman 2 style sessionsetup */
+	} else if(type < CIFS_NTLMSSP_NEG)
+		wct = 13; /* old style NTLM sessionsetup */
+	else /* same size for negotiate or auth, NTLMSSP or extended security */
+		wct = 12;
+
+	rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
+			    (void **)&smb_buffer);
+	if(rc)
+		return rc;
+
+	pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
+
+	capabilities = cifs_ssetup_hdr(ses, pSMB);
+	bcc_ptr = pByteArea(smb_buffer);
+	if(type > CIFS_NTLM) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+		capabilities |= CAP_EXTENDED_SECURITY;
+		pSMB->req.Capabilities = cpu_to_le32(capabilities);
+		/* BB set password lengths */
+	} else if(type < CIFS_NTLM) /* lanman */ {
+		/* no capabilities flags in old lanman negotiation */
+		/* pSMB->old_req.PasswordLength = */ /* BB fixme BB */
+	} else /* type CIFS_NTLM */ {
+		pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
+		pSMB->req_no_secext.CaseInsensitivePasswordLength =
+			cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+		pSMB->req_no_secext.CaseSensitivePasswordLength =
+			cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+	}
+
+
+/*	rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */
+	/* SMB request buf freed in SendReceive2 */
+
+	return rc;
+}
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h
index 803389b..d39b712 100644
--- a/fs/cifs/ntlmssp.h
+++ b/fs/cifs/ntlmssp.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/ntlmssp.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002
+ *   Copyright (c) International Business Machines  Corp., 2002,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index edb3b6e..2f6e282 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -197,10 +197,10 @@
 
 	if (allocation_size < end_of_file)
 		cFYI(1, ("May be sparse file, allocation less than file size"));
-	cFYI(1,
-	     ("File Size %ld and blocks %ld and blocksize %ld",
-	      (unsigned long)tmp_inode->i_size, tmp_inode->i_blocks,
-	      tmp_inode->i_blksize));
+	cFYI(1, ("File Size %ld and blocks %llu and blocksize %ld",
+		(unsigned long)tmp_inode->i_size,
+		(unsigned long long)tmp_inode->i_blocks,
+		tmp_inode->i_blksize));
 	if (S_ISREG(tmp_inode->i_mode)) {
 		cFYI(1, ("File inode"));
 		tmp_inode->i_op = &cifs_file_inode_ops;
@@ -604,7 +604,12 @@
 		cifsFile->search_resume_name = NULL;
 		if(cifsFile->srch_inf.ntwrk_buf_start) {
 			cFYI(1,("freeing SMB ff cache buf on search rewind"));
-			cifs_buf_release(cifsFile->srch_inf.ntwrk_buf_start);
+			if(cifsFile->srch_inf.smallBuf)
+				cifs_small_buf_release(cifsFile->srch_inf.
+						ntwrk_buf_start);
+			else
+				cifs_buf_release(cifsFile->srch_inf.
+						ntwrk_buf_start);
 		}
 		rc = initiate_cifs_search(xid,file);
 		if(rc) {
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index b12cb8a..3da8040 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -309,17 +309,16 @@
 	
 	*pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
 
-	if (ses == NULL) {
-		cERROR(1,("Null smb session"));
-		return -EIO;
-	}
-	if(ses->server == NULL) {
-		cERROR(1,("Null tcp session"));
+	if ((ses == NULL) || (ses->server == NULL)) {
+		cifs_small_buf_release(in_buf);
+		cERROR(1,("Null session"));
 		return -EIO;
 	}
 
-	if(ses->server->tcpStatus == CifsExiting)
+	if(ses->server->tcpStatus == CifsExiting) {
+		cifs_small_buf_release(in_buf);
 		return -ENOENT;
+	}
 
 	/* Ensure that we do not send more than 50 overlapping requests 
 	   to the same server. We may make this configurable later or
@@ -346,6 +345,7 @@
 			} else {
 				if(ses->server->tcpStatus == CifsExiting) {
 					spin_unlock(&GlobalMid_Lock);
+					cifs_small_buf_release(in_buf);
 					return -ENOENT;
 				}
 
@@ -385,6 +385,7 @@
 	midQ = AllocMidQEntry(in_buf, ses);
 	if (midQ == NULL) {
 		up(&ses->server->tcpSem);
+		cifs_small_buf_release(in_buf);
 		/* If not lock req, update # of requests on wire to server */
 		if(long_op < 3) {
 			atomic_dec(&ses->server->inFlight); 
@@ -408,14 +409,18 @@
 	if(rc < 0) {
 		DeleteMidQEntry(midQ);
 		up(&ses->server->tcpSem);
+		cifs_small_buf_release(in_buf);
 		/* If not lock req, update # of requests on wire to server */
 		if(long_op < 3) {
 			atomic_dec(&ses->server->inFlight); 
 			wake_up(&ses->server->request_q);
 		}
 		return rc;
-	} else
+	} else {
 		up(&ses->server->tcpSem);
+		cifs_small_buf_release(in_buf);
+	}
+
 	if (long_op == -1)
 		goto cifs_no_response_exit2;
 	else if (long_op == 2) /* writes past end of file can take loong time */
@@ -543,6 +548,7 @@
 
 out_unlock2:
 	up(&ses->server->tcpSem);
+	cifs_small_buf_release(in_buf);
 	/* If not lock req, update # of requests on wire to server */
 	if(long_op < 3) {
 		atomic_dec(&ses->server->inFlight); 
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 54f76de..71f2ea6 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -82,7 +82,7 @@
 	.setattr	= coda_setattr,
 };
 
-struct file_operations coda_dir_operations = {
+const struct file_operations coda_dir_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_read_dir,
 	.readdir	= coda_readdir,
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 146a991..7c26424 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -288,7 +288,7 @@
 	return err;
 }
 
-struct file_operations coda_file_operations = {
+const struct file_operations coda_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= coda_file_read,
 	.write		= coda_file_write,
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index 1277149..214822b 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -36,7 +36,7 @@
 	.setattr	= coda_setattr,
 };
 
-struct file_operations coda_ioctl_operations = {
+const struct file_operations coda_ioctl_operations = {
 	.owner		= THIS_MODULE,
 	.ioctl		= coda_pioctl,
 };
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 98c74fe..6c6771d 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -342,7 +342,7 @@
 }
 
 
-static struct file_operations coda_psdev_fops = {
+static const struct file_operations coda_psdev_fops = {
 	.owner		= THIS_MODULE,
 	.read		= coda_psdev_read,
 	.write		= coda_psdev_write,
diff --git a/fs/compat.c b/fs/compat.c
index ef5a077..7f8e26e 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1639,15 +1639,6 @@
  * This is a virtual copy of sys_select from fs/select.c and probably
  * should be compared to it from time to time
  */
-static void *select_bits_alloc(int size)
-{
-	return kmalloc(6 * size, GFP_KERNEL);
-}
-
-static void select_bits_free(void *bits, int size)
-{
-	kfree(bits);
-}
 
 /*
  * We can actually return ERESTARTSYS instead of EINTR, but I'd
@@ -1686,7 +1677,7 @@
 	 */
 	ret = -ENOMEM;
 	size = FDS_BYTES(n);
-	bits = select_bits_alloc(size);
+	bits = kmalloc(6 * size, GFP_KERNEL);
 	if (!bits)
 		goto out_nofds;
 	fds.in      = (unsigned long *)  bits;
@@ -1720,7 +1711,7 @@
 	compat_set_fd_set(n, exp, fds.res_ex);
 
 out:
-	select_bits_free(bits, size);
+	kfree(bits);
 out_nofds:
 	return ret;
 }
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h
index f70e469..3f4ff7a 100644
--- a/fs/configfs/configfs_internal.h
+++ b/fs/configfs/configfs_internal.h
@@ -72,9 +72,9 @@
 
 extern struct rw_semaphore configfs_rename_sem;
 extern struct super_block * configfs_sb;
-extern struct file_operations configfs_dir_operations;
-extern struct file_operations configfs_file_operations;
-extern struct file_operations bin_fops;
+extern const struct file_operations configfs_dir_operations;
+extern const struct file_operations configfs_file_operations;
+extern const struct file_operations bin_fops;
 extern struct inode_operations configfs_dir_inode_operations;
 extern struct inode_operations configfs_symlink_inode_operations;
 
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index ca60e3a..8ed9b06 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -1027,7 +1027,7 @@
 	return offset;
 }
 
-struct file_operations configfs_dir_operations = {
+const struct file_operations configfs_dir_operations = {
 	.open		= configfs_dir_open,
 	.release	= configfs_dir_close,
 	.llseek		= configfs_dir_lseek,
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index 3921920..f499803 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -322,7 +322,7 @@
 	return 0;
 }
 
-struct file_operations configfs_file_operations = {
+const struct file_operations configfs_file_operations = {
 	.read		= configfs_read_file,
 	.write		= configfs_write_file,
 	.llseek		= generic_file_llseek,
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 8ad52f5..9efcc3a 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -22,16 +22,17 @@
 #include <linux/cramfs_fs_sb.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
+#include <linux/mutex.h>
 #include <asm/semaphore.h>
 
 #include <asm/uaccess.h>
 
 static struct super_operations cramfs_ops;
 static struct inode_operations cramfs_dir_inode_operations;
-static struct file_operations cramfs_directory_operations;
+static const struct file_operations cramfs_directory_operations;
 static struct address_space_operations cramfs_aops;
 
-static DECLARE_MUTEX(read_mutex);
+static DEFINE_MUTEX(read_mutex);
 
 
 /* These two macros may change in future, to provide better st_ino
@@ -250,20 +251,20 @@
 	memset(sbi, 0, sizeof(struct cramfs_sb_info));
 
 	/* Invalidate the read buffers on mount: think disk change.. */
-	down(&read_mutex);
+	mutex_lock(&read_mutex);
 	for (i = 0; i < READ_BUFFERS; i++)
 		buffer_blocknr[i] = -1;
 
 	/* Read the first block and get the superblock from it */
 	memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super));
-	up(&read_mutex);
+	mutex_unlock(&read_mutex);
 
 	/* Do sanity checks on the superblock */
 	if (super.magic != CRAMFS_MAGIC) {
 		/* check at 512 byte offset */
-		down(&read_mutex);
+		mutex_lock(&read_mutex);
 		memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super));
-		up(&read_mutex);
+		mutex_unlock(&read_mutex);
 		if (super.magic != CRAMFS_MAGIC) {
 			if (!silent)
 				printk(KERN_ERR "cramfs: wrong magic\n");
@@ -366,7 +367,7 @@
 		mode_t mode;
 		int namelen, error;
 
-		down(&read_mutex);
+		mutex_lock(&read_mutex);
 		de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+256);
 		name = (char *)(de+1);
 
@@ -379,7 +380,7 @@
 		memcpy(buf, name, namelen);
 		ino = CRAMINO(de);
 		mode = de->mode;
-		up(&read_mutex);
+		mutex_unlock(&read_mutex);
 		nextoffset = offset + sizeof(*de) + namelen;
 		for (;;) {
 			if (!namelen) {
@@ -410,7 +411,7 @@
 	unsigned int offset = 0;
 	int sorted;
 
-	down(&read_mutex);
+	mutex_lock(&read_mutex);
 	sorted = CRAMFS_SB(dir->i_sb)->flags & CRAMFS_FLAG_SORTED_DIRS;
 	while (offset < dir->i_size) {
 		struct cramfs_inode *de;
@@ -433,7 +434,7 @@
 
 		for (;;) {
 			if (!namelen) {
-				up(&read_mutex);
+				mutex_unlock(&read_mutex);
 				return ERR_PTR(-EIO);
 			}
 			if (name[namelen-1])
@@ -447,7 +448,7 @@
 			continue;
 		if (!retval) {
 			struct cramfs_inode entry = *de;
-			up(&read_mutex);
+			mutex_unlock(&read_mutex);
 			d_add(dentry, get_cramfs_inode(dir->i_sb, &entry));
 			return NULL;
 		}
@@ -455,7 +456,7 @@
 		if (sorted)
 			break;
 	}
-	up(&read_mutex);
+	mutex_unlock(&read_mutex);
 	d_add(dentry, NULL);
 	return NULL;
 }
@@ -474,21 +475,21 @@
 		u32 start_offset, compr_len;
 
 		start_offset = OFFSET(inode) + maxblock*4;
-		down(&read_mutex);
+		mutex_lock(&read_mutex);
 		if (page->index)
 			start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, 4);
 		compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) - start_offset);
-		up(&read_mutex);
+		mutex_unlock(&read_mutex);
 		pgdata = kmap(page);
 		if (compr_len == 0)
 			; /* hole */
 		else {
-			down(&read_mutex);
+			mutex_lock(&read_mutex);
 			bytes_filled = cramfs_uncompress_block(pgdata,
 				 PAGE_CACHE_SIZE,
 				 cramfs_read(sb, start_offset, compr_len),
 				 compr_len);
-			up(&read_mutex);
+			mutex_unlock(&read_mutex);
 		}
 	} else
 		pgdata = kmap(page);
@@ -511,7 +512,7 @@
 /*
  * A directory can only readdir
  */
-static struct file_operations cramfs_directory_operations = {
+static const struct file_operations cramfs_directory_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_read_dir,
 	.readdir	= cramfs_readdir,
diff --git a/fs/dcache.c b/fs/dcache.c
index 93958464..940d188 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -34,9 +34,8 @@
 #include <linux/swap.h>
 #include <linux/bootmem.h>
 
-/* #define DCACHE_DEBUG 1 */
 
-int sysctl_vfs_cache_pressure = 100;
+int sysctl_vfs_cache_pressure __read_mostly = 100;
 EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
 
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock);
@@ -44,7 +43,7 @@
 
 EXPORT_SYMBOL(dcache_lock);
 
-static kmem_cache_t *dentry_cache; 
+static kmem_cache_t *dentry_cache __read_mostly;
 
 #define DNAME_INLINE_LEN (sizeof(struct dentry)-offsetof(struct dentry,d_iname))
 
@@ -59,9 +58,9 @@
 #define D_HASHBITS     d_hash_shift
 #define D_HASHMASK     d_hash_mask
 
-static unsigned int d_hash_mask;
-static unsigned int d_hash_shift;
-static struct hlist_head *dentry_hashtable;
+static unsigned int d_hash_mask __read_mostly;
+static unsigned int d_hash_shift __read_mostly;
+static struct hlist_head *dentry_hashtable __read_mostly;
 static LIST_HEAD(dentry_unused);
 
 /* Statistics gathering. */
@@ -603,10 +602,6 @@
 		 */
 		if (!list_empty(&dentry->d_subdirs)) {
 			this_parent = dentry;
-#ifdef DCACHE_DEBUG
-printk(KERN_DEBUG "select_parent: descending to %s/%s, found=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, found);
-#endif
 			goto repeat;
 		}
 	}
@@ -616,10 +611,6 @@
 	if (this_parent != parent) {
 		next = this_parent->d_u.d_child.next;
 		this_parent = this_parent->d_parent;
-#ifdef DCACHE_DEBUG
-printk(KERN_DEBUG "select_parent: ascending to %s/%s, found=%d\n",
-this_parent->d_parent->d_name.name, this_parent->d_name.name, found);
-#endif
 		goto resume;
 	}
 out:
@@ -798,7 +789,7 @@
  
 void d_instantiate(struct dentry *entry, struct inode * inode)
 {
-	if (!list_empty(&entry->d_alias)) BUG();
+	BUG_ON(!list_empty(&entry->d_alias));
 	spin_lock(&dcache_lock);
 	if (inode)
 		list_add(&entry->d_alias, &inode->i_dentry);
@@ -1110,6 +1101,32 @@
 }
 
 /**
+ * d_hash_and_lookup - hash the qstr then search for a dentry
+ * @dir: Directory to search in
+ * @name: qstr of name we wish to find
+ *
+ * On hash failure or on lookup failure NULL is returned.
+ */
+struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name)
+{
+	struct dentry *dentry = NULL;
+
+	/*
+	 * Check for a fs-specific hash function. Note that we must
+	 * calculate the standard hash first, as the d_op->d_hash()
+	 * routine may choose to leave the hash value unchanged.
+	 */
+	name->hash = full_name_hash(name->name, name->len);
+	if (dir->d_op && dir->d_op->d_hash) {
+		if (dir->d_op->d_hash(dir, name) < 0)
+			goto out;
+	}
+	dentry = d_lookup(dir, name);
+out:
+	return dentry;
+}
+
+/**
  * d_validate - verify dentry provided from insecure source
  * @dentry: The dentry alleged to be valid child of @dparent
  * @dparent: The parent dentry (known to be valid)
@@ -1181,11 +1198,11 @@
 	spin_lock(&dentry->d_lock);
 	isdir = S_ISDIR(dentry->d_inode->i_mode);
 	if (atomic_read(&dentry->d_count) == 1) {
-		/* remove this and other inotify debug checks after 2.6.18 */
-		dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED;
-
 		dentry_iput(dentry);
 		fsnotify_nameremove(dentry, isdir);
+
+		/* remove this and other inotify debug checks after 2.6.18 */
+		dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED;
 		return;
 	}
 
@@ -1625,26 +1642,12 @@
 	struct dentry * dentry;
 	ino_t ino = 0;
 
-	/*
-	 * Check for a fs-specific hash function. Note that we must
-	 * calculate the standard hash first, as the d_op->d_hash()
-	 * routine may choose to leave the hash value unchanged.
-	 */
-	name->hash = full_name_hash(name->name, name->len);
-	if (dir->d_op && dir->d_op->d_hash)
-	{
-		if (dir->d_op->d_hash(dir, name) != 0)
-			goto out;
-	}
-
-	dentry = d_lookup(dir, name);
-	if (dentry)
-	{
+	dentry = d_hash_and_lookup(dir, name);
+	if (dentry) {
 		if (dentry->d_inode)
 			ino = dentry->d_inode->i_ino;
 		dput(dentry);
 	}
-out:
 	return ino;
 }
 
@@ -1719,10 +1722,10 @@
 }
 
 /* SLAB cache for __getname() consumers */
-kmem_cache_t *names_cachep;
+kmem_cache_t *names_cachep __read_mostly;
 
 /* SLAB cache for file structures */
-kmem_cache_t *filp_cachep;
+kmem_cache_t *filp_cachep __read_mostly;
 
 EXPORT_SYMBOL(d_genocide);
 
diff --git a/fs/dcookies.c b/fs/dcookies.c
index f8274a8..8749339 100644
--- a/fs/dcookies.c
+++ b/fs/dcookies.c
@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/dcookies.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 /* The dcookies are allocated from a kmem_cache and
@@ -36,10 +37,10 @@
 };
 
 static LIST_HEAD(dcookie_users);
-static DECLARE_MUTEX(dcookie_sem);
-static kmem_cache_t * dcookie_cache;
-static struct list_head * dcookie_hashtable;
-static size_t hash_size;
+static DEFINE_MUTEX(dcookie_mutex);
+static kmem_cache_t *dcookie_cache __read_mostly;
+static struct list_head *dcookie_hashtable __read_mostly;
+static size_t hash_size __read_mostly;
 
 static inline int is_live(void)
 {
@@ -114,7 +115,7 @@
 	int err = 0;
 	struct dcookie_struct * dcs;
 
-	down(&dcookie_sem);
+	mutex_lock(&dcookie_mutex);
 
 	if (!is_live()) {
 		err = -EINVAL;
@@ -134,7 +135,7 @@
 	*cookie = dcookie_value(dcs);
 
 out:
-	up(&dcookie_sem);
+	mutex_unlock(&dcookie_mutex);
 	return err;
 }
 
@@ -157,7 +158,7 @@
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	down(&dcookie_sem);
+	mutex_lock(&dcookie_mutex);
 
 	if (!is_live()) {
 		err = -EINVAL;
@@ -192,7 +193,7 @@
 out_free:
 	kfree(kbuf);
 out:
-	up(&dcookie_sem);
+	mutex_unlock(&dcookie_mutex);
 	return err;
 }
 
@@ -290,7 +291,7 @@
 {
 	struct dcookie_user * user;
 
-	down(&dcookie_sem);
+	mutex_lock(&dcookie_mutex);
 
 	user = kmalloc(sizeof(struct dcookie_user), GFP_KERNEL);
 	if (!user)
@@ -302,7 +303,7 @@
 	list_add(&user->next, &dcookie_users);
 
 out:
-	up(&dcookie_sem);
+	mutex_unlock(&dcookie_mutex);
 	return user;
 out_free:
 	kfree(user);
@@ -313,7 +314,7 @@
 
 void dcookie_unregister(struct dcookie_user * user)
 {
-	down(&dcookie_sem);
+	mutex_lock(&dcookie_mutex);
 
 	list_del(&user->next);
 	kfree(user);
@@ -321,7 +322,7 @@
 	if (!is_live())
 		dcookie_exit();
 
-	up(&dcookie_sem);
+	mutex_unlock(&dcookie_mutex);
 }
 
 EXPORT_SYMBOL_GPL(dcookie_register);
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 40c4fc9..66a5054 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -39,7 +39,7 @@
 	return 0;
 }
 
-struct file_operations debugfs_file_operations = {
+const struct file_operations debugfs_file_operations = {
 	.read =		default_read_file,
 	.write =	default_write_file,
 	.open =		default_open,
@@ -213,7 +213,7 @@
 	return count;
 }
 
-static struct file_operations fops_bool = {
+static const struct file_operations fops_bool = {
 	.read =		read_file_bool,
 	.write =	write_file_bool,
 	.open =		default_open,
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index d4f1a2c..85d166c 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -191,7 +191,7 @@
  */
 struct dentry *debugfs_create_file(const char *name, mode_t mode,
 				   struct dentry *parent, void *data,
-				   struct file_operations *fops)
+				   const struct file_operations *fops)
 {
 	struct dentry *dentry = NULL;
 	int error;
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index b621521..52f5059 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -856,14 +856,14 @@
 #ifdef CONFIG_DEVFS_DEBUG
 static ssize_t stat_read(struct file *file, char __user *buf, size_t len,
 			 loff_t * ppos);
-static struct file_operations stat_fops = {
+static const struct file_operations stat_fops = {
 	.open = nonseekable_open,
 	.read = stat_read,
 };
 #endif
 
 /*  Devfs daemon file operations  */
-static struct file_operations devfsd_fops = {
+static const struct file_operations devfsd_fops = {
 	.open = nonseekable_open,
 	.read = devfsd_read,
 	.ioctl = devfsd_ioctl,
@@ -1842,8 +1842,8 @@
 
 static struct inode_operations devfs_iops;
 static struct inode_operations devfs_dir_iops;
-static struct file_operations devfs_fops;
-static struct file_operations devfs_dir_fops;
+static const struct file_operations devfs_fops;
+static const struct file_operations devfs_dir_fops;
 static struct inode_operations devfs_symlink_iops;
 
 static int devfs_notify_change(struct dentry *dentry, struct iattr *iattr)
@@ -2061,11 +2061,11 @@
 	return err;
 }				/*  End Function devfs_open  */
 
-static struct file_operations devfs_fops = {
+static const struct file_operations devfs_fops = {
 	.open = devfs_open,
 };
 
-static struct file_operations devfs_dir_fops = {
+static const struct file_operations devfs_dir_fops = {
 	.read = generic_read_dir,
 	.readdir = devfs_readdir,
 };
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 235ed8d..910a8ed 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -86,12 +86,12 @@
 	unsigned first_block_in_page;	/* doesn't change, Used only once */
 	int boundary;			/* prev block is at a boundary */
 	int reap_counter;		/* rate limit reaping */
-	get_blocks_t *get_blocks;	/* block mapping function */
+	get_block_t *get_block;		/* block mapping function */
 	dio_iodone_t *end_io;		/* IO completion function */
 	sector_t final_block_in_bio;	/* current final block in bio + 1 */
 	sector_t next_block_for_io;	/* next block to be put under IO,
 					   in dio_blocks units */
-	struct buffer_head map_bh;	/* last get_blocks() result */
+	struct buffer_head map_bh;	/* last get_block() result */
 
 	/*
 	 * Deferred addition of a page to the dio.  These variables are
@@ -211,9 +211,9 @@
 
 /*
  * Called when all DIO BIO I/O has been completed - let the filesystem
- * know, if it registered an interest earlier via get_blocks.  Pass the
+ * know, if it registered an interest earlier via get_block.  Pass the
  * private field of the map buffer_head so that filesystems can use it
- * to hold additional state between get_blocks calls and dio_complete.
+ * to hold additional state between get_block calls and dio_complete.
  */
 static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes)
 {
@@ -493,7 +493,7 @@
  * The fs is allowed to map lots of blocks at once.  If it wants to do that,
  * it uses the passed inode-relative block number as the file offset, as usual.
  *
- * get_blocks() is passed the number of i_blkbits-sized blocks which direct_io
+ * get_block() is passed the number of i_blkbits-sized blocks which direct_io
  * has remaining to do.  The fs should not map more than this number of blocks.
  *
  * If the fs has mapped a lot of blocks, it should populate bh->b_size to
@@ -506,7 +506,7 @@
  * In the case of filesystem holes: the fs may return an arbitrarily-large
  * hole by returning an appropriate value in b_size and by clearing
  * buffer_mapped().  However the direct-io code will only process holes one
- * block at a time - it will repeatedly call get_blocks() as it walks the hole.
+ * block at a time - it will repeatedly call get_block() as it walks the hole.
  */
 static int get_more_blocks(struct dio *dio)
 {
@@ -524,8 +524,6 @@
 	 */
 	ret = dio->page_errors;
 	if (ret == 0) {
-		map_bh->b_state = 0;
-		map_bh->b_size = 0;
 		BUG_ON(dio->block_in_file >= dio->final_block_in_request);
 		fs_startblk = dio->block_in_file >> dio->blkfactor;
 		dio_count = dio->final_block_in_request - dio->block_in_file;
@@ -534,6 +532,9 @@
 		if (dio_count & blkmask)	
 			fs_count++;
 
+		map_bh->b_state = 0;
+		map_bh->b_size = fs_count << dio->inode->i_blkbits;
+
 		create = dio->rw == WRITE;
 		if (dio->lock_type == DIO_LOCKING) {
 			if (dio->block_in_file < (i_size_read(dio->inode) >>
@@ -542,13 +543,14 @@
 		} else if (dio->lock_type == DIO_NO_LOCKING) {
 			create = 0;
 		}
+
 		/*
 		 * For writes inside i_size we forbid block creations: only
 		 * overwrites are permitted.  We fall back to buffered writes
 		 * at a higher level for inside-i_size block-instantiating
 		 * writes.
 		 */
-		ret = (*dio->get_blocks)(dio->inode, fs_startblk, fs_count,
+		ret = (*dio->get_block)(dio->inode, fs_startblk,
 						map_bh, create);
 	}
 	return ret;
@@ -783,11 +785,11 @@
  * happily perform page-sized but 512-byte aligned IOs.  It is important that
  * blockdev IO be able to have fine alignment and large sizes.
  *
- * So what we do is to permit the ->get_blocks function to populate bh.b_size
+ * So what we do is to permit the ->get_block function to populate bh.b_size
  * with the size of IO which is permitted at this offset and this i_blkbits.
  *
  * For best results, the blockdev should be set up with 512-byte i_blkbits and
- * it should set b_size to PAGE_SIZE or more inside get_blocks().  This gives
+ * it should set b_size to PAGE_SIZE or more inside get_block().  This gives
  * fine alignment but still allows this function to work in PAGE_SIZE units.
  */
 static int do_direct_IO(struct dio *dio)
@@ -947,7 +949,7 @@
 static ssize_t
 direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, 
 	const struct iovec *iov, loff_t offset, unsigned long nr_segs, 
-	unsigned blkbits, get_blocks_t get_blocks, dio_iodone_t end_io,
+	unsigned blkbits, get_block_t get_block, dio_iodone_t end_io,
 	struct dio *dio)
 {
 	unsigned long user_addr; 
@@ -969,7 +971,7 @@
 
 	dio->boundary = 0;
 	dio->reap_counter = 0;
-	dio->get_blocks = get_blocks;
+	dio->get_block = get_block;
 	dio->end_io = end_io;
 	dio->map_bh.b_private = NULL;
 	dio->final_block_in_bio = -1;
@@ -1177,7 +1179,7 @@
 ssize_t
 __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
 	struct block_device *bdev, const struct iovec *iov, loff_t offset, 
-	unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io,
+	unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
 	int dio_lock_type)
 {
 	int seg;
@@ -1273,7 +1275,7 @@
 		(end > i_size_read(inode)));
 
 	retval = direct_io_worker(rw, iocb, inode, iov, offset,
-				nr_segs, blkbits, get_blocks, end_io, dio);
+				nr_segs, blkbits, get_block, end_io, dio);
 
 	if (rw == READ && dio_lock_type == DIO_LOCKING)
 		release_i_mutex = 0;
diff --git a/fs/dnotify.c b/fs/dnotify.c
index f3b540d..f932591 100644
--- a/fs/dnotify.c
+++ b/fs/dnotify.c
@@ -21,9 +21,9 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 
-int dir_notify_enable = 1;
+int dir_notify_enable __read_mostly = 1;
 
-static kmem_cache_t *dn_cache;
+static kmem_cache_t *dn_cache __read_mostly;
 
 static void redo_inode_mask(struct inode *inode)
 {
diff --git a/fs/efs/dir.c b/fs/efs/dir.c
index 777c614..17f5b2d 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -10,7 +10,7 @@
 
 static int efs_readdir(struct file *, void *, filldir_t);
 
-struct file_operations efs_dir_operations = {
+const struct file_operations efs_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= efs_readdir,
 };
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index a0f682c..242fe1a 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -281,16 +281,16 @@
 static struct poll_safewake psw;
 
 /* Slab cache used to allocate "struct epitem" */
-static kmem_cache_t *epi_cache;
+static kmem_cache_t *epi_cache __read_mostly;
 
 /* Slab cache used to allocate "struct eppoll_entry" */
-static kmem_cache_t *pwq_cache;
+static kmem_cache_t *pwq_cache __read_mostly;
 
 /* Virtual fs used to allocate inodes for eventpoll files */
-static struct vfsmount *eventpoll_mnt;
+static struct vfsmount *eventpoll_mnt __read_mostly;
 
 /* File callbacks that implement the eventpoll file behaviour */
-static struct file_operations eventpoll_fops = {
+static const struct file_operations eventpoll_fops = {
 	.release	= ep_eventpoll_close,
 	.poll		= ep_eventpoll_poll
 };
diff --git a/fs/exec.c b/fs/exec.c
index 995cba3..950ebd4 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -616,6 +616,15 @@
 		kmem_cache_free(sighand_cachep, newsighand);
 		return -EAGAIN;
 	}
+
+	/*
+	 * child_reaper ignores SIGKILL, change it now.
+	 * Reparenting needs write_lock on tasklist_lock,
+	 * so it is safe to do it under read_lock.
+	 */
+	if (unlikely(current->group_leader == child_reaper))
+		child_reaper = current;
+
 	zap_other_threads(current);
 	read_unlock(&tasklist_lock);
 
@@ -632,7 +641,7 @@
 		 * synchronize with any firing (by calling del_timer_sync)
 		 * before we can safely let the old group leader die.
 		 */
-		sig->real_timer.data = current;
+		sig->tsk = current;
 		spin_unlock_irq(lock);
 		if (hrtimer_cancel(&sig->real_timer))
 			hrtimer_restart(&sig->real_timer);
@@ -699,22 +708,30 @@
 		remove_parent(current);
 		remove_parent(leader);
 
-		switch_exec_pids(leader, current);
+
+		/* Become a process group leader with the old leader's pid.
+		 * Note: The old leader also uses thispid until release_task
+		 *       is called.  Odd but simple and correct.
+		 */
+		detach_pid(current, PIDTYPE_PID);
+		current->pid = leader->pid;
+		attach_pid(current, PIDTYPE_PID,  current->pid);
+		attach_pid(current, PIDTYPE_PGID, current->signal->pgrp);
+		attach_pid(current, PIDTYPE_SID,  current->signal->session);
+		list_add_tail(&current->tasks, &init_task.tasks);
 
 		current->parent = current->real_parent = leader->real_parent;
 		leader->parent = leader->real_parent = child_reaper;
 		current->group_leader = current;
 		leader->group_leader = leader;
 
-		add_parent(current, current->parent);
-		add_parent(leader, leader->parent);
+		add_parent(current);
+		add_parent(leader);
 		if (ptrace) {
 			current->ptrace = ptrace;
 			__ptrace_link(current, parent);
 		}
 
-		list_del(&current->tasks);
-		list_add_tail(&current->tasks, &init_task.tasks);
 		current->exit_signal = SIGCHLD;
 
 		BUG_ON(leader->exit_state != EXIT_ZOMBIE);
@@ -751,7 +768,6 @@
 		/*
 		 * Move our state over to newsighand and switch it in.
 		 */
-		spin_lock_init(&newsighand->siglock);
 		atomic_set(&newsighand->count, 1);
 		memcpy(newsighand->action, oldsighand->action,
 		       sizeof(newsighand->action));
@@ -768,7 +784,7 @@
 		write_unlock_irq(&tasklist_lock);
 
 		if (atomic_dec_and_test(&oldsighand->count))
-			sighand_free(oldsighand);
+			kmem_cache_free(sighand_cachep, oldsighand);
 	}
 
 	BUG_ON(!thread_group_leader(current));
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index b3dbd71..d672aa9 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -416,8 +416,7 @@
 
 	lock_page(page);
 	err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
-	if (err)
-		BUG();
+	BUG_ON(err);
 	de->inode = cpu_to_le32(inode->i_ino);
 	ext2_set_de_type (de, inode);
 	err = ext2_commit_chunk(page, from, to);
@@ -554,8 +553,7 @@
 		from = (char*)pde - (char*)page_address(page);
 	lock_page(page);
 	err = mapping->a_ops->prepare_write(NULL, page, from, to);
-	if (err)
-		BUG();
+	BUG_ON(err);
 	if (pde)
 		pde->rec_len = cpu_to_le16(to-from);
 	dir->inode = 0;
@@ -660,7 +658,7 @@
 	return 0;
 }
 
-struct file_operations ext2_dir_operations = {
+const struct file_operations ext2_dir_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_read_dir,
 	.readdir	= ext2_readdir,
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 11035ac..9f74a62 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -154,12 +154,12 @@
  */
 
 /* dir.c */
-extern struct file_operations ext2_dir_operations;
+extern const struct file_operations ext2_dir_operations;
 
 /* file.c */
 extern struct inode_operations ext2_file_inode_operations;
-extern struct file_operations ext2_file_operations;
-extern struct file_operations ext2_xip_file_operations;
+extern const struct file_operations ext2_file_operations;
+extern const struct file_operations ext2_xip_file_operations;
 
 /* inode.c */
 extern struct address_space_operations ext2_aops;
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index a484412..23e2c7c 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -39,7 +39,7 @@
  * We have mostly NULL's here: the current defaults are ok for
  * the ext2 filesystem.
  */
-struct file_operations ext2_file_operations = {
+const struct file_operations ext2_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
 	.write		= generic_file_write,
@@ -53,10 +53,12 @@
 	.readv		= generic_file_readv,
 	.writev		= generic_file_writev,
 	.sendfile	= generic_file_sendfile,
+	.splice_read	= generic_file_splice_read,
+	.splice_write	= generic_file_splice_write,
 };
 
 #ifdef CONFIG_EXT2_FS_XIP
-struct file_operations ext2_xip_file_operations = {
+const struct file_operations ext2_xip_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= xip_file_read,
 	.write		= xip_file_write,
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index a717837..04af9c4 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -667,18 +667,6 @@
 	return generic_block_bmap(mapping,block,ext2_get_block);
 }
 
-static int
-ext2_get_blocks(struct inode *inode, sector_t iblock, unsigned long max_blocks,
-			struct buffer_head *bh_result, int create)
-{
-	int ret;
-
-	ret = ext2_get_block(inode, iblock, bh_result, create);
-	if (ret == 0)
-		bh_result->b_size = (1 << inode->i_blkbits);
-	return ret;
-}
-
 static ssize_t
 ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
 			loff_t offset, unsigned long nr_segs)
@@ -687,7 +675,7 @@
 	struct inode *inode = file->f_mapping->host;
 
 	return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
-				offset, nr_segs, ext2_get_blocks, NULL);
+				offset, nr_segs, ext2_get_block, NULL);
 }
 
 static int
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 46623f7..77927d6 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -653,9 +653,11 @@
  */
 static int
 ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group,
-	struct buffer_head *bitmap_bh, int goal, struct ext3_reserve_window *my_rsv)
+			struct buffer_head *bitmap_bh, int goal,
+			unsigned long *count, struct ext3_reserve_window *my_rsv)
 {
 	int group_first_block, start, end;
+	unsigned long num = 0;
 
 	/* we do allocation within the reservation window if we have a window */
 	if (my_rsv) {
@@ -713,8 +715,18 @@
 			goto fail_access;
 		goto repeat;
 	}
-	return goal;
+	num++;
+	goal++;
+	while (num < *count && goal < end
+		&& ext3_test_allocatable(goal, bitmap_bh)
+		&& claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) {
+		num++;
+		goal++;
+	}
+	*count = num;
+	return goal - num;
 fail_access:
+	*count = num;
 	return -1;
 }
 
@@ -999,6 +1011,31 @@
 	goto retry;
 }
 
+static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv,
+			struct super_block *sb, int size)
+{
+	struct ext3_reserve_window_node *next_rsv;
+	struct rb_node *next;
+	spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock;
+
+	if (!spin_trylock(rsv_lock))
+		return;
+
+	next = rb_next(&my_rsv->rsv_node);
+
+	if (!next)
+		my_rsv->rsv_end += size;
+	else {
+		next_rsv = list_entry(next, struct ext3_reserve_window_node, rsv_node);
+
+		if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size)
+			my_rsv->rsv_end += size;
+		else
+			my_rsv->rsv_end = next_rsv->rsv_start - 1;
+	}
+	spin_unlock(rsv_lock);
+}
+
 /*
  * This is the main function used to allocate a new block and its reservation
  * window.
@@ -1024,11 +1061,12 @@
 ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
 			unsigned int group, struct buffer_head *bitmap_bh,
 			int goal, struct ext3_reserve_window_node * my_rsv,
-			int *errp)
+			unsigned long *count, int *errp)
 {
 	unsigned long group_first_block;
 	int ret = 0;
 	int fatal;
+	unsigned long num = *count;
 
 	*errp = 0;
 
@@ -1051,7 +1089,8 @@
 	 * or last attempt to allocate a block with reservation turned on failed
 	 */
 	if (my_rsv == NULL ) {
-		ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, NULL);
+		ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh,
+						goal, count, NULL);
 		goto out;
 	}
 	/*
@@ -1081,6 +1120,8 @@
 	while (1) {
 		if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) ||
 			!goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) {
+			if (my_rsv->rsv_goal_size < *count)
+				my_rsv->rsv_goal_size = *count;
 			ret = alloc_new_reservation(my_rsv, goal, sb,
 							group, bitmap_bh);
 			if (ret < 0)
@@ -1088,16 +1129,21 @@
 
 			if (!goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb))
 				goal = -1;
-		}
+		} else if (goal > 0 && (my_rsv->rsv_end-goal+1) < *count)
+			try_to_extend_reservation(my_rsv, sb,
+					*count-my_rsv->rsv_end + goal - 1);
+
 		if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb))
 		    || (my_rsv->rsv_end < group_first_block))
 			BUG();
 		ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal,
-					   &my_rsv->rsv_window);
+					   &num, &my_rsv->rsv_window);
 		if (ret >= 0) {
-			my_rsv->rsv_alloc_hit++;
+			my_rsv->rsv_alloc_hit += num;
+			*count = num;
 			break;				/* succeed */
 		}
+		num = *count;
 	}
 out:
 	if (ret >= 0) {
@@ -1154,8 +1200,8 @@
  * bitmap, and then for any free bit if that fails.
  * This function also updates quota and i_blocks field.
  */
-int ext3_new_block(handle_t *handle, struct inode *inode,
-			unsigned long goal, int *errp)
+int ext3_new_blocks(handle_t *handle, struct inode *inode,
+			unsigned long goal, unsigned long *count, int *errp)
 {
 	struct buffer_head *bitmap_bh = NULL;
 	struct buffer_head *gdp_bh;
@@ -1178,6 +1224,7 @@
 	static int goal_hits, goal_attempts;
 #endif
 	unsigned long ngroups;
+	unsigned long num = *count;
 
 	*errp = -ENOSPC;
 	sb = inode->i_sb;
@@ -1189,7 +1236,7 @@
 	/*
 	 * Check quota for allocation of this block.
 	 */
-	if (DQUOT_ALLOC_BLOCK(inode, 1)) {
+	if (DQUOT_ALLOC_BLOCK(inode, num)) {
 		*errp = -EDQUOT;
 		return 0;
 	}
@@ -1244,7 +1291,7 @@
 		if (!bitmap_bh)
 			goto io_error;
 		ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no,
-					bitmap_bh, ret_block, my_rsv, &fatal);
+					bitmap_bh, ret_block, my_rsv, &num, &fatal);
 		if (fatal)
 			goto out;
 		if (ret_block >= 0)
@@ -1281,7 +1328,7 @@
 		if (!bitmap_bh)
 			goto io_error;
 		ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no,
-					bitmap_bh, -1, my_rsv, &fatal);
+					bitmap_bh, -1, my_rsv, &num, &fatal);
 		if (fatal)
 			goto out;
 		if (ret_block >= 0) 
@@ -1316,13 +1363,15 @@
 	target_block = ret_block + group_no * EXT3_BLOCKS_PER_GROUP(sb)
 				+ le32_to_cpu(es->s_first_data_block);
 
-	if (target_block == le32_to_cpu(gdp->bg_block_bitmap) ||
-	    target_block == le32_to_cpu(gdp->bg_inode_bitmap) ||
+	if (in_range(le32_to_cpu(gdp->bg_block_bitmap), target_block, num) ||
+	    in_range(le32_to_cpu(gdp->bg_inode_bitmap), target_block, num) ||
 	    in_range(target_block, le32_to_cpu(gdp->bg_inode_table),
+		      EXT3_SB(sb)->s_itb_per_group) ||
+	    in_range(target_block + num - 1, le32_to_cpu(gdp->bg_inode_table),
 		      EXT3_SB(sb)->s_itb_per_group))
 		ext3_error(sb, "ext3_new_block",
 			    "Allocating block in system zone - "
-			    "block = %u", target_block);
+			    "blocks from %u, length %lu", target_block, num);
 
 	performed_allocation = 1;
 
@@ -1341,10 +1390,14 @@
 	jbd_lock_bh_state(bitmap_bh);
 	spin_lock(sb_bgl_lock(sbi, group_no));
 	if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) {
-		if (ext3_test_bit(ret_block,
-				bh2jh(bitmap_bh)->b_committed_data)) {
-			printk("%s: block was unexpectedly set in "
-				"b_committed_data\n", __FUNCTION__);
+		int i;
+
+		for (i = 0; i < num; i++) {
+			if (ext3_test_bit(ret_block,
+					bh2jh(bitmap_bh)->b_committed_data)) {
+				printk("%s: block was unexpectedly set in "
+					"b_committed_data\n", __FUNCTION__);
+			}
 		}
 	}
 	ext3_debug("found bit %d\n", ret_block);
@@ -1355,7 +1408,7 @@
 	/* ret_block was blockgroup-relative.  Now it becomes fs-relative */
 	ret_block = target_block;
 
-	if (ret_block >= le32_to_cpu(es->s_blocks_count)) {
+	if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) {
 		ext3_error(sb, "ext3_new_block",
 			    "block(%d) >= blocks count(%d) - "
 			    "block_group = %d, es == %p ", ret_block,
@@ -1373,9 +1426,9 @@
 
 	spin_lock(sb_bgl_lock(sbi, group_no));
 	gdp->bg_free_blocks_count =
-			cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1);
+			cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - num);
 	spin_unlock(sb_bgl_lock(sbi, group_no));
-	percpu_counter_mod(&sbi->s_freeblocks_counter, -1);
+	percpu_counter_mod(&sbi->s_freeblocks_counter, -num);
 
 	BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor");
 	err = ext3_journal_dirty_metadata(handle, gdp_bh);
@@ -1388,6 +1441,8 @@
 
 	*errp = 0;
 	brelse(bitmap_bh);
+	DQUOT_FREE_BLOCK(inode, *count-num);
+	*count = num;
 	return ret_block;
 
 io_error:
@@ -1401,11 +1456,19 @@
 	 * Undo the block allocation
 	 */
 	if (!performed_allocation)
-		DQUOT_FREE_BLOCK(inode, 1);
+		DQUOT_FREE_BLOCK(inode, *count);
 	brelse(bitmap_bh);
 	return 0;
 }
 
+int ext3_new_block(handle_t *handle, struct inode *inode,
+			unsigned long goal, int *errp)
+{
+	unsigned long count = 1;
+
+	return ext3_new_blocks(handle, inode, goal, &count, errp);
+}
+
 unsigned long ext3_count_free_blocks(struct super_block *sb)
 {
 	unsigned long desc_count;
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index 7734591..f37528e 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -39,7 +39,7 @@
 static int ext3_release_dir (struct inode * inode,
 				struct file * filp);
 
-struct file_operations ext3_dir_operations = {
+const struct file_operations ext3_dir_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_read_dir,
 	.readdir	= ext3_readdir,		/* we take BKL. needed?*/
@@ -131,8 +131,9 @@
 		struct buffer_head *bh = NULL;
 
 		map_bh.b_state = 0;
-		err = ext3_get_block_handle(NULL, inode, blk, &map_bh, 0, 0);
-		if (!err) {
+		err = ext3_get_blocks_handle(NULL, inode, blk, 1,
+						&map_bh, 0, 0);
+		if (err > 0) {
 			page_cache_readahead(sb->s_bdev->bd_inode->i_mapping,
 				&filp->f_ra,
 				filp,
diff --git a/fs/ext3/file.c b/fs/ext3/file.c
index 59098ea..1efefb6 100644
--- a/fs/ext3/file.c
+++ b/fs/ext3/file.c
@@ -105,7 +105,7 @@
 	return ret;
 }
 
-struct file_operations ext3_file_operations = {
+const struct file_operations ext3_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= do_sync_read,
 	.write		= do_sync_write,
@@ -119,6 +119,8 @@
 	.release	= ext3_release_file,
 	.fsync		= ext3_sync_file,
 	.sendfile	= generic_file_sendfile,
+	.splice_read	= generic_file_splice_read,
+	.splice_write	= generic_file_splice_write,
 };
 
 struct inode_operations ext3_file_inode_operations = {
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 2c36137..48ae033 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -44,16 +44,16 @@
 /*
  * Test whether an inode is a fast symlink.
  */
-static inline int ext3_inode_is_fast_symlink(struct inode *inode)
+static int ext3_inode_is_fast_symlink(struct inode *inode)
 {
 	int ea_blocks = EXT3_I(inode)->i_file_acl ?
 		(inode->i_sb->s_blocksize >> 9) : 0;
 
-	return (S_ISLNK(inode->i_mode) &&
-		inode->i_blocks - ea_blocks == 0);
+	return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0);
 }
 
-/* The ext3 forget function must perform a revoke if we are freeing data
+/*
+ * The ext3 forget function must perform a revoke if we are freeing data
  * which has been journaled.  Metadata (eg. indirect blocks) must be
  * revoked in all cases. 
  *
@@ -61,10 +61,8 @@
  * but there may still be a record of it in the journal, and that record
  * still needs to be revoked.
  */
-
-int ext3_forget(handle_t *handle, int is_metadata,
-		       struct inode *inode, struct buffer_head *bh,
-		       int blocknr)
+int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode,
+			struct buffer_head *bh, int blocknr)
 {
 	int err;
 
@@ -104,10 +102,9 @@
 }
 
 /*
- * Work out how many blocks we need to progress with the next chunk of a
+ * Work out how many blocks we need to proceed with the next chunk of a
  * truncate transaction.
  */
-
 static unsigned long blocks_for_truncate(struct inode *inode) 
 {
 	unsigned long needed;
@@ -141,7 +138,6 @@
  * extend fails, we need to propagate the failure up and restart the
  * transaction in the top-level truncate loop. --sct 
  */
-
 static handle_t *start_transaction(struct inode *inode) 
 {
 	handle_t *result;
@@ -194,9 +190,11 @@
 
 	handle = start_transaction(inode);
 	if (IS_ERR(handle)) {
-		/* If we're going to skip the normal cleanup, we still
-		 * need to make sure that the in-core orphan linked list
-		 * is properly cleaned up. */
+		/*
+		 * If we're going to skip the normal cleanup, we still need to
+		 * make sure that the in-core orphan linked list is properly
+		 * cleaned up.
+		 */
 		ext3_orphan_del(NULL, inode);
 		goto no_delete;
 	}
@@ -235,16 +233,6 @@
 	clear_inode(inode);	/* We must guarantee clearing of inode... */
 }
 
-static int ext3_alloc_block (handle_t *handle,
-			struct inode * inode, unsigned long goal, int *err)
-{
-	unsigned long result;
-
-	result = ext3_new_block(handle, inode, goal, err);
-	return result;
-}
-
-
 typedef struct {
 	__le32	*p;
 	__le32	key;
@@ -257,7 +245,7 @@
 	p->bh = bh;
 }
 
-static inline int verify_chain(Indirect *from, Indirect *to)
+static int verify_chain(Indirect *from, Indirect *to)
 {
 	while (from <= to && from->key == *from->p)
 		from++;
@@ -327,10 +315,10 @@
 		offsets[n++] = i_block & (ptrs - 1);
 		final = ptrs;
 	} else {
-		ext3_warning (inode->i_sb, "ext3_block_to_path", "block > big");
+		ext3_warning(inode->i_sb, "ext3_block_to_path", "block > big");
 	}
 	if (boundary)
-		*boundary = (i_block & (ptrs - 1)) == (final - 1);
+		*boundary = final - 1 - (i_block & (ptrs - 1));
 	return n;
 }
 
@@ -419,7 +407,6 @@
  *
  *	Caller must make sure that @ind is valid and will stay that way.
  */
-
 static unsigned long ext3_find_near(struct inode *inode, Indirect *ind)
 {
 	struct ext3_inode_info *ei = EXT3_I(inode);
@@ -429,17 +416,18 @@
 	unsigned long colour;
 
 	/* Try to find previous block */
-	for (p = ind->p - 1; p >= start; p--)
+	for (p = ind->p - 1; p >= start; p--) {
 		if (*p)
 			return le32_to_cpu(*p);
+	}
 
 	/* No such thing, so let's try location of indirect block */
 	if (ind->bh)
 		return ind->bh->b_blocknr;
 
 	/*
-	 * It is going to be refered from inode itself? OK, just put it into
-	 * the same cylinder group then.
+	 * It is going to be referred to from the inode itself? OK, just put it
+	 * into the same cylinder group then.
 	 */
 	bg_start = (ei->i_block_group * EXT3_BLOCKS_PER_GROUP(inode->i_sb)) +
 		le32_to_cpu(EXT3_SB(inode->i_sb)->s_es->s_first_data_block);
@@ -463,7 +451,9 @@
 static unsigned long ext3_find_goal(struct inode *inode, long block,
 		Indirect chain[4], Indirect *partial)
 {
-	struct ext3_block_alloc_info *block_i =  EXT3_I(inode)->i_block_alloc_info;
+	struct ext3_block_alloc_info *block_i;
+
+	block_i =  EXT3_I(inode)->i_block_alloc_info;
 
 	/*
 	 * try the heuristic for sequential allocation,
@@ -478,13 +468,113 @@
 }
 
 /**
+ *	ext3_blks_to_allocate: Look up the block map and count the number
+ *	of direct blocks need to be allocated for the given branch.
+ *
+ * 	@branch: chain of indirect blocks
+ *	@k: number of blocks need for indirect blocks
+ *	@blks: number of data blocks to be mapped.
+ *	@blocks_to_boundary:  the offset in the indirect block
+ *
+ *	return the total number of blocks to be allocate, including the
+ *	direct and indirect blocks.
+ */
+static int ext3_blks_to_allocate(Indirect *branch, int k, unsigned long blks,
+		int blocks_to_boundary)
+{
+	unsigned long count = 0;
+
+	/*
+	 * Simple case, [t,d]Indirect block(s) has not allocated yet
+	 * then it's clear blocks on that path have not allocated
+	 */
+	if (k > 0) {
+		/* right now we don't handle cross boundary allocation */
+		if (blks < blocks_to_boundary + 1)
+			count += blks;
+		else
+			count += blocks_to_boundary + 1;
+		return count;
+	}
+
+	count++;
+	while (count < blks && count <= blocks_to_boundary &&
+		le32_to_cpu(*(branch[0].p + count)) == 0) {
+		count++;
+	}
+	return count;
+}
+
+/**
+ *	ext3_alloc_blocks: multiple allocate blocks needed for a branch
+ *	@indirect_blks: the number of blocks need to allocate for indirect
+ *			blocks
+ *
+ *	@new_blocks: on return it will store the new block numbers for
+ *	the indirect blocks(if needed) and the first direct block,
+ *	@blks:	on return it will store the total number of allocated
+ *		direct blocks
+ */
+static int ext3_alloc_blocks(handle_t *handle, struct inode *inode,
+			unsigned long goal, int indirect_blks, int blks,
+			unsigned long long new_blocks[4], int *err)
+{
+	int target, i;
+	unsigned long count = 0;
+	int index = 0;
+	unsigned long current_block = 0;
+	int ret = 0;
+
+	/*
+	 * Here we try to allocate the requested multiple blocks at once,
+	 * on a best-effort basis.
+	 * To build a branch, we should allocate blocks for
+	 * the indirect blocks(if not allocated yet), and at least
+	 * the first direct block of this branch.  That's the
+	 * minimum number of blocks need to allocate(required)
+	 */
+	target = blks + indirect_blks;
+
+	while (1) {
+		count = target;
+		/* allocating blocks for indirect blocks and direct blocks */
+		current_block = ext3_new_blocks(handle,inode,goal,&count,err);
+		if (*err)
+			goto failed_out;
+
+		target -= count;
+		/* allocate blocks for indirect blocks */
+		while (index < indirect_blks && count) {
+			new_blocks[index++] = current_block++;
+			count--;
+		}
+
+		if (count > 0)
+			break;
+	}
+
+	/* save the new block number for the first direct block */
+	new_blocks[index] = current_block;
+
+	/* total number of blocks allocated for direct blocks */
+	ret = count;
+	*err = 0;
+	return ret;
+failed_out:
+	for (i = 0; i <index; i++)
+		ext3_free_blocks(handle, inode, new_blocks[i], 1);
+	return ret;
+}
+
+/**
  *	ext3_alloc_branch - allocate and set up a chain of blocks.
  *	@inode: owner
- *	@num: depth of the chain (number of blocks to allocate)
+ *	@indirect_blks: number of allocated indirect blocks
+ *	@blks: number of allocated direct blocks
  *	@offsets: offsets (in the blocks) to store the pointers to next.
  *	@branch: place to store the chain in.
  *
- *	This function allocates @num blocks, zeroes out all but the last one,
+ *	This function allocates blocks, zeroes out all but the last one,
  *	links them into chain and (if we are synchronous) writes them to disk.
  *	In other words, it prepares a branch that can be spliced onto the
  *	inode. It stores the information about that chain in the branch[], in
@@ -501,97 +591,106 @@
  *	ext3_alloc_block() (normally -ENOSPC). Otherwise we set the chain
  *	as described above and return 0.
  */
-
 static int ext3_alloc_branch(handle_t *handle, struct inode *inode,
-			     int num,
-			     unsigned long goal,
-			     int *offsets,
-			     Indirect *branch)
+			int indirect_blks, int *blks, unsigned long goal,
+			int *offsets, Indirect *branch)
 {
 	int blocksize = inode->i_sb->s_blocksize;
-	int n = 0, keys = 0;
+	int i, n = 0;
 	int err = 0;
-	int i;
-	int parent = ext3_alloc_block(handle, inode, goal, &err);
+	struct buffer_head *bh;
+	int num;
+	unsigned long long new_blocks[4];
+	unsigned long long current_block;
 
-	branch[0].key = cpu_to_le32(parent);
-	if (parent) {
-		for (n = 1; n < num; n++) {
-			struct buffer_head *bh;
-			/* Allocate the next block */
-			int nr = ext3_alloc_block(handle, inode, parent, &err);
-			if (!nr)
-				break;
-			branch[n].key = cpu_to_le32(nr);
+	num = ext3_alloc_blocks(handle, inode, goal, indirect_blks,
+				*blks, new_blocks, &err);
+	if (err)
+		return err;
 
-			/*
-			 * Get buffer_head for parent block, zero it out
-			 * and set the pointer to new one, then send
-			 * parent to disk.  
-			 */
-			bh = sb_getblk(inode->i_sb, parent);
-			if (!bh)
-				break;
-			keys = n+1;
-			branch[n].bh = bh;
-			lock_buffer(bh);
-			BUFFER_TRACE(bh, "call get_create_access");
-			err = ext3_journal_get_create_access(handle, bh);
-			if (err) {
-				unlock_buffer(bh);
-				brelse(bh);
-				break;
-			}
-
-			memset(bh->b_data, 0, blocksize);
-			branch[n].p = (__le32*) bh->b_data + offsets[n];
-			*branch[n].p = branch[n].key;
-			BUFFER_TRACE(bh, "marking uptodate");
-			set_buffer_uptodate(bh);
+	branch[0].key = cpu_to_le32(new_blocks[0]);
+	/*
+	 * metadata blocks and data blocks are allocated.
+	 */
+	for (n = 1; n <= indirect_blks;  n++) {
+		/*
+		 * Get buffer_head for parent block, zero it out
+		 * and set the pointer to new one, then send
+		 * parent to disk.
+		 */
+		bh = sb_getblk(inode->i_sb, new_blocks[n-1]);
+		branch[n].bh = bh;
+		lock_buffer(bh);
+		BUFFER_TRACE(bh, "call get_create_access");
+		err = ext3_journal_get_create_access(handle, bh);
+		if (err) {
 			unlock_buffer(bh);
-
-			BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
-			err = ext3_journal_dirty_metadata(handle, bh);
-			if (err)
-				break;
-
-			parent = nr;
+			brelse(bh);
+			goto failed;
 		}
-	}
-	if (n == num)
-		return 0;
 
+		memset(bh->b_data, 0, blocksize);
+		branch[n].p = (__le32 *) bh->b_data + offsets[n];
+		branch[n].key = cpu_to_le32(new_blocks[n]);
+		*branch[n].p = branch[n].key;
+		if ( n == indirect_blks) {
+			current_block = new_blocks[n];
+			/*
+			 * End of chain, update the last new metablock of
+			 * the chain to point to the new allocated
+			 * data blocks numbers
+			 */
+			for (i=1; i < num; i++)
+				*(branch[n].p + i) = cpu_to_le32(++current_block);
+		}
+		BUFFER_TRACE(bh, "marking uptodate");
+		set_buffer_uptodate(bh);
+		unlock_buffer(bh);
+
+		BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
+		err = ext3_journal_dirty_metadata(handle, bh);
+		if (err)
+			goto failed;
+	}
+	*blks = num;
+	return err;
+failed:
 	/* Allocation failed, free what we already allocated */
-	for (i = 1; i < keys; i++) {
+	for (i = 1; i <= n ; i++) {
 		BUFFER_TRACE(branch[i].bh, "call journal_forget");
 		ext3_journal_forget(handle, branch[i].bh);
 	}
-	for (i = 0; i < keys; i++)
-		ext3_free_blocks(handle, inode, le32_to_cpu(branch[i].key), 1);
+	for (i = 0; i <indirect_blks; i++)
+		ext3_free_blocks(handle, inode, new_blocks[i], 1);
+
+	ext3_free_blocks(handle, inode, new_blocks[i], num);
+
 	return err;
 }
 
 /**
- *	ext3_splice_branch - splice the allocated branch onto inode.
- *	@inode: owner
- *	@block: (logical) number of block we are adding
- *	@chain: chain of indirect blocks (with a missing link - see
- *		ext3_alloc_branch)
- *	@where: location of missing link
- *	@num:   number of blocks we are adding
+ * ext3_splice_branch - splice the allocated branch onto inode.
+ * @inode: owner
+ * @block: (logical) number of block we are adding
+ * @chain: chain of indirect blocks (with a missing link - see
+ *	ext3_alloc_branch)
+ * @where: location of missing link
+ * @num:   number of indirect blocks we are adding
+ * @blks:  number of direct blocks we are adding
  *
- *	This function fills the missing link and does all housekeeping needed in
- *	inode (->i_blocks, etc.). In case of success we end up with the full
- *	chain to new block and return 0.
+ * This function fills the missing link and does all housekeeping needed in
+ * inode (->i_blocks, etc.). In case of success we end up with the full
+ * chain to new block and return 0.
  */
-
-static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block,
-			      Indirect chain[4], Indirect *where, int num)
+static int ext3_splice_branch(handle_t *handle, struct inode *inode,
+			long block, Indirect *where, int num, int blks)
 {
 	int i;
 	int err = 0;
-	struct ext3_block_alloc_info *block_i = EXT3_I(inode)->i_block_alloc_info;
+	struct ext3_block_alloc_info *block_i;
+	unsigned long current_block;
 
+	block_i = EXT3_I(inode)->i_block_alloc_info;
 	/*
 	 * If we're splicing into a [td]indirect block (as opposed to the
 	 * inode) then we need to get write access to the [td]indirect block
@@ -608,13 +707,24 @@
 	*where->p = where->key;
 
 	/*
+	 * Update the host buffer_head or inode to point to more just allocated
+	 * direct blocks blocks
+	 */
+	if (num == 0 && blks > 1) {
+		current_block = le32_to_cpu(where->key + 1);
+		for (i = 1; i < blks; i++)
+			*(where->p + i ) = cpu_to_le32(current_block++);
+	}
+
+	/*
 	 * update the most recently allocated logical & physical block
 	 * in i_block_alloc_info, to assist find the proper goal block for next
 	 * allocation
 	 */
 	if (block_i) {
-		block_i->last_alloc_logical_block = block;
-		block_i->last_alloc_physical_block = le32_to_cpu(where[num-1].key);
+		block_i->last_alloc_logical_block = block + blks - 1;
+		block_i->last_alloc_physical_block =
+				le32_to_cpu(where[num].key + blks - 1);
 	}
 
 	/* We are done with atomic stuff, now do the rest of housekeeping */
@@ -625,7 +735,7 @@
 	/* had we spliced it onto indirect block? */
 	if (where->bh) {
 		/*
-		 * akpm: If we spliced it onto an indirect block, we haven't
+		 * If we spliced it onto an indirect block, we haven't
 		 * altered the inode.  Note however that if it is being spliced
 		 * onto an indirect block at the very end of the file (the
 		 * file is growing) then we *will* alter the inode to reflect
@@ -647,10 +757,13 @@
 	return err;
 
 err_out:
-	for (i = 1; i < num; i++) {
+	for (i = 1; i <= num; i++) {
 		BUFFER_TRACE(where[i].bh, "call journal_forget");
 		ext3_journal_forget(handle, where[i].bh);
+		ext3_free_blocks(handle,inode,le32_to_cpu(where[i-1].key),1);
 	}
+	ext3_free_blocks(handle, inode, le32_to_cpu(where[num].key), blks);
+
 	return err;
 }
 
@@ -666,26 +779,33 @@
  * allocations is needed - we simply release blocks and do not touch anything
  * reachable from inode.
  *
- * akpm: `handle' can be NULL if create == 0.
+ * `handle' can be NULL if create == 0.
  *
  * The BKL may not be held on entry here.  Be sure to take it early.
+ * return > 0, # of blocks mapped or allocated.
+ * return = 0, if plain lookup failed.
+ * return < 0, error case.
  */
-
-int
-ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock,
-		struct buffer_head *bh_result, int create, int extend_disksize)
+int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
+		sector_t iblock, unsigned long maxblocks,
+		struct buffer_head *bh_result,
+		int create, int extend_disksize)
 {
 	int err = -EIO;
 	int offsets[4];
 	Indirect chain[4];
 	Indirect *partial;
 	unsigned long goal;
-	int left;
-	int boundary = 0;
-	const int depth = ext3_block_to_path(inode, iblock, offsets, &boundary);
+	int indirect_blks;
+	int blocks_to_boundary = 0;
+	int depth;
 	struct ext3_inode_info *ei = EXT3_I(inode);
+	int count = 0;
+	unsigned long first_block = 0;
+
 
 	J_ASSERT(handle != NULL || create == 0);
+	depth = ext3_block_to_path(inode,iblock,offsets,&blocks_to_boundary);
 
 	if (depth == 0)
 		goto out;
@@ -694,8 +814,31 @@
 
 	/* Simplest case - block found, no allocation needed */
 	if (!partial) {
+		first_block = chain[depth - 1].key;
 		clear_buffer_new(bh_result);
-		goto got_it;
+		count++;
+		/*map more blocks*/
+		while (count < maxblocks && count <= blocks_to_boundary) {
+			if (!verify_chain(chain, partial)) {
+				/*
+				 * Indirect block might be removed by
+				 * truncate while we were reading it.
+				 * Handling of that case: forget what we've
+				 * got now. Flag the err as EAGAIN, so it
+				 * will reread.
+				 */
+				err = -EAGAIN;
+				count = 0;
+				break;
+			}
+			if (le32_to_cpu(*(chain[depth-1].p+count) ==
+					(first_block + count)))
+				count++;
+			else
+				break;
+		}
+		if (err != -EAGAIN)
+			goto got_it;
 	}
 
 	/* Next simple case - plain lookup or failed read of indirect block */
@@ -723,6 +866,7 @@
 		}
 		partial = ext3_get_branch(inode, depth, offsets, chain, &err);
 		if (!partial) {
+			count++;
 			mutex_unlock(&ei->truncate_mutex);
 			if (err)
 				goto cleanup;
@@ -740,12 +884,19 @@
 
 	goal = ext3_find_goal(inode, iblock, chain, partial);
 
-	left = (chain + depth) - partial;
+	/* the number of blocks need to allocate for [d,t]indirect blocks */
+	indirect_blks = (chain + depth) - partial - 1;
 
 	/*
+	 * Next look up the indirect map to count the totoal number of
+	 * direct blocks to allocate for this branch.
+	 */
+	count = ext3_blks_to_allocate(partial, indirect_blks,
+					maxblocks, blocks_to_boundary);
+	/*
 	 * Block out ext3_truncate while we alter the tree
 	 */
-	err = ext3_alloc_branch(handle, inode, left, goal,
+	err = ext3_alloc_branch(handle, inode, indirect_blks, &count, goal,
 				offsets + (partial - chain), partial);
 
 	/*
@@ -756,8 +907,8 @@
 	 * may need to return -EAGAIN upwards in the worst case.  --sct
 	 */
 	if (!err)
-		err = ext3_splice_branch(handle, inode, iblock, chain,
-					 partial, left);
+		err = ext3_splice_branch(handle, inode, iblock,
+					partial, indirect_blks, count);
 	/*
 	 * i_disksize growing is protected by truncate_mutex.  Don't forget to
 	 * protect it if you're about to implement concurrent
@@ -772,8 +923,9 @@
 	set_buffer_new(bh_result);
 got_it:
 	map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
-	if (boundary)
+	if (blocks_to_boundary == 0)
 		set_buffer_boundary(bh_result);
+	err = count;
 	/* Clean up and exit */
 	partial = chain + depth - 1;	/* the whole chain */
 cleanup:
@@ -787,34 +939,21 @@
 	return err;
 }
 
+#define DIO_CREDITS (EXT3_RESERVE_TRANS_BLOCKS + 32)
+
 static int ext3_get_block(struct inode *inode, sector_t iblock,
 			struct buffer_head *bh_result, int create)
 {
-	handle_t *handle = NULL;
-	int ret;
-
-	if (create) {
-		handle = ext3_journal_current_handle();
-		J_ASSERT(handle != 0);
-	}
-	ret = ext3_get_block_handle(handle, inode, iblock,
-				bh_result, create, 1);
-	return ret;
-}
-
-#define DIO_CREDITS (EXT3_RESERVE_TRANS_BLOCKS + 32)
-
-static int
-ext3_direct_io_get_blocks(struct inode *inode, sector_t iblock,
-		unsigned long max_blocks, struct buffer_head *bh_result,
-		int create)
-{
 	handle_t *handle = journal_current_handle();
 	int ret = 0;
+	unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
 
-	if (!handle)
+	if (!create)
 		goto get_block;		/* A read */
 
+	if (max_blocks == 1)
+		goto get_block;		/* A single block get */
+
 	if (handle->h_transaction->t_state == T_LOCKED) {
 		/*
 		 * Huge direct-io writes can hold off commits for long
@@ -841,18 +980,22 @@
 	}
 
 get_block:
-	if (ret == 0)
-		ret = ext3_get_block_handle(handle, inode, iblock,
-					bh_result, create, 0);
-	bh_result->b_size = (1 << inode->i_blkbits);
+	if (ret == 0) {
+		ret = ext3_get_blocks_handle(handle, inode, iblock,
+					max_blocks, bh_result, create, 0);
+		if (ret > 0) {
+			bh_result->b_size = (ret << inode->i_blkbits);
+			ret = 0;
+		}
+	}
 	return ret;
 }
 
 /*
  * `handle' can be NULL if create is zero
  */
-struct buffer_head *ext3_getblk(handle_t *handle, struct inode * inode,
-				long block, int create, int * errp)
+struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode,
+				long block, int create, int *errp)
 {
 	struct buffer_head dummy;
 	int fatal = 0, err;
@@ -862,8 +1005,16 @@
 	dummy.b_state = 0;
 	dummy.b_blocknr = -1000;
 	buffer_trace_init(&dummy.b_history);
-	*errp = ext3_get_block_handle(handle, inode, block, &dummy, create, 1);
-	if (!*errp && buffer_mapped(&dummy)) {
+	err = ext3_get_blocks_handle(handle, inode, block, 1,
+					&dummy, create, 1);
+	if (err == 1) {
+		err = 0;
+	} else if (err >= 0) {
+		WARN_ON(1);
+		err = -EIO;
+	}
+	*errp = err;
+	if (!err && buffer_mapped(&dummy)) {
 		struct buffer_head *bh;
 		bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
 		if (!bh) {
@@ -874,17 +1025,18 @@
 			J_ASSERT(create != 0);
 			J_ASSERT(handle != 0);
 
-			/* Now that we do not always journal data, we
-			   should keep in mind whether this should
-			   always journal the new buffer as metadata.
-			   For now, regular file writes use
-			   ext3_get_block instead, so it's not a
-			   problem. */
+			/*
+			 * Now that we do not always journal data, we should
+			 * keep in mind whether this should always journal the
+			 * new buffer as metadata.  For now, regular file
+			 * writes use ext3_get_block instead, so it's not a
+			 * problem.
+			 */
 			lock_buffer(bh);
 			BUFFER_TRACE(bh, "call get_create_access");
 			fatal = ext3_journal_get_create_access(handle, bh);
 			if (!fatal && !buffer_uptodate(bh)) {
-				memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+				memset(bh->b_data,0,inode->i_sb->s_blocksize);
 				set_buffer_uptodate(bh);
 			}
 			unlock_buffer(bh);
@@ -906,7 +1058,7 @@
 	return NULL;
 }
 
-struct buffer_head *ext3_bread(handle_t *handle, struct inode * inode,
+struct buffer_head *ext3_bread(handle_t *handle, struct inode *inode,
 			       int block, int create, int *err)
 {
 	struct buffer_head * bh;
@@ -982,9 +1134,8 @@
  * is elevated.  We'll still have enough credits for the tiny quotafile
  * write.  
  */
-
-static int do_journal_get_write_access(handle_t *handle, 
-				       struct buffer_head *bh)
+static int do_journal_get_write_access(handle_t *handle,
+					struct buffer_head *bh)
 {
 	if (!buffer_mapped(bh) || buffer_freed(bh))
 		return 0;
@@ -1025,8 +1176,7 @@
 	return ret;
 }
 
-int
-ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
+int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
 {
 	int err = journal_dirty_data(handle, bh);
 	if (err)
@@ -1051,7 +1201,6 @@
  * ext3 never places buffers on inode->i_mapping->private_list.  metadata
  * buffers are managed internally.
  */
-
 static int ext3_ordered_commit_write(struct file *file, struct page *page,
 			     unsigned from, unsigned to)
 {
@@ -1261,7 +1410,7 @@
  * we don't need to open a transaction here.
  */
 static int ext3_ordered_writepage(struct page *page,
-			struct writeback_control *wbc)
+				struct writeback_control *wbc)
 {
 	struct inode *inode = page->mapping->host;
 	struct buffer_head *page_bufs;
@@ -1430,7 +1579,7 @@
 	return mpage_readpages(mapping, pages, nr_pages, ext3_get_block);
 }
 
-static int ext3_invalidatepage(struct page *page, unsigned long offset)
+static void ext3_invalidatepage(struct page *page, unsigned long offset)
 {
 	journal_t *journal = EXT3_JOURNAL(page->mapping->host);
 
@@ -1440,7 +1589,7 @@
 	if (offset == 0)
 		ClearPageChecked(page);
 
-	return journal_invalidatepage(journal, page, offset);
+	journal_invalidatepage(journal, page, offset);
 }
 
 static int ext3_releasepage(struct page *page, gfp_t wait)
@@ -1492,11 +1641,10 @@
 
 	ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, 
 				 offset, nr_segs,
-				 ext3_direct_io_get_blocks, NULL);
+				 ext3_get_block, NULL);
 
 	/*
-	 * Reacquire the handle: ext3_direct_io_get_block() can restart the
-	 * transaction
+	 * Reacquire the handle: ext3_get_block() can restart the transaction
 	 */
 	handle = journal_current_handle();
 
@@ -1752,11 +1900,8 @@
  *		c) free the subtrees growing from the inode past the @chain[0].
  *			(no partially truncated stuff there).  */
 
-static Indirect *ext3_find_shared(struct inode *inode,
-				int depth,
-				int offsets[4],
-				Indirect chain[4],
-				__le32 *top)
+static Indirect *ext3_find_shared(struct inode *inode, int depth,
+			int offsets[4], Indirect chain[4], __le32 *top)
 {
 	Indirect *partial, *p;
 	int k, err;
@@ -1795,8 +1940,7 @@
 	}
 	/* Writer: end */
 
-	while(partial > p)
-	{
+	while(partial > p) {
 		brelse(partial->bh);
 		partial--;
 	}
@@ -1812,10 +1956,9 @@
  * We release `count' blocks on disk, but (last - first) may be greater
  * than `count' because there can be holes in there.
  */
-static void
-ext3_clear_blocks(handle_t *handle, struct inode *inode, struct buffer_head *bh,
-		unsigned long block_to_free, unsigned long count,
-		__le32 *first, __le32 *last)
+static void ext3_clear_blocks(handle_t *handle, struct inode *inode,
+		struct buffer_head *bh, unsigned long block_to_free,
+		unsigned long count, __le32 *first, __le32 *last)
 {
 	__le32 *p;
 	if (try_to_extend_transaction(handle, inode)) {
@@ -2076,8 +2219,7 @@
  * that's fine - as long as they are linked from the inode, the post-crash
  * ext3_truncate() run will find them and release them.
  */
-
-void ext3_truncate(struct inode * inode)
+void ext3_truncate(struct inode *inode)
 {
 	handle_t *handle;
 	struct ext3_inode_info *ei = EXT3_I(inode);
@@ -2201,29 +2343,26 @@
 do_indirects:
 	/* Kill the remaining (whole) subtrees */
 	switch (offsets[0]) {
-		default:
-			nr = i_data[EXT3_IND_BLOCK];
-			if (nr) {
-				ext3_free_branches(handle, inode, NULL,
-						   &nr, &nr+1, 1);
-				i_data[EXT3_IND_BLOCK] = 0;
-			}
-		case EXT3_IND_BLOCK:
-			nr = i_data[EXT3_DIND_BLOCK];
-			if (nr) {
-				ext3_free_branches(handle, inode, NULL,
-						   &nr, &nr+1, 2);
-				i_data[EXT3_DIND_BLOCK] = 0;
-			}
-		case EXT3_DIND_BLOCK:
-			nr = i_data[EXT3_TIND_BLOCK];
-			if (nr) {
-				ext3_free_branches(handle, inode, NULL,
-						   &nr, &nr+1, 3);
-				i_data[EXT3_TIND_BLOCK] = 0;
-			}
-		case EXT3_TIND_BLOCK:
-			;
+	default:
+		nr = i_data[EXT3_IND_BLOCK];
+		if (nr) {
+			ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 1);
+			i_data[EXT3_IND_BLOCK] = 0;
+		}
+	case EXT3_IND_BLOCK:
+		nr = i_data[EXT3_DIND_BLOCK];
+		if (nr) {
+			ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 2);
+			i_data[EXT3_DIND_BLOCK] = 0;
+		}
+	case EXT3_DIND_BLOCK:
+		nr = i_data[EXT3_TIND_BLOCK];
+		if (nr) {
+			ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 3);
+			i_data[EXT3_TIND_BLOCK] = 0;
+		}
+	case EXT3_TIND_BLOCK:
+		;
 	}
 
 	ext3_discard_reservation(inode);
@@ -2232,8 +2371,10 @@
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
 	ext3_mark_inode_dirty(handle, inode);
 
-	/* In a multi-transaction truncate, we only make the final
-	 * transaction synchronous */
+	/*
+	 * In a multi-transaction truncate, we only make the final transaction
+	 * synchronous
+	 */
 	if (IS_SYNC(inode))
 		handle->h_sync = 1;
 out_stop:
@@ -2259,20 +2400,16 @@
 	struct ext3_group_desc * gdp;
 
 
-	if ((ino != EXT3_ROOT_INO &&
-		ino != EXT3_JOURNAL_INO &&
-		ino != EXT3_RESIZE_INO &&
-		ino < EXT3_FIRST_INO(sb)) ||
-		ino > le32_to_cpu(
-			EXT3_SB(sb)->s_es->s_inodes_count)) {
-		ext3_error (sb, "ext3_get_inode_block",
+	if ((ino != EXT3_ROOT_INO && ino != EXT3_JOURNAL_INO &&
+		ino != EXT3_RESIZE_INO && ino < EXT3_FIRST_INO(sb)) ||
+		ino > le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count)) {
+		ext3_error(sb, "ext3_get_inode_block",
 			    "bad inode number: %lu", ino);
 		return 0;
 	}
 	block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb);
 	if (block_group >= EXT3_SB(sb)->s_groups_count) {
-		ext3_error (sb, "ext3_get_inode_block",
-			    "group >= groups count");
+		ext3_error(sb,"ext3_get_inode_block","group >= groups count");
 		return 0;
 	}
 	smp_rmb();
@@ -2285,7 +2422,7 @@
 		return 0;
 	}
 
-	gdp = (struct ext3_group_desc *) bh->b_data;
+	gdp = (struct ext3_group_desc *)bh->b_data;
 	/*
 	 * Figure out the offset within the block group inode table
 	 */
@@ -2834,7 +2971,7 @@
 
 
 /*
- * akpm: how many blocks doth make a writepage()?
+ * How many blocks doth make a writepage()?
  *
  * With N blocks per page, it may be:
  * N data blocks
@@ -2924,8 +3061,8 @@
 }
 
 /*
- * akpm: What we do here is to mark the in-core inode as clean
- * with respect to inode dirtiness (it may still be data-dirty).
+ * What we do here is to mark the in-core inode as clean with respect to inode
+ * dirtiness (it may still be data-dirty).
  * This means that the in-core inode may be reaped by prune_icache
  * without having to perform any I/O.  This is a very good thing,
  * because *any* task may call prune_icache - even ones which
@@ -2957,7 +3094,7 @@
 }
 
 /*
- * akpm: ext3_dirty_inode() is called from __mark_inode_dirty()
+ * ext3_dirty_inode() is called from __mark_inode_dirty()
  *
  * We're really interested in the case where a file is being extended.
  * i_size has been changed by generic_commit_write() and we thus need
@@ -2993,7 +3130,7 @@
 	return;
 }
 
-#ifdef AKPM
+#if 0
 /* 
  * Bind an inode's backing buffer_head into this transaction, to prevent
  * it from being flushed to disk early.  Unlike
@@ -3001,8 +3138,7 @@
  * returns no iloc structure, so the caller needs to repeat the iloc
  * lookup to mark the inode dirty later.
  */
-static inline int
-ext3_pin_inode(handle_t *handle, struct inode *inode)
+static int ext3_pin_inode(handle_t *handle, struct inode *inode)
 {
 	struct ext3_iloc iloc;
 
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 86e4431..f8a5266 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -1678,12 +1678,6 @@
 	}
 
 	if (test_opt(sb, NOBH)) {
-		if (sb->s_blocksize_bits != PAGE_CACHE_SHIFT) {
-			printk(KERN_WARNING "EXT3-fs: Ignoring nobh option "
-				"since filesystem blocksize doesn't match "
-				"pagesize\n");
-			clear_opt(sbi->s_mount_opt, NOBH);
-		}
 		if (!(test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)) {
 			printk(KERN_WARNING "EXT3-fs: Ignoring nobh option - "
 				"its supported only with writeback mode\n");
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 4095bc1..698b85b 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -741,7 +741,7 @@
 	return ret;
 }
 
-struct file_operations fat_dir_operations = {
+const struct file_operations fat_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= fat_readdir,
 	.ioctl		= fat_dir_ioctl,
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 88aa1ae..1ee2523 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -112,7 +112,7 @@
 	}
 }
 
-struct file_operations fat_file_operations = {
+const struct file_operations fat_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= do_sync_read,
 	.write		= do_sync_write,
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 297300f..c1ce284f 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -101,11 +101,11 @@
 }
 
 static int fat_get_blocks(struct inode *inode, sector_t iblock,
-			  unsigned long max_blocks,
 			  struct buffer_head *bh_result, int create)
 {
 	struct super_block *sb = inode->i_sb;
 	int err;
+	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
 
 	err = __fat_get_blocks(inode, iblock, &max_blocks, bh_result, create);
 	if (err)
@@ -1435,9 +1435,6 @@
 
 EXPORT_SYMBOL_GPL(fat_fill_super);
 
-int __init fat_cache_init(void);
-void fat_cache_destroy(void);
-
 static int __init init_fat_fs(void)
 {
 	int err;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 03c7895..2a24791 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -412,7 +412,7 @@
 
 /* Table to convert sigio signal codes into poll band bitmaps */
 
-static long band_table[NSIGPOLL] = {
+static const long band_table[NSIGPOLL] = {
 	POLLIN | POLLRDNORM,			/* POLL_IN */
 	POLLOUT | POLLWRNORM | POLLWRBAND,	/* POLL_OUT */
 	POLLIN | POLLRDNORM | POLLMSG,		/* POLL_MSG */
@@ -531,7 +531,7 @@
 }
 
 static DEFINE_RWLOCK(fasync_lock);
-static kmem_cache_t *fasync_cache;
+static kmem_cache_t *fasync_cache __read_mostly;
 
 /*
  * fasync_helper() is used by some character device drivers (mainly mice)
diff --git a/fs/fifo.c b/fs/fifo.c
index d13fcd3..889f722 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -145,6 +145,6 @@
  * is contain the open that then fills in the correct operations
  * depending on the access mode of the file...
  */
-struct file_operations def_fifo_fops = {
+const struct file_operations def_fifo_fops = {
 	.open		= fifo_open,	/* will set read or write pipe_fops */
 };
diff --git a/fs/file.c b/fs/file.c
index bbc7433..55f4e70 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -373,6 +373,6 @@
 void __init files_defer_init(void)
 {
 	int i;
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 		fdtable_defer_list_init(i);
 }
diff --git a/fs/freevxfs/vxfs_extern.h b/fs/freevxfs/vxfs_extern.h
index 927acf7..1cf1fe8 100644
--- a/fs/freevxfs/vxfs_extern.h
+++ b/fs/freevxfs/vxfs_extern.h
@@ -63,7 +63,7 @@
 
 /* vxfs_lookup.c */
 extern struct inode_operations	vxfs_dir_inode_ops;
-extern struct file_operations	vxfs_dir_operations;
+extern const struct file_operations	vxfs_dir_operations;
 
 /* vxfs_olt.c */
 extern int			vxfs_read_olt(struct super_block *, u_long);
diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c
index 554eb45..29cce45 100644
--- a/fs/freevxfs/vxfs_lookup.c
+++ b/fs/freevxfs/vxfs_lookup.c
@@ -56,7 +56,7 @@
 	.lookup =		vxfs_lookup,
 };
 
-struct file_operations vxfs_dir_operations = {
+const struct file_operations vxfs_dir_operations = {
 	.readdir =		vxfs_readdir,
 };
 
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 0c9a2ee..23d1f52 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -922,7 +922,7 @@
 	return 0;
 }
 
-struct file_operations fuse_dev_operations = {
+const struct file_operations fuse_dev_operations = {
 	.owner		= THIS_MODULE,
 	.llseek		= no_llseek,
 	.read		= fuse_dev_read,
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index c72a8a9..256355b 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1170,7 +1170,7 @@
 	.removexattr	= fuse_removexattr,
 };
 
-static struct file_operations fuse_dir_operations = {
+static const struct file_operations fuse_dir_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_read_dir,
 	.readdir	= fuse_readdir,
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 6f05379..975f269 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -12,7 +12,7 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 
-static struct file_operations fuse_direct_io_file_operations;
+static const struct file_operations fuse_direct_io_file_operations;
 
 static int fuse_send_open(struct inode *inode, struct file *file, int isdir,
 			  struct fuse_open_out *outargp)
@@ -611,7 +611,7 @@
 	return 0;
 }
 
-static struct file_operations fuse_file_operations = {
+static const struct file_operations fuse_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
 	.write		= generic_file_write,
@@ -623,7 +623,7 @@
 	.sendfile	= generic_file_sendfile,
 };
 
-static struct file_operations fuse_direct_io_file_operations = {
+static const struct file_operations fuse_direct_io_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= fuse_direct_read,
 	.write		= fuse_direct_write,
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 4a83adf..a16a04f 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -346,7 +346,7 @@
 }
 
 /** Device operations */
-extern struct file_operations fuse_dev_operations;
+extern const struct file_operations fuse_dev_operations;
 
 /**
  * This is the single global spinlock which protects FUSE's structures
diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c
index a7a7d77..1e44dcf 100644
--- a/fs/hfs/bnode.c
+++ b/fs/hfs/bnode.c
@@ -306,8 +306,7 @@
 	for (p = &node->tree->node_hash[hfs_bnode_hash(node->this)];
 	     *p && *p != node; p = &(*p)->next_hash)
 		;
-	if (!*p)
-		BUG();
+	BUG_ON(!*p);
 	*p = node->next_hash;
 	node->tree->node_hash_cnt--;
 }
@@ -415,8 +414,7 @@
 	spin_lock(&tree->hash_lock);
 	node = hfs_bnode_findhash(tree, num);
 	spin_unlock(&tree->hash_lock);
-	if (node)
-		BUG();
+	BUG_ON(node);
 	node = __hfs_bnode_create(tree, num);
 	if (!node)
 		return ERR_PTR(-ENOMEM);
@@ -459,8 +457,7 @@
 
 		dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n",
 		       node->tree->cnid, node->this, atomic_read(&node->refcnt));
-		if (!atomic_read(&node->refcnt))
-			BUG();
+		BUG_ON(!atomic_read(&node->refcnt));
 		if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
 			return;
 		for (i = 0; i < tree->pages_per_bnode; i++) {
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
index 7bb11ed..d20131c 100644
--- a/fs/hfs/btree.c
+++ b/fs/hfs/btree.c
@@ -36,8 +36,7 @@
 	tree->inode = iget_locked(sb, id);
 	if (!tree->inode)
 		goto free_tree;
-	if (!(tree->inode->i_state & I_NEW))
-		BUG();
+	BUG_ON(!(tree->inode->i_state & I_NEW));
 	{
 	struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
 	HFS_I(tree->inode)->flags = 0;
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index 534e5a7..7cd8cc0 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -313,7 +313,7 @@
 	return res;
 }
 
-struct file_operations hfs_dir_operations = {
+const struct file_operations hfs_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= hfs_readdir,
 	.llseek		= generic_file_llseek,
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index 18ce47a..3ed8663 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -169,7 +169,7 @@
 extern void hfs_cat_build_key(struct super_block *, btree_key *, u32, struct qstr *);
 
 /* dir.c */
-extern struct file_operations hfs_dir_operations;
+extern const struct file_operations hfs_dir_operations;
 extern struct inode_operations hfs_dir_inode_operations;
 
 /* extent.c */
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 39fd85b..2d4ced2 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -17,7 +17,7 @@
 #include "hfs_fs.h"
 #include "btree.h"
 
-static struct file_operations hfs_file_operations;
+static const struct file_operations hfs_file_operations;
 static struct inode_operations hfs_file_inode_operations;
 
 /*================ Variable-like macros ================*/
@@ -98,17 +98,6 @@
 	return res ? try_to_free_buffers(page) : 0;
 }
 
-static int hfs_get_blocks(struct inode *inode, sector_t iblock, unsigned long max_blocks,
-			  struct buffer_head *bh_result, int create)
-{
-	int ret;
-
-	ret = hfs_get_block(inode, iblock, bh_result, create);
-	if (!ret)
-		bh_result->b_size = (1 << inode->i_blkbits);
-	return ret;
-}
-
 static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb,
 		const struct iovec *iov, loff_t offset, unsigned long nr_segs)
 {
@@ -116,7 +105,7 @@
 	struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
 
 	return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
-				  offset, nr_segs, hfs_get_blocks, NULL);
+				  offset, nr_segs, hfs_get_block, NULL);
 }
 
 static int hfs_writepages(struct address_space *mapping,
@@ -612,7 +601,7 @@
 }
 
 
-static struct file_operations hfs_file_operations = {
+static const struct file_operations hfs_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
 	.write		= generic_file_write,
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 01a6fe3..1f9ece0 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -483,7 +483,7 @@
 	.rename		= hfsplus_rename,
 };
 
-struct file_operations hfsplus_dir_operations = {
+const struct file_operations hfsplus_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= hfsplus_readdir,
 	.ioctl          = hfsplus_ioctl,
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 12ed2b7..acf66db 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -93,17 +93,6 @@
 	return res ? try_to_free_buffers(page) : 0;
 }
 
-static int hfsplus_get_blocks(struct inode *inode, sector_t iblock, unsigned long max_blocks,
-			      struct buffer_head *bh_result, int create)
-{
-	int ret;
-
-	ret = hfsplus_get_block(inode, iblock, bh_result, create);
-	if (!ret)
-		bh_result->b_size = (1 << inode->i_blkbits);
-	return ret;
-}
-
 static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb,
 		const struct iovec *iov, loff_t offset, unsigned long nr_segs)
 {
@@ -111,7 +100,7 @@
 	struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
 
 	return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
-				  offset, nr_segs, hfsplus_get_blocks, NULL);
+				  offset, nr_segs, hfsplus_get_block, NULL);
 }
 
 static int hfsplus_writepages(struct address_space *mapping,
@@ -291,7 +280,7 @@
 	.listxattr	= hfsplus_listxattr,
 };
 
-static struct file_operations hfsplus_file_operations = {
+static const struct file_operations hfsplus_file_operations = {
 	.llseek 	= generic_file_llseek,
 	.read		= generic_file_read,
 	.write		= generic_file_write,
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index b3ad0bd..bf0f8e1 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -384,7 +384,7 @@
 	return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
 }
 
-static struct file_operations hostfs_file_fops = {
+static const struct file_operations hostfs_file_fops = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
 	.sendfile	= generic_file_sendfile,
@@ -399,7 +399,7 @@
 	.fsync		= hostfs_fsync,
 };
 
-static struct file_operations hostfs_dir_fops = {
+static const struct file_operations hostfs_dir_fops = {
 	.llseek		= generic_file_llseek,
 	.readdir	= hostfs_readdir,
 	.read		= generic_read_dir,
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index b97809d..23b7cee 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -360,7 +360,6 @@
 	spare_out[2] = buf.f_spare[2];
 	spare_out[3] = buf.f_spare[3];
 	spare_out[4] = buf.f_spare[4];
-	spare_out[5] = buf.f_spare[5];
 	return(0);
 }
 
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index 5591f96..ecc9180 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -310,7 +310,7 @@
 	return ERR_PTR(-ENOENT);
 }
 
-struct file_operations hpfs_dir_ops =
+const struct file_operations hpfs_dir_ops =
 {
 	.llseek		= hpfs_dir_lseek,
 	.read		= generic_read_dir,
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index 7c995ac..d3b9fff 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -119,7 +119,7 @@
 	return retval;
 }
 
-struct file_operations hpfs_file_ops =
+const struct file_operations hpfs_file_ops =
 {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
index 4c6473a..29b7a3e 100644
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -240,7 +240,7 @@
 /* dir.c */
 
 struct dentry *hpfs_lookup(struct inode *, struct dentry *, struct nameidata *);
-extern struct file_operations hpfs_dir_ops;
+extern const struct file_operations hpfs_dir_ops;
 
 /* dnode.c */
 
@@ -266,7 +266,7 @@
 /* file.c */
 
 int hpfs_file_fsync(struct file *, struct dentry *, int);
-extern struct file_operations hpfs_file_ops;
+extern const struct file_operations hpfs_file_ops;
 extern struct inode_operations hpfs_file_iops;
 extern struct address_space_operations hpfs_aops;
 
diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
index a44dc58..5e6363b 100644
--- a/fs/hppfs/hppfs_kern.c
+++ b/fs/hppfs/hppfs_kern.c
@@ -216,10 +216,10 @@
 static struct inode_operations hppfs_file_iops = {
 };
 
-static ssize_t read_proc(struct file *file, char *buf, ssize_t count,
+static ssize_t read_proc(struct file *file, char __user *buf, ssize_t count,
 			 loff_t *ppos, int is_user)
 {
-	ssize_t (*read)(struct file *, char *, size_t, loff_t *);
+	ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
 	ssize_t n;
 
 	read = file->f_dentry->d_inode->i_fop->read;
@@ -236,7 +236,7 @@
 	return n;
 }
 
-static ssize_t hppfs_read_file(int fd, char *buf, ssize_t count)
+static ssize_t hppfs_read_file(int fd, char __user *buf, ssize_t count)
 {
 	ssize_t n;
 	int cur, err;
@@ -274,7 +274,7 @@
 	return n;
 }
 
-static ssize_t hppfs_read(struct file *file, char *buf, size_t count,
+static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count,
 			  loff_t *ppos)
 {
 	struct hppfs_private *hppfs = file->private_data;
@@ -313,12 +313,12 @@
 	return(count);
 }
 
-static ssize_t hppfs_write(struct file *file, const char *buf, size_t len,
+static ssize_t hppfs_write(struct file *file, const char __user *buf, size_t len,
 			   loff_t *ppos)
 {
 	struct hppfs_private *data = file->private_data;
 	struct file *proc_file = data->proc_file;
-	ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+	ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
 	int err;
 
 	write = proc_file->f_dentry->d_inode->i_fop->write;
@@ -558,7 +558,7 @@
 	return(default_llseek(file, off, where));
 }
 
-static struct file_operations hppfs_file_fops = {
+static const struct file_operations hppfs_file_fops = {
 	.owner		= NULL,
 	.llseek		= hppfs_llseek,
 	.read		= hppfs_read,
@@ -609,7 +609,7 @@
 	return(0);
 }
 
-static struct file_operations hppfs_dir_fops = {
+static const struct file_operations hppfs_dir_fops = {
 	.owner		= NULL,
 	.readdir	= hppfs_readdir,
 	.open		= hppfs_dir_open,
@@ -658,7 +658,7 @@
 	.statfs		= hppfs_statfs,
 };
 
-static int hppfs_readlink(struct dentry *dentry, char *buffer, int buflen)
+static int hppfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
 {
 	struct file *proc_file;
 	struct dentry *proc_dentry;
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 25fa8bb..3a5b4e9 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -35,7 +35,7 @@
 
 static struct super_operations hugetlbfs_ops;
 static struct address_space_operations hugetlbfs_aops;
-struct file_operations hugetlbfs_file_operations;
+const struct file_operations hugetlbfs_file_operations;
 static struct inode_operations hugetlbfs_dir_inode_operations;
 static struct inode_operations hugetlbfs_inode_operations;
 
@@ -566,7 +566,7 @@
 		inode_init_once(&ei->vfs_inode);
 }
 
-struct file_operations hugetlbfs_file_operations = {
+const struct file_operations hugetlbfs_file_operations = {
 	.mmap			= hugetlbfs_file_mmap,
 	.fsync			= simple_sync_file,
 	.get_unmapped_area	= hugetlb_get_unmapped_area,
diff --git a/fs/inode.c b/fs/inode.c
index 85da110..32b7c33 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -56,8 +56,8 @@
 #define I_HASHBITS	i_hash_shift
 #define I_HASHMASK	i_hash_mask
 
-static unsigned int i_hash_mask;
-static unsigned int i_hash_shift;
+static unsigned int i_hash_mask __read_mostly;
+static unsigned int i_hash_shift __read_mostly;
 
 /*
  * Each inode can be on two separate lists. One is
@@ -73,7 +73,7 @@
 
 LIST_HEAD(inode_in_use);
 LIST_HEAD(inode_unused);
-static struct hlist_head *inode_hashtable;
+static struct hlist_head *inode_hashtable __read_mostly;
 
 /*
  * A simple spinlock to protect the list manipulations.
@@ -98,13 +98,13 @@
  */
 struct inodes_stat_t inodes_stat;
 
-static kmem_cache_t * inode_cachep;
+static kmem_cache_t * inode_cachep __read_mostly;
 
 static struct inode *alloc_inode(struct super_block *sb)
 {
 	static struct address_space_operations empty_aops;
 	static struct inode_operations empty_iops;
-	static struct file_operations empty_fops;
+	static const struct file_operations empty_fops;
 	struct inode *inode;
 
 	if (sb->s_op->alloc_inode)
diff --git a/fs/inotify.c b/fs/inotify.c
index a61e93e..367c487 100644
--- a/fs/inotify.c
+++ b/fs/inotify.c
@@ -39,15 +39,15 @@
 
 static atomic_t inotify_cookie;
 
-static kmem_cache_t *watch_cachep;
-static kmem_cache_t *event_cachep;
+static kmem_cache_t *watch_cachep __read_mostly;
+static kmem_cache_t *event_cachep __read_mostly;
 
-static struct vfsmount *inotify_mnt;
+static struct vfsmount *inotify_mnt __read_mostly;
 
 /* these are configurable via /proc/sys/fs/inotify/ */
-int inotify_max_user_instances;
-int inotify_max_user_watches;
-int inotify_max_queued_events;
+int inotify_max_user_instances __read_mostly;
+int inotify_max_user_watches __read_mostly;
+int inotify_max_queued_events __read_mostly;
 
 /*
  * Lock ordering:
@@ -920,7 +920,7 @@
 	return ret;
 }
 
-static struct file_operations inotify_fops = {
+static const struct file_operations inotify_fops = {
 	.poll           = inotify_poll,
 	.read           = inotify_read,
 	.release        = inotify_release,
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 7901ac9..5440ea2 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -16,7 +16,7 @@
 
 static int isofs_readdir(struct file *, void *, filldir_t);
 
-struct file_operations isofs_dir_operations =
+const struct file_operations isofs_dir_operations =
 {
 	.read		= generic_read_dir,
 	.readdir	= isofs_readdir,
diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h
index 439a19b..b87ba06 100644
--- a/fs/isofs/isofs.h
+++ b/fs/isofs/isofs.h
@@ -175,6 +175,6 @@
 }
 
 extern struct inode_operations isofs_dir_inode_operations;
-extern struct file_operations isofs_dir_operations;
+extern const struct file_operations isofs_dir_operations;
 extern struct address_space_operations isofs_symlink_aops;
 extern struct export_operations isofs_export_ops;
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index ada31fa..c609f50 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -1873,16 +1873,15 @@
 }
 
 /** 
- * int journal_invalidatepage() 
+ * void journal_invalidatepage()
  * @journal: journal to use for flush... 
  * @page:    page to flush
  * @offset:  length of page to invalidate.
  *
  * Reap page buffers containing data after offset in page.
  *
- * Return non-zero if the page's buffers were successfully reaped.
  */
-int journal_invalidatepage(journal_t *journal, 
+void journal_invalidatepage(journal_t *journal,
 		      struct page *page, 
 		      unsigned long offset)
 {
@@ -1893,7 +1892,7 @@
 	if (!PageLocked(page))
 		BUG();
 	if (!page_has_buffers(page))
-		return 1;
+		return;
 
 	/* We will potentially be playing with lists other than just the
 	 * data lists (especially for journaled data mode), so be
@@ -1916,11 +1915,9 @@
 	} while (bh != head);
 
 	if (!offset) {
-		if (!may_free || !try_to_free_buffers(page))
-			return 0;
-		J_ASSERT(!page_has_buffers(page));
+		if (may_free && try_to_free_buffers(page))
+			J_ASSERT(!page_has_buffers(page));
 	}
-	return 1;
 }
 
 /* 
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
index 5a4519e..020cc09 100644
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -55,9 +55,9 @@
 static int jffs_remove(struct inode *dir, struct dentry *dentry, int type);
 
 static struct super_operations jffs_ops;
-static struct file_operations jffs_file_operations;
+static const struct file_operations jffs_file_operations;
 static struct inode_operations jffs_file_inode_operations;
-static struct file_operations jffs_dir_operations;
+static const struct file_operations jffs_dir_operations;
 static struct inode_operations jffs_dir_inode_operations;
 static struct address_space_operations jffs_address_operations;
 
@@ -1629,7 +1629,7 @@
 }
 
 
-static struct file_operations jffs_file_operations =
+static const struct file_operations jffs_file_operations =
 {
 	.open		= generic_file_open,
 	.llseek		= generic_file_llseek,
@@ -1649,7 +1649,7 @@
 };
 
 
-static struct file_operations jffs_dir_operations =
+static const struct file_operations jffs_dir_operations =
 {
 	.readdir	= jffs_readdir,
 };
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
index 4db8be8..5c63e0c 100644
--- a/fs/jffs2/compr_zlib.c
+++ b/fs/jffs2/compr_zlib.c
@@ -33,13 +33,14 @@
 	*/
 #define STREAM_END_SPACE 12
 
-static DECLARE_MUTEX(deflate_sem);
-static DECLARE_MUTEX(inflate_sem);
+static DEFINE_MUTEX(deflate_mutex);
+static DEFINE_MUTEX(inflate_mutex);
 static z_stream inf_strm, def_strm;
 
 #ifdef __KERNEL__ /* Linux-only */
 #include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 
 static int __init alloc_workspaces(void)
 {
@@ -79,11 +80,11 @@
 	if (*dstlen <= STREAM_END_SPACE)
 		return -1;
 
-	down(&deflate_sem);
+	mutex_lock(&deflate_mutex);
 
 	if (Z_OK != zlib_deflateInit(&def_strm, 3)) {
 		printk(KERN_WARNING "deflateInit failed\n");
-		up(&deflate_sem);
+		mutex_unlock(&deflate_mutex);
 		return -1;
 	}
 
@@ -104,7 +105,7 @@
 		if (ret != Z_OK) {
 			D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret));
 			zlib_deflateEnd(&def_strm);
-			up(&deflate_sem);
+			mutex_unlock(&deflate_mutex);
 			return -1;
 		}
 	}
@@ -133,7 +134,7 @@
 	*sourcelen = def_strm.total_in;
 	ret = 0;
  out:
-	up(&deflate_sem);
+	mutex_unlock(&deflate_mutex);
 	return ret;
 }
 
@@ -145,7 +146,7 @@
 	int ret;
 	int wbits = MAX_WBITS;
 
-	down(&inflate_sem);
+	mutex_lock(&inflate_mutex);
 
 	inf_strm.next_in = data_in;
 	inf_strm.avail_in = srclen;
@@ -173,7 +174,7 @@
 
 	if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
 		printk(KERN_WARNING "inflateInit failed\n");
-		up(&inflate_sem);
+		mutex_unlock(&inflate_mutex);
 		return 1;
 	}
 
@@ -183,7 +184,7 @@
 		printk(KERN_NOTICE "inflate returned %d\n", ret);
 	}
 	zlib_inflateEnd(&inf_strm);
-	up(&inflate_sem);
+	mutex_unlock(&inflate_mutex);
         return 0;
 }
 
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index a7bf9cb..8bc7a50 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -37,7 +37,7 @@
 static int jffs2_rename (struct inode *, struct dentry *,
                         struct inode *, struct dentry *);
 
-struct file_operations jffs2_dir_operations =
+const struct file_operations jffs2_dir_operations =
 {
 	.read =		generic_read_dir,
 	.readdir =	jffs2_readdir,
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index 935f273..9f41712 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -38,7 +38,7 @@
 	return 0;
 }
 
-struct file_operations jffs2_file_operations =
+const struct file_operations jffs2_file_operations =
 {
 	.llseek =	generic_file_llseek,
 	.open =		generic_file_open,
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index 59e7a39..d307cf5 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -159,11 +159,11 @@
 void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c);
 
 /* dir.c */
-extern struct file_operations jffs2_dir_operations;
+extern const struct file_operations jffs2_dir_operations;
 extern struct inode_operations jffs2_dir_inode_operations;
 
 /* file.c */
-extern struct file_operations jffs2_file_operations;
+extern const struct file_operations jffs2_file_operations;
 extern struct inode_operations jffs2_file_inode_operations;
 extern struct address_space_operations jffs2_file_address_operations;
 int jffs2_fsync(struct file *, struct dentry *, int);
diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index e1ac6e4..1c9745b 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -100,7 +100,7 @@
 #endif
 };
 
-struct file_operations jfs_file_operations = {
+const struct file_operations jfs_file_operations = {
 	.open		= jfs_open,
 	.llseek		= generic_file_llseek,
 	.write		= generic_file_write,
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index 51a5fed..04eb78f 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -258,7 +258,8 @@
 static int jfs_get_block(struct inode *ip, sector_t lblock,
 			 struct buffer_head *bh_result, int create)
 {
-	return jfs_get_blocks(ip, lblock, 1, bh_result, create);
+	return jfs_get_blocks(ip, lblock, bh_result->b_size >> ip->i_blkbits,
+			bh_result, create);
 }
 
 static int jfs_writepage(struct page *page, struct writeback_control *wbc)
@@ -301,7 +302,7 @@
 	struct inode *inode = file->f_mapping->host;
 
 	return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
-				offset, nr_segs, jfs_get_blocks, NULL);
+				offset, nr_segs, jfs_get_block, NULL);
 }
 
 struct address_space_operations jfs_aops = {
diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h
index 095d471..c300726 100644
--- a/fs/jfs/jfs_inode.h
+++ b/fs/jfs/jfs_inode.h
@@ -35,9 +35,9 @@
 
 extern struct address_space_operations jfs_aops;
 extern struct inode_operations jfs_dir_inode_operations;
-extern struct file_operations jfs_dir_operations;
+extern const struct file_operations jfs_dir_operations;
 extern struct inode_operations jfs_file_inode_operations;
-extern struct file_operations jfs_file_operations;
+extern const struct file_operations jfs_file_operations;
 extern struct inode_operations jfs_symlink_inode_operations;
 extern struct dentry_operations jfs_ci_dentry_operations;
 #endif				/* _H_JFS_INODE */
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index 0b348b1..3315f0b 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -69,6 +69,7 @@
 #include <linux/bio.h>
 #include <linux/suspend.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 #include "jfs_incore.h"
 #include "jfs_filsys.h"
 #include "jfs_metapage.h"
@@ -165,7 +166,7 @@
  */
 static LIST_HEAD(jfs_external_logs);
 static struct jfs_log *dummy_log = NULL;
-static DECLARE_MUTEX(jfs_log_sem);
+static DEFINE_MUTEX(jfs_log_mutex);
 
 /*
  * forward references
@@ -1085,20 +1086,20 @@
 	if (sbi->mntflag & JFS_INLINELOG)
 		return open_inline_log(sb);
 
-	down(&jfs_log_sem);
+	mutex_lock(&jfs_log_mutex);
 	list_for_each_entry(log, &jfs_external_logs, journal_list) {
 		if (log->bdev->bd_dev == sbi->logdev) {
 			if (memcmp(log->uuid, sbi->loguuid,
 				   sizeof(log->uuid))) {
 				jfs_warn("wrong uuid on JFS journal\n");
-				up(&jfs_log_sem);
+				mutex_unlock(&jfs_log_mutex);
 				return -EINVAL;
 			}
 			/*
 			 * add file system to log active file system list
 			 */
 			if ((rc = lmLogFileSystem(log, sbi, 1))) {
-				up(&jfs_log_sem);
+				mutex_unlock(&jfs_log_mutex);
 				return rc;
 			}
 			goto journal_found;
@@ -1106,7 +1107,7 @@
 	}
 
 	if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL))) {
-		up(&jfs_log_sem);
+		mutex_unlock(&jfs_log_mutex);
 		return -ENOMEM;
 	}
 	INIT_LIST_HEAD(&log->sb_list);
@@ -1151,7 +1152,7 @@
 	sbi->log = log;
 	LOG_UNLOCK(log);
 
-	up(&jfs_log_sem);
+	mutex_unlock(&jfs_log_mutex);
 	return 0;
 
 	/*
@@ -1168,7 +1169,7 @@
 	blkdev_put(bdev);
 
       free:		/* free log descriptor */
-	up(&jfs_log_sem);
+	mutex_unlock(&jfs_log_mutex);
 	kfree(log);
 
 	jfs_warn("lmLogOpen: exit(%d)", rc);
@@ -1212,11 +1213,11 @@
 {
 	int rc;
 
-	down(&jfs_log_sem);
+	mutex_lock(&jfs_log_mutex);
 	if (!dummy_log) {
 		dummy_log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL);
 		if (!dummy_log) {
-			up(&jfs_log_sem);
+			mutex_unlock(&jfs_log_mutex);
 			return -ENOMEM;
 		}
 		INIT_LIST_HEAD(&dummy_log->sb_list);
@@ -1229,7 +1230,7 @@
 		if (rc) {
 			kfree(dummy_log);
 			dummy_log = NULL;
-			up(&jfs_log_sem);
+			mutex_unlock(&jfs_log_mutex);
 			return rc;
 		}
 	}
@@ -1238,7 +1239,7 @@
 	list_add(&JFS_SBI(sb)->log_list, &dummy_log->sb_list);
 	JFS_SBI(sb)->log = dummy_log;
 	LOG_UNLOCK(dummy_log);
-	up(&jfs_log_sem);
+	mutex_unlock(&jfs_log_mutex);
 
 	return 0;
 }
@@ -1466,7 +1467,7 @@
 
 	jfs_info("lmLogClose: log:0x%p", log);
 
-	down(&jfs_log_sem);
+	mutex_lock(&jfs_log_mutex);
 	LOG_LOCK(log);
 	list_del(&sbi->log_list);
 	LOG_UNLOCK(log);
@@ -1516,7 +1517,7 @@
 	kfree(log);
 
       out:
-	up(&jfs_log_sem);
+	mutex_unlock(&jfs_log_mutex);
 	jfs_info("lmLogClose: exit(%d)", rc);
 	return rc;
 }
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
index 5fbaeaa..f28696f 100644
--- a/fs/jfs/jfs_metapage.c
+++ b/fs/jfs/jfs_metapage.c
@@ -220,8 +220,8 @@
 	if (metapage_cache == NULL)
 		return -ENOMEM;
 
-	metapage_mempool = mempool_create(METAPOOL_MIN_PAGES, mempool_alloc_slab,
-					  mempool_free_slab, metapage_cache);
+	metapage_mempool = mempool_create_slab_pool(METAPOOL_MIN_PAGES,
+						    metapage_cache);
 
 	if (metapage_mempool == NULL) {
 		kmem_cache_destroy(metapage_cache);
@@ -578,14 +578,13 @@
 	return 0;
 }
 
-static int metapage_invalidatepage(struct page *page, unsigned long offset)
+static void metapage_invalidatepage(struct page *page, unsigned long offset)
 {
 	BUG_ON(offset);
 
-	if (PageWriteback(page))
-		return 0;
+	BUG_ON(PageWriteback(page));
 
-	return metapage_releasepage(page, 0);
+	metapage_releasepage(page, 0);
 }
 
 struct address_space_operations jfs_metapage_aops = {
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 309cee5..09ea03f 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -1519,7 +1519,7 @@
 #endif
 };
 
-struct file_operations jfs_dir_operations = {
+const struct file_operations jfs_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= jfs_readdir,
 	.fsync		= jfs_fsync,
diff --git a/fs/libfs.c b/fs/libfs.c
index 4fdeace..7145ba7 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -179,7 +179,7 @@
 	return -EISDIR;
 }
 
-struct file_operations simple_dir_operations = {
+const struct file_operations simple_dir_operations = {
 	.open		= dcache_dir_open,
 	.release	= dcache_dir_close,
 	.llseek		= dcache_dir_lseek,
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 112ebf8..729ac42 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -16,6 +16,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
 #include <linux/lockd/sm_inter.h>
+#include <linux/mutex.h>
 
 
 #define NLMDBG_FACILITY		NLMDBG_HOSTCACHE
@@ -30,7 +31,7 @@
 static struct nlm_host *	nlm_hosts[NLM_HOST_NRHASH];
 static unsigned long		next_gc;
 static int			nrhosts;
-static DECLARE_MUTEX(nlm_host_sema);
+static DEFINE_MUTEX(nlm_host_mutex);
 
 
 static void			nlm_gc_hosts(void);
@@ -71,7 +72,7 @@
 	hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
 
 	/* Lock hash table */
-	down(&nlm_host_sema);
+	mutex_lock(&nlm_host_mutex);
 
 	if (time_after_eq(jiffies, next_gc))
 		nlm_gc_hosts();
@@ -91,7 +92,7 @@
 				nlm_hosts[hash] = host;
 			}
 			nlm_get_host(host);
-			up(&nlm_host_sema);
+			mutex_unlock(&nlm_host_mutex);
 			return host;
 		}
 	}
@@ -130,7 +131,7 @@
 		next_gc = 0;
 
 nohost:
-	up(&nlm_host_sema);
+	mutex_unlock(&nlm_host_mutex);
 	return host;
 }
 
@@ -141,19 +142,19 @@
 	 * and return it
 	 */
 	int hash;
-	down(&nlm_host_sema);
+	mutex_lock(&nlm_host_mutex);
 	for (hash = 0 ; hash < NLM_HOST_NRHASH; hash++) {
 		struct nlm_host *host, **hp;
 		for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) {
 			if (host->h_server &&
 			    host->h_killed == 0) {
 				nlm_get_host(host);
-				up(&nlm_host_sema);
+				mutex_unlock(&nlm_host_mutex);
 				return host;
 			}
 		}
 	}
-	up(&nlm_host_sema);
+	mutex_unlock(&nlm_host_mutex);
 	return NULL;
 }
 
@@ -265,7 +266,7 @@
 	int		i;
 
 	dprintk("lockd: shutting down host module\n");
-	down(&nlm_host_sema);
+	mutex_lock(&nlm_host_mutex);
 
 	/* First, make all hosts eligible for gc */
 	dprintk("lockd: nuking all hosts...\n");
@@ -276,7 +277,7 @@
 
 	/* Then, perform a garbage collection pass */
 	nlm_gc_hosts();
-	up(&nlm_host_sema);
+	mutex_unlock(&nlm_host_mutex);
 
 	/* complain if any hosts are left */
 	if (nrhosts) {
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 5e85bde..fd56c88 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/stats.h>
@@ -43,13 +44,13 @@
 struct nlmsvc_binding *		nlmsvc_ops;
 EXPORT_SYMBOL(nlmsvc_ops);
 
-static DECLARE_MUTEX(nlmsvc_sema);
+static DEFINE_MUTEX(nlmsvc_mutex);
 static unsigned int		nlmsvc_users;
 static pid_t			nlmsvc_pid;
 int				nlmsvc_grace_period;
 unsigned long			nlmsvc_timeout;
 
-static DECLARE_MUTEX_LOCKED(lockd_start);
+static DECLARE_COMPLETION(lockd_start_done);
 static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
 
 /*
@@ -112,7 +113,7 @@
 	 * Let our maker know we're running.
 	 */
 	nlmsvc_pid = current->pid;
-	up(&lockd_start);
+	complete(&lockd_start_done);
 
 	daemonize("lockd");
 
@@ -215,7 +216,7 @@
 	struct svc_serv *	serv;
 	int			error = 0;
 
-	down(&nlmsvc_sema);
+	mutex_lock(&nlmsvc_mutex);
 	/*
 	 * Unconditionally increment the user count ... this is
 	 * the number of clients who _want_ a lockd process.
@@ -263,7 +264,7 @@
 			"lockd_up: create thread failed, error=%d\n", error);
 		goto destroy_and_out;
 	}
-	down(&lockd_start);
+	wait_for_completion(&lockd_start_done);
 
 	/*
 	 * Note: svc_serv structures have an initial use count of 1,
@@ -272,7 +273,7 @@
 destroy_and_out:
 	svc_destroy(serv);
 out:
-	up(&nlmsvc_sema);
+	mutex_unlock(&nlmsvc_mutex);
 	return error;
 }
 EXPORT_SYMBOL(lockd_up);
@@ -285,7 +286,7 @@
 {
 	static int warned;
 
-	down(&nlmsvc_sema);
+	mutex_lock(&nlmsvc_mutex);
 	if (nlmsvc_users) {
 		if (--nlmsvc_users)
 			goto out;
@@ -315,7 +316,7 @@
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 out:
-	up(&nlmsvc_sema);
+	mutex_unlock(&nlmsvc_mutex);
 }
 EXPORT_SYMBOL(lockd_down);
 
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index c7a6e3a..a570e5c 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -11,6 +11,7 @@
 #include <linux/string.h>
 #include <linux/time.h>
 #include <linux/in.h>
+#include <linux/mutex.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfsd/nfsfh.h>
@@ -28,7 +29,7 @@
 #define FILE_HASH_BITS		5
 #define FILE_NRHASH		(1<<FILE_HASH_BITS)
 static struct nlm_file *	nlm_files[FILE_NRHASH];
-static DECLARE_MUTEX(nlm_file_sema);
+static DEFINE_MUTEX(nlm_file_mutex);
 
 #ifdef NFSD_DEBUG
 static inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f)
@@ -91,7 +92,7 @@
 	hash = file_hash(f);
 
 	/* Lock file table */
-	down(&nlm_file_sema);
+	mutex_lock(&nlm_file_mutex);
 
 	for (file = nlm_files[hash]; file; file = file->f_next)
 		if (!nfs_compare_fh(&file->f_handle, f))
@@ -130,7 +131,7 @@
 	nfserr = 0;
 
 out_unlock:
-	up(&nlm_file_sema);
+	mutex_unlock(&nlm_file_mutex);
 	return nfserr;
 
 out_free:
@@ -239,14 +240,14 @@
 	struct nlm_file	*file, **fp;
 	int		i;
 
-	down(&nlm_file_sema);
+	mutex_lock(&nlm_file_mutex);
 	for (i = 0; i < FILE_NRHASH; i++) {
 		fp = nlm_files + i;
 		while ((file = *fp) != NULL) {
 			/* Traverse locks, blocks and shares of this file
 			 * and update file->f_locks count */
 			if (nlm_inspect_file(host, file, action)) {
-				up(&nlm_file_sema);
+				mutex_unlock(&nlm_file_mutex);
 				return 1;
 			}
 
@@ -261,7 +262,7 @@
 			}
 		}
 	}
-	up(&nlm_file_sema);
+	mutex_unlock(&nlm_file_mutex);
 	return 0;
 }
 
@@ -281,7 +282,7 @@
 				file, file->f_count);
 
 	/* Lock file table */
-	down(&nlm_file_sema);
+	mutex_lock(&nlm_file_mutex);
 
 	/* If there are no more locks etc, delete the file */
 	if(--file->f_count == 0) {
@@ -289,7 +290,7 @@
 			nlm_delete_file(file);
 	}
 
-	up(&nlm_file_sema);
+	mutex_unlock(&nlm_file_mutex);
 }
 
 /*
diff --git a/fs/locks.c b/fs/locks.c
index 56f996e..dda83d6 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -142,7 +142,7 @@
 static LIST_HEAD(file_lock_list);
 static LIST_HEAD(blocked_list);
 
-static kmem_cache_t *filelock_cache;
+static kmem_cache_t *filelock_cache __read_mostly;
 
 /* Allocate an empty lock structure. */
 static struct file_lock *locks_alloc_lock(void)
@@ -168,18 +168,9 @@
 /* Free a lock which is not in use. */
 static void locks_free_lock(struct file_lock *fl)
 {
-	if (fl == NULL) {
-		BUG();
-		return;
-	}
-	if (waitqueue_active(&fl->fl_wait))
-		panic("Attempting to free lock with active wait queue");
-
-	if (!list_empty(&fl->fl_block))
-		panic("Attempting to free lock with active block list");
-
-	if (!list_empty(&fl->fl_link))
-		panic("Attempting to free lock on active lock list");
+	BUG_ON(waitqueue_active(&fl->fl_wait));
+	BUG_ON(!list_empty(&fl->fl_block));
+	BUG_ON(!list_empty(&fl->fl_link));
 
 	locks_release_private(fl);
 	kmem_cache_free(filelock_cache, fl);
@@ -533,12 +524,7 @@
 static void locks_insert_block(struct file_lock *blocker, 
 			       struct file_lock *waiter)
 {
-	if (!list_empty(&waiter->fl_block)) {
-		printk(KERN_ERR "locks_insert_block: removing duplicated lock "
-			"(pid=%d %Ld-%Ld type=%d)\n", waiter->fl_pid,
-			waiter->fl_start, waiter->fl_end, waiter->fl_type);
-		__locks_delete_block(waiter);
-	}
+	BUG_ON(!list_empty(&waiter->fl_block));
 	list_add_tail(&waiter->fl_block, &blocker->fl_block);
 	waiter->fl_next = blocker;
 	if (IS_POSIX(blocker))
@@ -740,8 +726,9 @@
  * at the head of the list, but that's secret knowledge known only to
  * flock_lock_file and posix_lock_file.
  */
-static int flock_lock_file(struct file *filp, struct file_lock *new_fl)
+static int flock_lock_file(struct file *filp, struct file_lock *request)
 {
+	struct file_lock *new_fl = NULL;
 	struct file_lock **before;
 	struct inode * inode = filp->f_dentry->d_inode;
 	int error = 0;
@@ -756,17 +743,19 @@
 			continue;
 		if (filp != fl->fl_file)
 			continue;
-		if (new_fl->fl_type == fl->fl_type)
+		if (request->fl_type == fl->fl_type)
 			goto out;
 		found = 1;
 		locks_delete_lock(before);
 		break;
 	}
-	unlock_kernel();
 
-	if (new_fl->fl_type == F_UNLCK)
-		return 0;
+	if (request->fl_type == F_UNLCK)
+		goto out;
 
+	new_fl = locks_alloc_lock();
+	if (new_fl == NULL)
+		goto out;
 	/*
 	 * If a higher-priority process was blocked on the old file lock,
 	 * give it the opportunity to lock the file.
@@ -774,32 +763,31 @@
 	if (found)
 		cond_resched();
 
-	lock_kernel();
 	for_each_lock(inode, before) {
 		struct file_lock *fl = *before;
 		if (IS_POSIX(fl))
 			break;
 		if (IS_LEASE(fl))
 			continue;
-		if (!flock_locks_conflict(new_fl, fl))
+		if (!flock_locks_conflict(request, fl))
 			continue;
 		error = -EAGAIN;
-		if (new_fl->fl_flags & FL_SLEEP) {
-			locks_insert_block(fl, new_fl);
-		}
+		if (request->fl_flags & FL_SLEEP)
+			locks_insert_block(fl, request);
 		goto out;
 	}
+	locks_copy_lock(new_fl, request);
 	locks_insert_lock(&inode->i_flock, new_fl);
-	error = 0;
+	new_fl = NULL;
 
 out:
 	unlock_kernel();
+	if (new_fl)
+		locks_free_lock(new_fl);
 	return error;
 }
 
-EXPORT_SYMBOL(posix_lock_file);
-
-static int __posix_lock_file(struct inode *inode, struct file_lock *request)
+static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock)
 {
 	struct file_lock *fl;
 	struct file_lock *new_fl, *new_fl2;
@@ -823,6 +811,8 @@
 				continue;
 			if (!posix_locks_conflict(request, fl))
 				continue;
+			if (conflock)
+				locks_copy_lock(conflock, fl);
 			error = -EAGAIN;
 			if (!(request->fl_flags & FL_SLEEP))
 				goto out;
@@ -992,8 +982,24 @@
  */
 int posix_lock_file(struct file *filp, struct file_lock *fl)
 {
-	return __posix_lock_file(filp->f_dentry->d_inode, fl);
+	return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, NULL);
 }
+EXPORT_SYMBOL(posix_lock_file);
+
+/**
+ * posix_lock_file_conf - Apply a POSIX-style lock to a file
+ * @filp: The file to apply the lock to
+ * @fl: The lock to be applied
+ * @conflock: Place to return a copy of the conflicting lock, if found.
+ *
+ * Except for the conflock parameter, acts just like posix_lock_file.
+ */
+int posix_lock_file_conf(struct file *filp, struct file_lock *fl,
+			struct file_lock *conflock)
+{
+	return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, conflock);
+}
+EXPORT_SYMBOL(posix_lock_file_conf);
 
 /**
  * posix_lock_file_wait - Apply a POSIX-style lock to a file
@@ -1009,7 +1015,7 @@
 	int error;
 	might_sleep ();
 	for (;;) {
-		error = __posix_lock_file(filp->f_dentry->d_inode, fl);
+		error = posix_lock_file(filp, fl);
 		if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP))
 			break;
 		error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
@@ -1081,7 +1087,7 @@
 	fl.fl_end = offset + count - 1;
 
 	for (;;) {
-		error = __posix_lock_file(inode, &fl);
+		error = __posix_lock_file_conf(inode, &fl, NULL);
 		if (error != -EAGAIN)
 			break;
 		if (!(fl.fl_flags & FL_SLEEP))
@@ -1558,9 +1564,7 @@
 		error = flock_lock_file_wait(filp, lock);
 
  out_free:
-	if (list_empty(&lock->fl_link)) {
-		locks_free_lock(lock);
-	}
+	locks_free_lock(lock);
 
  out_putf:
 	fput(filp);
@@ -1694,7 +1698,7 @@
 		error = filp->f_op->lock(filp, cmd, file_lock);
 	else {
 		for (;;) {
-			error = __posix_lock_file(inode, file_lock);
+			error = posix_lock_file(filp, file_lock);
 			if ((error != -EAGAIN) || (cmd == F_SETLK))
 				break;
 			error = wait_event_interruptible(file_lock->fl_wait,
@@ -1837,7 +1841,7 @@
 		error = filp->f_op->lock(filp, cmd, file_lock);
 	else {
 		for (;;) {
-			error = __posix_lock_file(inode, file_lock);
+			error = posix_lock_file(filp, file_lock);
 			if ((error != -EAGAIN) || (cmd == F_SETLK64))
 				break;
 			error = wait_event_interruptible(file_lock->fl_wait,
diff --git a/fs/mbcache.c b/fs/mbcache.c
index 73e754f..e4fde1a 100644
--- a/fs/mbcache.c
+++ b/fs/mbcache.c
@@ -311,7 +311,7 @@
 /*
  * mb_cache_shrink()
  *
- * Removes all cache entires of a device from the cache. All cache entries
+ * Removes all cache entries of a device from the cache. All cache entries
  * currently in use cannot be freed, and thus remain in the cache. All others
  * are freed.
  *
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 732502a..69224d1 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -14,7 +14,7 @@
 
 static int minix_readdir(struct file *, void *, filldir_t);
 
-struct file_operations minix_dir_operations = {
+const struct file_operations minix_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= minix_readdir,
 	.fsync		= minix_sync_file,
diff --git a/fs/minix/file.c b/fs/minix/file.c
index f1d77ac..420b328 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -15,7 +15,7 @@
  */
 int minix_sync_file(struct file *, struct dentry *, int);
 
-struct file_operations minix_file_operations = {
+const struct file_operations minix_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
 	.write		= generic_file_write,
diff --git a/fs/minix/minix.h b/fs/minix/minix.h
index e42a8bb..c55b77c 100644
--- a/fs/minix/minix.h
+++ b/fs/minix/minix.h
@@ -81,8 +81,8 @@
 
 extern struct inode_operations minix_file_inode_operations;
 extern struct inode_operations minix_dir_inode_operations;
-extern struct file_operations minix_file_operations;
-extern struct file_operations minix_dir_operations;
+extern const struct file_operations minix_file_operations;
+extern const struct file_operations minix_dir_operations;
 extern struct dentry_operations minix_dentry_operations;
 
 static inline struct minix_sb_info *minix_sb(struct super_block *sb)
diff --git a/fs/mpage.c b/fs/mpage.c
index e431cb3..9bf2eb3 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -163,9 +163,19 @@
 	} while (page_bh != head);
 }
 
+/*
+ * This is the worker routine which does all the work of mapping the disk
+ * blocks and constructs largest possible bios, submits them for IO if the
+ * blocks are not contiguous on the disk.
+ *
+ * We pass a buffer_head back and forth and use its buffer_mapped() flag to
+ * represent the validity of its disk mapping and to decide when to do the next
+ * get_block() call.
+ */
 static struct bio *
 do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,
-			sector_t *last_block_in_bio, get_block_t get_block)
+		sector_t *last_block_in_bio, struct buffer_head *map_bh,
+		unsigned long *first_logical_block, get_block_t get_block)
 {
 	struct inode *inode = page->mapping->host;
 	const unsigned blkbits = inode->i_blkbits;
@@ -173,33 +183,72 @@
 	const unsigned blocksize = 1 << blkbits;
 	sector_t block_in_file;
 	sector_t last_block;
+	sector_t last_block_in_file;
 	sector_t blocks[MAX_BUF_PER_PAGE];
 	unsigned page_block;
 	unsigned first_hole = blocks_per_page;
 	struct block_device *bdev = NULL;
-	struct buffer_head bh;
 	int length;
 	int fully_mapped = 1;
+	unsigned nblocks;
+	unsigned relative_block;
 
 	if (page_has_buffers(page))
 		goto confused;
 
 	block_in_file = (sector_t)page->index << (PAGE_CACHE_SHIFT - blkbits);
-	last_block = (i_size_read(inode) + blocksize - 1) >> blkbits;
+	last_block = block_in_file + nr_pages * blocks_per_page;
+	last_block_in_file = (i_size_read(inode) + blocksize - 1) >> blkbits;
+	if (last_block > last_block_in_file)
+		last_block = last_block_in_file;
+	page_block = 0;
 
-	bh.b_page = page;
-	for (page_block = 0; page_block < blocks_per_page;
-				page_block++, block_in_file++) {
-		bh.b_state = 0;
+	/*
+	 * Map blocks using the result from the previous get_blocks call first.
+	 */
+	nblocks = map_bh->b_size >> blkbits;
+	if (buffer_mapped(map_bh) && block_in_file > *first_logical_block &&
+			block_in_file < (*first_logical_block + nblocks)) {
+		unsigned map_offset = block_in_file - *first_logical_block;
+		unsigned last = nblocks - map_offset;
+
+		for (relative_block = 0; ; relative_block++) {
+			if (relative_block == last) {
+				clear_buffer_mapped(map_bh);
+				break;
+			}
+			if (page_block == blocks_per_page)
+				break;
+			blocks[page_block] = map_bh->b_blocknr + map_offset +
+						relative_block;
+			page_block++;
+			block_in_file++;
+		}
+		bdev = map_bh->b_bdev;
+	}
+
+	/*
+	 * Then do more get_blocks calls until we are done with this page.
+	 */
+	map_bh->b_page = page;
+	while (page_block < blocks_per_page) {
+		map_bh->b_state = 0;
+		map_bh->b_size = 0;
+
 		if (block_in_file < last_block) {
-			if (get_block(inode, block_in_file, &bh, 0))
+			map_bh->b_size = (last_block-block_in_file) << blkbits;
+			if (get_block(inode, block_in_file, map_bh, 0))
 				goto confused;
+			*first_logical_block = block_in_file;
 		}
 
-		if (!buffer_mapped(&bh)) {
+		if (!buffer_mapped(map_bh)) {
 			fully_mapped = 0;
 			if (first_hole == blocks_per_page)
 				first_hole = page_block;
+			page_block++;
+			block_in_file++;
+			clear_buffer_mapped(map_bh);
 			continue;
 		}
 
@@ -209,8 +258,8 @@
 		 * we just collected from get_block into the page's buffers
 		 * so readpage doesn't have to repeat the get_block call
 		 */
-		if (buffer_uptodate(&bh)) {
-			map_buffer_to_page(page, &bh, page_block);
+		if (buffer_uptodate(map_bh)) {
+			map_buffer_to_page(page, map_bh, page_block);
 			goto confused;
 		}
 	
@@ -218,10 +267,20 @@
 			goto confused;		/* hole -> non-hole */
 
 		/* Contiguous blocks? */
-		if (page_block && blocks[page_block-1] != bh.b_blocknr-1)
+		if (page_block && blocks[page_block-1] != map_bh->b_blocknr-1)
 			goto confused;
-		blocks[page_block] = bh.b_blocknr;
-		bdev = bh.b_bdev;
+		nblocks = map_bh->b_size >> blkbits;
+		for (relative_block = 0; ; relative_block++) {
+			if (relative_block == nblocks) {
+				clear_buffer_mapped(map_bh);
+				break;
+			} else if (page_block == blocks_per_page)
+				break;
+			blocks[page_block] = map_bh->b_blocknr+relative_block;
+			page_block++;
+			block_in_file++;
+		}
+		bdev = map_bh->b_bdev;
 	}
 
 	if (first_hole != blocks_per_page) {
@@ -260,7 +319,7 @@
 		goto alloc_new;
 	}
 
-	if (buffer_boundary(&bh) || (first_hole != blocks_per_page))
+	if (buffer_boundary(map_bh) || (first_hole != blocks_per_page))
 		bio = mpage_bio_submit(READ, bio);
 	else
 		*last_block_in_bio = blocks[blocks_per_page - 1];
@@ -331,7 +390,10 @@
 	unsigned page_idx;
 	sector_t last_block_in_bio = 0;
 	struct pagevec lru_pvec;
+	struct buffer_head map_bh;
+	unsigned long first_logical_block = 0;
 
+	clear_buffer_mapped(&map_bh);
 	pagevec_init(&lru_pvec, 0);
 	for (page_idx = 0; page_idx < nr_pages; page_idx++) {
 		struct page *page = list_entry(pages->prev, struct page, lru);
@@ -342,7 +404,9 @@
 					page->index, GFP_KERNEL)) {
 			bio = do_mpage_readpage(bio, page,
 					nr_pages - page_idx,
-					&last_block_in_bio, get_block);
+					&last_block_in_bio, &map_bh,
+					&first_logical_block,
+					get_block);
 			if (!pagevec_add(&lru_pvec, page))
 				__pagevec_lru_add(&lru_pvec);
 		} else {
@@ -364,9 +428,12 @@
 {
 	struct bio *bio = NULL;
 	sector_t last_block_in_bio = 0;
+	struct buffer_head map_bh;
+	unsigned long first_logical_block = 0;
 
-	bio = do_mpage_readpage(bio, page, 1,
-			&last_block_in_bio, get_block);
+	clear_buffer_mapped(&map_bh);
+	bio = do_mpage_readpage(bio, page, 1, &last_block_in_bio,
+			&map_bh, &first_logical_block, get_block);
 	if (bio)
 		mpage_bio_submit(READ, bio);
 	return 0;
@@ -472,6 +539,7 @@
 	for (page_block = 0; page_block < blocks_per_page; ) {
 
 		map_bh.b_state = 0;
+		map_bh.b_size = 1 << blkbits;
 		if (get_block(inode, block_in_file, &map_bh, 1))
 			goto confused;
 		if (buffer_new(&map_bh))
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 626a367..5b76ccd 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -12,14 +12,6 @@
 #include <linux/msdos_fs.h>
 #include <linux/smp_lock.h>
 
-/* MS-DOS "device special files" */
-static const unsigned char *reserved_names[] = {
-	"CON     ", "PRN     ", "NUL     ", "AUX     ",
-	"LPT1    ", "LPT2    ", "LPT3    ", "LPT4    ",
-	"COM1    ", "COM2    ", "COM3    ", "COM4    ",
-	NULL
-};
-
 /* Characters that are undesirable in an MS-DOS file name */
 static unsigned char bad_chars[] = "*?<>|\"";
 static unsigned char bad_if_strict_pc[] = "+=,; ";
@@ -40,7 +32,6 @@
 	 */
 {
 	unsigned char *walk;
-	const unsigned char **reserved;
 	unsigned char c;
 	int space;
 
@@ -127,11 +118,7 @@
 	}
 	while (walk - res < MSDOS_NAME)
 		*walk++ = ' ';
-	if (!opts->atari)
-		/* GEMDOS is less stupid and has no reserved names */
-		for (reserved = reserved_names; *reserved; reserved++)
-			if (!strncmp(res, *reserved, 8))
-				return -EINVAL;
+
 	return 0;
 }
 
diff --git a/fs/namei.c b/fs/namei.c
index 98dc2e1..96723ae 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -546,33 +546,6 @@
 	struct dentry *dentry;
 };
 
-static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd)
-{
-	int error;
-	void *cookie;
-	struct dentry *dentry = path->dentry;
-
-	touch_atime(path->mnt, dentry);
-	nd_set_link(nd, NULL);
-
-	if (path->mnt == nd->mnt)
-		mntget(path->mnt);
-	cookie = dentry->d_inode->i_op->follow_link(dentry, nd);
-	error = PTR_ERR(cookie);
-	if (!IS_ERR(cookie)) {
-		char *s = nd_get_link(nd);
-		error = 0;
-		if (s)
-			error = __vfs_follow_link(nd, s);
-		if (dentry->d_inode->i_op->put_link)
-			dentry->d_inode->i_op->put_link(dentry, nd, cookie);
-	}
-	dput(dentry);
-	mntput(path->mnt);
-
-	return error;
-}
-
 static inline void dput_path(struct path *path, struct nameidata *nd)
 {
 	dput(path->dentry);
@@ -589,6 +562,36 @@
 	nd->dentry = path->dentry;
 }
 
+static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd)
+{
+	int error;
+	void *cookie;
+	struct dentry *dentry = path->dentry;
+
+	touch_atime(path->mnt, dentry);
+	nd_set_link(nd, NULL);
+
+	if (path->mnt != nd->mnt) {
+		path_to_nameidata(path, nd);
+		dget(dentry);
+	}
+	mntget(path->mnt);
+	cookie = dentry->d_inode->i_op->follow_link(dentry, nd);
+	error = PTR_ERR(cookie);
+	if (!IS_ERR(cookie)) {
+		char *s = nd_get_link(nd);
+		error = 0;
+		if (s)
+			error = __vfs_follow_link(nd, s);
+		if (dentry->d_inode->i_op->put_link)
+			dentry->d_inode->i_op->put_link(dentry, nd, cookie);
+	}
+	dput(dentry);
+	mntput(path->mnt);
+
+	return error;
+}
+
 /*
  * This limits recursive symlink follows to 8, while
  * limiting consecutive symlinks to 40.
@@ -1251,7 +1254,7 @@
 	return dentry;
 }
 
-struct dentry * lookup_hash(struct nameidata *nd)
+static struct dentry *lookup_hash(struct nameidata *nd)
 {
 	return __lookup_hash(&nd->last, nd->dentry, nd);
 }
@@ -2694,7 +2697,6 @@
 EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
 EXPORT_SYMBOL(getname);
 EXPORT_SYMBOL(lock_rename);
-EXPORT_SYMBOL(lookup_hash);
 EXPORT_SYMBOL(lookup_one_len);
 EXPORT_SYMBOL(page_follow_link_light);
 EXPORT_SYMBOL(page_put_link);
diff --git a/fs/namespace.c b/fs/namespace.c
index 71e75bc..bf478ad 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -43,9 +43,9 @@
 
 static int event;
 
-static struct list_head *mount_hashtable;
+static struct list_head *mount_hashtable __read_mostly;
 static int hash_mask __read_mostly, hash_bits __read_mostly;
-static kmem_cache_t *mnt_cache;
+static kmem_cache_t *mnt_cache __read_mostly;
 static struct rw_semaphore namespace_sem;
 
 /* /sys/fs */
@@ -459,9 +459,9 @@
 	spin_unlock(&vfsmount_lock);
 
 	if (actual_refs > minimum_refs)
-		return -EBUSY;
+		return 0;
 
-	return 0;
+	return 1;
 }
 
 EXPORT_SYMBOL(may_umount_tree);
@@ -481,10 +481,10 @@
  */
 int may_umount(struct vfsmount *mnt)
 {
-	int ret = 0;
+	int ret = 1;
 	spin_lock(&vfsmount_lock);
 	if (propagate_mount_busy(mnt, 2))
-		ret = -EBUSY;
+		ret = 0;
 	spin_unlock(&vfsmount_lock);
 	return ret;
 }
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index cfd76f4..f0860c6 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -49,7 +49,7 @@
 #define ncp_symlink NULL
 #endif
 		      
-struct file_operations ncp_dir_operations =
+const struct file_operations ncp_dir_operations =
 {
 	.read		= generic_read_dir,
 	.readdir	= ncp_readdir,
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index ebdad8f..e6b7c67 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -283,7 +283,7 @@
 	return 0;
 }
 
-struct file_operations ncp_file_operations =
+const struct file_operations ncp_file_operations =
 {
 	.llseek		= remote_llseek,
 	.read		= ncp_file_read,
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 99d2cfb..90c95ad 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -14,6 +14,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/nfs_fs.h>
+#include <linux/mutex.h>
 
 #include <net/inet_sock.h>
 
@@ -31,7 +32,7 @@
 };
 
 static struct nfs_callback_data nfs_callback_info;
-static DECLARE_MUTEX(nfs_callback_sema);
+static DEFINE_MUTEX(nfs_callback_mutex);
 static struct svc_program nfs4_callback_program;
 
 unsigned int nfs_callback_set_tcpport;
@@ -95,7 +96,7 @@
 	int ret = 0;
 
 	lock_kernel();
-	down(&nfs_callback_sema);
+	mutex_lock(&nfs_callback_mutex);
 	if (nfs_callback_info.users++ || nfs_callback_info.pid != 0)
 		goto out;
 	init_completion(&nfs_callback_info.started);
@@ -121,7 +122,7 @@
 	nfs_callback_info.serv = serv;
 	wait_for_completion(&nfs_callback_info.started);
 out:
-	up(&nfs_callback_sema);
+	mutex_unlock(&nfs_callback_mutex);
 	unlock_kernel();
 	return ret;
 out_destroy:
@@ -139,7 +140,7 @@
 	int ret = 0;
 
 	lock_kernel();
-	down(&nfs_callback_sema);
+	mutex_lock(&nfs_callback_mutex);
 	nfs_callback_info.users--;
 	do {
 		if (nfs_callback_info.users != 0 || nfs_callback_info.pid == 0)
@@ -147,7 +148,7 @@
 		if (kill_proc(nfs_callback_info.pid, SIGKILL, 1) < 0)
 			break;
 	} while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0);
-	up(&nfs_callback_sema);
+	mutex_unlock(&nfs_callback_mutex);
 	unlock_kernel();
 	return ret;
 }
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 06c48b3..a23f348 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -54,7 +54,7 @@
 static int nfs_fsync_dir(struct file *, struct dentry *, int);
 static loff_t nfs_llseek_dir(struct file *, loff_t, int);
 
-struct file_operations nfs_dir_operations = {
+const struct file_operations nfs_dir_operations = {
 	.llseek		= nfs_llseek_dir,
 	.read		= generic_read_dir,
 	.readdir	= nfs_readdir,
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 5263b28..f1df2c8 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -49,7 +49,7 @@
 static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
 static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
 
-struct file_operations nfs_file_operations = {
+const struct file_operations nfs_file_operations = {
 	.llseek		= nfs_file_llseek,
 	.read		= do_sync_read,
 	.write		= do_sync_write,
@@ -318,10 +318,9 @@
 	return status;
 }
 
-static int nfs_invalidate_page(struct page *page, unsigned long offset)
+static void nfs_invalidate_page(struct page *page, unsigned long offset)
 {
 	/* FIXME: we really should cancel any unstarted writes on this page */
-	return 1;
 }
 
 static int nfs_release_page(struct page *page, gfp_t gfp)
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 3961524..624ca71 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -663,10 +663,8 @@
 	if (nfs_rdata_cachep == NULL)
 		return -ENOMEM;
 
-	nfs_rdata_mempool = mempool_create(MIN_POOL_READ,
-					   mempool_alloc_slab,
-					   mempool_free_slab,
-					   nfs_rdata_cachep);
+	nfs_rdata_mempool = mempool_create_slab_pool(MIN_POOL_READ,
+						     nfs_rdata_cachep);
 	if (nfs_rdata_mempool == NULL)
 		return -ENOMEM;
 
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 3f52254..4cfada2 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -1521,17 +1521,13 @@
 	if (nfs_wdata_cachep == NULL)
 		return -ENOMEM;
 
-	nfs_wdata_mempool = mempool_create(MIN_POOL_WRITE,
-					   mempool_alloc_slab,
-					   mempool_free_slab,
-					   nfs_wdata_cachep);
+	nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE,
+						     nfs_wdata_cachep);
 	if (nfs_wdata_mempool == NULL)
 		return -ENOMEM;
 
-	nfs_commit_mempool = mempool_create(MIN_POOL_COMMIT,
-					   mempool_alloc_slab,
-					   mempool_free_slab,
-					   nfs_wdata_cachep);
+	nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT,
+						      nfs_wdata_cachep);
 	if (nfs_commit_mempool == NULL)
 		return -ENOMEM;
 
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 417ec02..c340be0 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -57,27 +57,17 @@
 #define	EXPKEY_HASHMASK		(EXPKEY_HASHMAX -1)
 static struct cache_head *expkey_table[EXPKEY_HASHMAX];
 
-static inline int svc_expkey_hash(struct svc_expkey *item)
+static void expkey_put(struct kref *ref)
 {
-	int hash = item->ek_fsidtype;
-	char * cp = (char*)item->ek_fsid;
-	int len = key_len(item->ek_fsidtype);
+	struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
 
-	hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
-	hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
-	return hash & EXPKEY_HASHMASK;
-}
-
-void expkey_put(struct cache_head *item, struct cache_detail *cd)
-{
-	if (cache_put(item, cd)) {
-		struct svc_expkey *key = container_of(item, struct svc_expkey, h);
-		if (test_bit(CACHE_VALID, &item->flags) &&
-		    !test_bit(CACHE_NEGATIVE, &item->flags))
-			exp_put(key->ek_export);
-		auth_domain_put(key->ek_client);
-		kfree(key);
+	if (test_bit(CACHE_VALID, &key->h.flags) &&
+	    !test_bit(CACHE_NEGATIVE, &key->h.flags)) {
+		dput(key->ek_dentry);
+		mntput(key->ek_mnt);
 	}
+	auth_domain_put(key->ek_client);
+	kfree(key);
 }
 
 static void expkey_request(struct cache_detail *cd,
@@ -95,7 +85,10 @@
 	(*bpp)[-1] = '\n';
 }
 
-static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *, int);
+static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old);
+static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *);
+static struct cache_detail svc_expkey_cache;
+
 static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
 {
 	/* client fsidtype fsid [path] */
@@ -106,6 +99,7 @@
 	int fsidtype;
 	char *ep;
 	struct svc_expkey key;
+	struct svc_expkey *ek;
 
 	if (mesg[mlen-1] != '\n')
 		return -EINVAL;
@@ -150,40 +144,38 @@
 	key.ek_fsidtype = fsidtype;
 	memcpy(key.ek_fsid, buf, len);
 
+	ek = svc_expkey_lookup(&key);
+	err = -ENOMEM;
+	if (!ek)
+		goto out;
+
 	/* now we want a pathname, or empty meaning NEGATIVE  */
+	err = -EINVAL;
 	if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0)
 		goto out;
 	dprintk("Path seems to be <%s>\n", buf);
 	err = 0;
 	if (len == 0) {
-		struct svc_expkey *ek;
 		set_bit(CACHE_NEGATIVE, &key.h.flags);
-		ek = svc_expkey_lookup(&key, 1);
+		ek = svc_expkey_update(&key, ek);
 		if (ek)
-			expkey_put(&ek->h, &svc_expkey_cache);
+			cache_put(&ek->h, &svc_expkey_cache);
+		else err = -ENOMEM;
 	} else {
 		struct nameidata nd;
-		struct svc_expkey *ek;
-		struct svc_export *exp;
 		err = path_lookup(buf, 0, &nd);
 		if (err)
 			goto out;
 
 		dprintk("Found the path %s\n", buf);
-		exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
-
-		err = -ENOENT;
-		if (!exp)
-			goto out_nd;
-		key.ek_export = exp;
-		dprintk("And found export\n");
+		key.ek_mnt = nd.mnt;
+		key.ek_dentry = nd.dentry;
 		
-		ek = svc_expkey_lookup(&key, 1);
+		ek = svc_expkey_update(&key, ek);
 		if (ek)
-			expkey_put(&ek->h, &svc_expkey_cache);
-		exp_put(exp);
-		err = 0;
-	out_nd:
+			cache_put(&ek->h, &svc_expkey_cache);
+		else
+			err = -ENOMEM;
 		path_release(&nd);
 	}
 	cache_flush();
@@ -214,13 +206,58 @@
 	if (test_bit(CACHE_VALID, &h->flags) && 
 	    !test_bit(CACHE_NEGATIVE, &h->flags)) {
 		seq_printf(m, " ");
-		seq_path(m, ek->ek_export->ex_mnt, ek->ek_export->ex_dentry, "\\ \t\n");
+		seq_path(m, ek->ek_mnt, ek->ek_dentry, "\\ \t\n");
 	}
 	seq_printf(m, "\n");
 	return 0;
 }
-	
-struct cache_detail svc_expkey_cache = {
+
+static inline int expkey_match (struct cache_head *a, struct cache_head *b)
+{
+	struct svc_expkey *orig = container_of(a, struct svc_expkey, h);
+	struct svc_expkey *new = container_of(b, struct svc_expkey, h);
+
+	if (orig->ek_fsidtype != new->ek_fsidtype ||
+	    orig->ek_client != new->ek_client ||
+	    memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0)
+		return 0;
+	return 1;
+}
+
+static inline void expkey_init(struct cache_head *cnew,
+				   struct cache_head *citem)
+{
+	struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
+	struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
+
+	kref_get(&item->ek_client->ref);
+	new->ek_client = item->ek_client;
+	new->ek_fsidtype = item->ek_fsidtype;
+	new->ek_fsid[0] = item->ek_fsid[0];
+	new->ek_fsid[1] = item->ek_fsid[1];
+	new->ek_fsid[2] = item->ek_fsid[2];
+}
+
+static inline void expkey_update(struct cache_head *cnew,
+				   struct cache_head *citem)
+{
+	struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
+	struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
+
+	new->ek_mnt = mntget(item->ek_mnt);
+	new->ek_dentry = dget(item->ek_dentry);
+}
+
+static struct cache_head *expkey_alloc(void)
+{
+	struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL);
+	if (i)
+		return &i->h;
+	else
+		return NULL;
+}
+
+static struct cache_detail svc_expkey_cache = {
 	.owner		= THIS_MODULE,
 	.hash_size	= EXPKEY_HASHMAX,
 	.hash_table	= expkey_table,
@@ -229,34 +266,52 @@
 	.cache_request	= expkey_request,
 	.cache_parse	= expkey_parse,
 	.cache_show	= expkey_show,
+	.match		= expkey_match,
+	.init		= expkey_init,
+	.update       	= expkey_update,
+	.alloc		= expkey_alloc,
 };
 
-static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b)
+static struct svc_expkey *
+svc_expkey_lookup(struct svc_expkey *item)
 {
-	if (a->ek_fsidtype != b->ek_fsidtype ||
-	    a->ek_client != b->ek_client ||
-	    memcmp(a->ek_fsid, b->ek_fsid, key_len(a->ek_fsidtype)) != 0)
-		return 0;
-	return 1;
+	struct cache_head *ch;
+	int hash = item->ek_fsidtype;
+	char * cp = (char*)item->ek_fsid;
+	int len = key_len(item->ek_fsidtype);
+
+	hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
+	hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
+	hash &= EXPKEY_HASHMASK;
+
+	ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h,
+				 hash);
+	if (ch)
+		return container_of(ch, struct svc_expkey, h);
+	else
+		return NULL;
 }
 
-static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item)
+static struct svc_expkey *
+svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old)
 {
-	cache_get(&item->ek_client->h);
-	new->ek_client = item->ek_client;
-	new->ek_fsidtype = item->ek_fsidtype;
-	new->ek_fsid[0] = item->ek_fsid[0];
-	new->ek_fsid[1] = item->ek_fsid[1];
-	new->ek_fsid[2] = item->ek_fsid[2];
+	struct cache_head *ch;
+	int hash = new->ek_fsidtype;
+	char * cp = (char*)new->ek_fsid;
+	int len = key_len(new->ek_fsidtype);
+
+	hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
+	hash ^= hash_ptr(new->ek_client, EXPKEY_HASHBITS);
+	hash &= EXPKEY_HASHMASK;
+
+	ch = sunrpc_cache_update(&svc_expkey_cache, &new->h,
+				 &old->h, hash);
+	if (ch)
+		return container_of(ch, struct svc_expkey, h);
+	else
+		return NULL;
 }
 
-static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item)
-{
-	cache_get(&item->ek_export->h);
-	new->ek_export = item->ek_export;
-}
-
-static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */
 
 #define	EXPORT_HASHBITS		8
 #define	EXPORT_HASHMAX		(1<< EXPORT_HASHBITS)
@@ -264,25 +319,13 @@
 
 static struct cache_head *export_table[EXPORT_HASHMAX];
 
-static inline int svc_export_hash(struct svc_export *item)
+static void svc_export_put(struct kref *ref)
 {
-	int rv;
-
-	rv = hash_ptr(item->ex_client, EXPORT_HASHBITS);
-	rv ^= hash_ptr(item->ex_dentry, EXPORT_HASHBITS);
-	rv ^= hash_ptr(item->ex_mnt, EXPORT_HASHBITS);
-	return rv;
-}
-
-void svc_export_put(struct cache_head *item, struct cache_detail *cd)
-{
-	if (cache_put(item, cd)) {
-		struct svc_export *exp = container_of(item, struct svc_export, h);
-		dput(exp->ex_dentry);
-		mntput(exp->ex_mnt);
-		auth_domain_put(exp->ex_client);
-		kfree(exp);
-	}
+	struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
+	dput(exp->ex_dentry);
+	mntput(exp->ex_mnt);
+	auth_domain_put(exp->ex_client);
+	kfree(exp);
 }
 
 static void svc_export_request(struct cache_detail *cd,
@@ -304,7 +347,9 @@
 	(*bpp)[-1] = '\n';
 }
 
-static struct svc_export *svc_export_lookup(struct svc_export *, int);
+static struct svc_export *svc_export_update(struct svc_export *new,
+					    struct svc_export *old);
+static struct svc_export *svc_export_lookup(struct svc_export *);
 
 static int check_export(struct inode *inode, int flags)
 {
@@ -417,11 +462,16 @@
 		if (err) goto out;
 	}
 
-	expp = svc_export_lookup(&exp, 1);
+	expp = svc_export_lookup(&exp);
 	if (expp)
-		exp_put(expp);
-	err = 0;
+		expp = svc_export_update(&exp, expp);
+	else
+		err = -ENOMEM;
 	cache_flush();
+	if (expp == NULL)
+		err = -ENOMEM;
+	else
+		exp_put(expp);
  out:
 	if (nd.dentry)
 		path_release(&nd);
@@ -455,6 +505,46 @@
 	seq_puts(m, ")\n");
 	return 0;
 }
+static int svc_export_match(struct cache_head *a, struct cache_head *b)
+{
+	struct svc_export *orig = container_of(a, struct svc_export, h);
+	struct svc_export *new = container_of(b, struct svc_export, h);
+	return orig->ex_client == new->ex_client &&
+		orig->ex_dentry == new->ex_dentry &&
+		orig->ex_mnt == new->ex_mnt;
+}
+
+static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
+{
+	struct svc_export *new = container_of(cnew, struct svc_export, h);
+	struct svc_export *item = container_of(citem, struct svc_export, h);
+
+	kref_get(&item->ex_client->ref);
+	new->ex_client = item->ex_client;
+	new->ex_dentry = dget(item->ex_dentry);
+	new->ex_mnt = mntget(item->ex_mnt);
+}
+
+static void export_update(struct cache_head *cnew, struct cache_head *citem)
+{
+	struct svc_export *new = container_of(cnew, struct svc_export, h);
+	struct svc_export *item = container_of(citem, struct svc_export, h);
+
+	new->ex_flags = item->ex_flags;
+	new->ex_anon_uid = item->ex_anon_uid;
+	new->ex_anon_gid = item->ex_anon_gid;
+	new->ex_fsid = item->ex_fsid;
+}
+
+static struct cache_head *svc_export_alloc(void)
+{
+	struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL);
+	if (i)
+		return &i->h;
+	else
+		return NULL;
+}
+
 struct cache_detail svc_export_cache = {
 	.owner		= THIS_MODULE,
 	.hash_size	= EXPORT_HASHMAX,
@@ -464,34 +554,49 @@
 	.cache_request	= svc_export_request,
 	.cache_parse	= svc_export_parse,
 	.cache_show	= svc_export_show,
+	.match		= svc_export_match,
+	.init		= svc_export_init,
+	.update		= export_update,
+	.alloc		= svc_export_alloc,
 };
 
-static inline int svc_export_match(struct svc_export *a, struct svc_export *b)
+static struct svc_export *
+svc_export_lookup(struct svc_export *exp)
 {
-	return a->ex_client == b->ex_client &&
-		a->ex_dentry == b->ex_dentry &&
-		a->ex_mnt == b->ex_mnt;
-}
-static inline void svc_export_init(struct svc_export *new, struct svc_export *item)
-{
-	cache_get(&item->ex_client->h);
-	new->ex_client = item->ex_client;
-	new->ex_dentry = dget(item->ex_dentry);
-	new->ex_mnt = mntget(item->ex_mnt);
+	struct cache_head *ch;
+	int hash;
+	hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS);
+	hash ^= hash_ptr(exp->ex_dentry, EXPORT_HASHBITS);
+	hash ^= hash_ptr(exp->ex_mnt, EXPORT_HASHBITS);
+
+	ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h,
+				 hash);
+	if (ch)
+		return container_of(ch, struct svc_export, h);
+	else
+		return NULL;
 }
 
-static inline void svc_export_update(struct svc_export *new, struct svc_export *item)
+static struct svc_export *
+svc_export_update(struct svc_export *new, struct svc_export *old)
 {
-	new->ex_flags = item->ex_flags;
-	new->ex_anon_uid = item->ex_anon_uid;
-	new->ex_anon_gid = item->ex_anon_gid;
-	new->ex_fsid = item->ex_fsid;
+	struct cache_head *ch;
+	int hash;
+	hash = hash_ptr(old->ex_client, EXPORT_HASHBITS);
+	hash ^= hash_ptr(old->ex_dentry, EXPORT_HASHBITS);
+	hash ^= hash_ptr(old->ex_mnt, EXPORT_HASHBITS);
+
+	ch = sunrpc_cache_update(&svc_export_cache, &new->h,
+				 &old->h,
+				 hash);
+	if (ch)
+		return container_of(ch, struct svc_export, h);
+	else
+		return NULL;
 }
 
-static DefineSimpleCacheLookup(svc_export,1) /* allow inplace updates */
 
-
-struct svc_expkey *
+static struct svc_expkey *
 exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
 {
 	struct svc_expkey key, *ek;
@@ -504,7 +609,7 @@
 	key.ek_fsidtype = fsid_type;
 	memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
 
-	ek = svc_expkey_lookup(&key, 0);
+	ek = svc_expkey_lookup(&key);
 	if (ek != NULL)
 		if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp)))
 			ek = ERR_PTR(err);
@@ -519,13 +624,16 @@
 	key.ek_client = clp;
 	key.ek_fsidtype = fsid_type;
 	memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
-	key.ek_export = exp;
+	key.ek_mnt = exp->ex_mnt;
+	key.ek_dentry = exp->ex_dentry;
 	key.h.expiry_time = NEVER;
 	key.h.flags = 0;
 
-	ek = svc_expkey_lookup(&key, 1);
+	ek = svc_expkey_lookup(&key);
+	if (ek)
+		ek = svc_expkey_update(&key,ek);
 	if (ek) {
-		expkey_put(&ek->h, &svc_expkey_cache);
+		cache_put(&ek->h, &svc_expkey_cache);
 		return 0;
 	}
 	return -ENOMEM;
@@ -573,7 +681,7 @@
 	key.ex_mnt = mnt;
 	key.ex_dentry = dentry;
 
-	exp = svc_export_lookup(&key, 0);
+	exp = svc_export_lookup(&key);
 	if (exp != NULL) 
 		switch (cache_check(&svc_export_cache, &exp->h, reqp)) {
 		case 0: break;
@@ -654,7 +762,7 @@
 	ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
 	if (ek && !IS_ERR(ek)) {
 		ek->h.expiry_time = get_seconds()-1;
-		expkey_put(&ek->h, &svc_expkey_cache);
+		cache_put(&ek->h, &svc_expkey_cache);
 	}
 	svc_expkey_cache.nextcheck = get_seconds();
 }
@@ -692,7 +800,7 @@
 	ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
 	if (ek && !IS_ERR(ek)) {
 		ek->h.expiry_time = get_seconds()-1;
-		expkey_put(&ek->h, &svc_expkey_cache);
+		cache_put(&ek->h, &svc_expkey_cache);
 	}
 	svc_expkey_cache.nextcheck = get_seconds();
 }
@@ -741,8 +849,8 @@
 	if ((nxp->ex_flags & NFSEXP_FSID) &&
 	    (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) &&
 	    !IS_ERR(fsid_key) &&
-	    fsid_key->ek_export &&
-	    fsid_key->ek_export != exp)
+	    fsid_key->ek_mnt &&
+	    (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) )
 		goto finish;
 
 	if (exp) {
@@ -775,13 +883,13 @@
 	new.ex_anon_gid = nxp->ex_anon_gid;
 	new.ex_fsid = nxp->ex_dev;
 
-	exp = svc_export_lookup(&new, 1);
+	exp = svc_export_lookup(&new);
+	if (exp)
+		exp = svc_export_update(&new, exp);
 
-	if (exp == NULL)
+	if (!exp)
 		goto finish;
 
-	err = 0;
-
 	if (exp_hash(clp, exp) ||
 	    exp_fsid_hash(clp, exp)) {
 		/* failed to create at least one index */
@@ -794,7 +902,7 @@
 	if (exp)
 		exp_put(exp);
 	if (fsid_key && !IS_ERR(fsid_key))
-		expkey_put(&fsid_key->h, &svc_expkey_cache);
+		cache_put(&fsid_key->h, &svc_expkey_cache);
 	if (clp)
 		auth_domain_put(clp);
 	path_release(&nd);
@@ -912,6 +1020,24 @@
 	return err;
 }
 
+struct svc_export *
+exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
+	 struct cache_req *reqp)
+{
+	struct svc_export *exp;
+	struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
+	if (!ek || IS_ERR(ek))
+		return ERR_PTR(PTR_ERR(ek));
+
+	exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);
+	cache_put(&ek->h, &svc_expkey_cache);
+
+	if (!exp || IS_ERR(exp))
+		return ERR_PTR(PTR_ERR(exp));
+	return exp;
+}
+
+
 /*
  * Called when we need the filehandle for the root of the pseudofs,
  * for a given NFSv4 client.   The root is defined to be the
@@ -922,6 +1048,7 @@
 	       struct cache_req *creq)
 {
 	struct svc_expkey *fsid_key;
+	struct svc_export *exp;
 	int rv;
 	u32 fsidv[2];
 
@@ -933,9 +1060,15 @@
 	if (!fsid_key || IS_ERR(fsid_key))
 		return nfserr_perm;
 
-	rv = fh_compose(fhp, fsid_key->ek_export, 
-			  fsid_key->ek_export->ex_dentry, NULL);
-	expkey_put(&fsid_key->h, &svc_expkey_cache);
+	exp = exp_get_by_name(clp, fsid_key->ek_mnt, fsid_key->ek_dentry, creq);
+	if (exp == NULL)
+		rv = nfserr_perm;
+	else if (IS_ERR(exp))
+		rv = nfserrno(PTR_ERR(exp));
+	else
+		rv = fh_compose(fhp, exp,
+				fsid_key->ek_dentry, NULL);
+	cache_put(&fsid_key->h, &svc_expkey_cache);
 	return rv;
 }
 
@@ -1054,7 +1187,7 @@
 	cache_get(&exp->h);
 	if (cache_check(&svc_export_cache, &exp->h, NULL))
 		return 0;
-	if (cache_put(&exp->h, &svc_export_cache)) BUG();
+	cache_put(&exp->h, &svc_export_cache);
 	return svc_export_show(m, &svc_export_cache, cp);
 }
 
@@ -1129,7 +1262,6 @@
 	 */
 	if (dom) {
 		err = auth_unix_forget_old(dom);
-		dom->h.expiry_time = get_seconds();
 		auth_domain_put(dom);
 	}
 
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 1336965..4b6aa60 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -76,21 +76,18 @@
 	char              authname[IDMAP_NAMESZ];
 };
 
-#define DefineSimpleCacheLookupMap(STRUCT, FUNC)			\
-        DefineCacheLookup(struct STRUCT, h, FUNC##_lookup,		\
-        (struct STRUCT *item, int set), /*no setup */,			\
-	& FUNC##_cache, FUNC##_hash(item), FUNC##_match(item, tmp),	\
-	STRUCT##_init(new, item), STRUCT##_update(tmp, item), 0)
-
 /* Common entry handling */
 
 #define ENT_HASHBITS          8
 #define ENT_HASHMAX           (1 << ENT_HASHBITS)
 #define ENT_HASHMASK          (ENT_HASHMAX - 1)
 
-static inline void
-ent_init(struct ent *new, struct ent *itm)
+static void
+ent_init(struct cache_head *cnew, struct cache_head *citm)
 {
+	struct ent *new = container_of(cnew, struct ent, h);
+	struct ent *itm = container_of(citm, struct ent, h);
+
 	new->id = itm->id;
 	new->type = itm->type;
 
@@ -98,19 +95,21 @@
 	strlcpy(new->authname, itm->authname, sizeof(new->name));
 }
 
-static inline void
-ent_update(struct ent *new, struct ent *itm)
+static void
+ent_put(struct kref *ref)
 {
-	ent_init(new, itm);
+	struct ent *map = container_of(ref, struct ent, h.ref);
+	kfree(map);
 }
 
-static void
-ent_put(struct cache_head *ch, struct cache_detail *cd)
+static struct cache_head *
+ent_alloc(void)
 {
-	if (cache_put(ch, cd)) {
-		struct ent *map = container_of(ch, struct ent, h);
-		kfree(map);
-	}
+	struct ent *e = kmalloc(sizeof(*e), GFP_KERNEL);
+	if (e)
+		return &e->h;
+	else
+		return NULL;
 }
 
 /*
@@ -149,9 +148,12 @@
 	(*bpp)[-1] = '\n';
 }
 
-static inline int
-idtoname_match(struct ent *a, struct ent *b)
+static int
+idtoname_match(struct cache_head *ca, struct cache_head *cb)
 {
+	struct ent *a = container_of(ca, struct ent, h);
+	struct ent *b = container_of(cb, struct ent, h);
+
 	return (a->id == b->id && a->type == b->type &&
 	    strcmp(a->authname, b->authname) == 0);
 }
@@ -184,7 +186,8 @@
 
 
 static int         idtoname_parse(struct cache_detail *, char *, int);
-static struct ent *idtoname_lookup(struct ent *, int);
+static struct ent *idtoname_lookup(struct ent *);
+static struct ent *idtoname_update(struct ent *, struct ent *);
 
 static struct cache_detail idtoname_cache = {
 	.owner		= THIS_MODULE,
@@ -196,6 +199,10 @@
 	.cache_parse	= idtoname_parse,
 	.cache_show	= idtoname_show,
 	.warn_no_listener = warn_no_idmapd,
+	.match		= idtoname_match,
+	.init		= ent_init,
+	.update		= ent_init,
+	.alloc		= ent_alloc,
 };
 
 int
@@ -238,6 +245,11 @@
 	if (ent.h.expiry_time == 0)
 		goto out;
 
+	error = -ENOMEM;
+	res = idtoname_lookup(&ent);
+	if (!res)
+		goto out;
+
 	/* Name */
 	error = qword_get(&buf, buf1, PAGE_SIZE);
 	if (error == -EINVAL)
@@ -252,10 +264,11 @@
 		memcpy(ent.name, buf1, sizeof(ent.name));
 	}
 	error = -ENOMEM;
-	if ((res = idtoname_lookup(&ent, 1)) == NULL)
+	res = idtoname_update(&ent, res);
+	if (res == NULL)
 		goto out;
 
-	ent_put(&res->h, &idtoname_cache);
+	cache_put(&res->h, &idtoname_cache);
 
 	error = 0;
 out:
@@ -264,7 +277,31 @@
 	return error;
 }
 
-static DefineSimpleCacheLookupMap(ent, idtoname);
+
+static struct ent *
+idtoname_lookup(struct ent *item)
+{
+	struct cache_head *ch = sunrpc_cache_lookup(&idtoname_cache,
+						    &item->h,
+						    idtoname_hash(item));
+	if (ch)
+		return container_of(ch, struct ent, h);
+	else
+		return NULL;
+}
+
+static struct ent *
+idtoname_update(struct ent *new, struct ent *old)
+{
+	struct cache_head *ch = sunrpc_cache_update(&idtoname_cache,
+						    &new->h, &old->h,
+						    idtoname_hash(new));
+	if (ch)
+		return container_of(ch, struct ent, h);
+	else
+		return NULL;
+}
+
 
 /*
  * Name -> ID cache
@@ -291,9 +328,12 @@
 	(*bpp)[-1] = '\n';
 }
 
-static inline int
-nametoid_match(struct ent *a, struct ent *b)
+static int
+nametoid_match(struct cache_head *ca, struct cache_head *cb)
 {
+	struct ent *a = container_of(ca, struct ent, h);
+	struct ent *b = container_of(cb, struct ent, h);
+
 	return (a->type == b->type && strcmp(a->name, b->name) == 0 &&
 	    strcmp(a->authname, b->authname) == 0);
 }
@@ -317,7 +357,8 @@
 	return 0;
 }
 
-static struct ent *nametoid_lookup(struct ent *, int);
+static struct ent *nametoid_lookup(struct ent *);
+static struct ent *nametoid_update(struct ent *, struct ent *);
 static int         nametoid_parse(struct cache_detail *, char *, int);
 
 static struct cache_detail nametoid_cache = {
@@ -330,6 +371,10 @@
 	.cache_parse	= nametoid_parse,
 	.cache_show	= nametoid_show,
 	.warn_no_listener = warn_no_idmapd,
+	.match		= nametoid_match,
+	.init		= ent_init,
+	.update		= ent_init,
+	.alloc		= ent_alloc,
 };
 
 static int
@@ -379,10 +424,14 @@
 		set_bit(CACHE_NEGATIVE, &ent.h.flags);
 
 	error = -ENOMEM;
-	if ((res = nametoid_lookup(&ent, 1)) == NULL)
+	res = nametoid_lookup(&ent);
+	if (res == NULL)
+		goto out;
+	res = nametoid_update(&ent, res);
+	if (res == NULL)
 		goto out;
 
-	ent_put(&res->h, &nametoid_cache);
+	cache_put(&res->h, &nametoid_cache);
 	error = 0;
 out:
 	kfree(buf1);
@@ -390,7 +439,30 @@
 	return (error);
 }
 
-static DefineSimpleCacheLookupMap(ent, nametoid);
+
+static struct ent *
+nametoid_lookup(struct ent *item)
+{
+	struct cache_head *ch = sunrpc_cache_lookup(&nametoid_cache,
+						    &item->h,
+						    nametoid_hash(item));
+	if (ch)
+		return container_of(ch, struct ent, h);
+	else
+		return NULL;
+}
+
+static struct ent *
+nametoid_update(struct ent *new, struct ent *old)
+{
+	struct cache_head *ch = sunrpc_cache_update(&nametoid_cache,
+						    &new->h, &old->h,
+						    nametoid_hash(new));
+	if (ch)
+		return container_of(ch, struct ent, h);
+	else
+		return NULL;
+}
 
 /*
  * Exported API
@@ -458,24 +530,24 @@
 }
 
 static inline int
-do_idmap_lookup(struct ent *(*lookup_fn)(struct ent *, int), struct ent *key,
+do_idmap_lookup(struct ent *(*lookup_fn)(struct ent *), struct ent *key,
 		struct cache_detail *detail, struct ent **item,
 		struct idmap_defer_req *mdr)
 {
-	*item = lookup_fn(key, 0);
+	*item = lookup_fn(key);
 	if (!*item)
 		return -ENOMEM;
 	return cache_check(detail, &(*item)->h, &mdr->req);
 }
 
 static inline int
-do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *, int),
+do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *),
 			struct ent *key, struct cache_detail *detail,
 			struct ent **item)
 {
 	int ret = -ENOMEM;
 
-	*item = lookup_fn(key, 0);
+	*item = lookup_fn(key);
 	if (!*item)
 		goto out_err;
 	ret = -ETIMEDOUT;
@@ -488,7 +560,7 @@
 		goto out_put;
 	return 0;
 out_put:
-	ent_put(&(*item)->h, detail);
+	cache_put(&(*item)->h, detail);
 out_err:
 	*item = NULL;
 	return ret;
@@ -496,7 +568,7 @@
 
 static int
 idmap_lookup(struct svc_rqst *rqstp,
-		struct ent *(*lookup_fn)(struct ent *, int), struct ent *key,
+		struct ent *(*lookup_fn)(struct ent *), struct ent *key,
 		struct cache_detail *detail, struct ent **item)
 {
 	struct idmap_defer_req *mdr;
@@ -539,7 +611,7 @@
 	if (ret)
 		return ret;
 	*id = item->id;
-	ent_put(&item->h, &nametoid_cache);
+	cache_put(&item->h, &nametoid_cache);
 	return 0;
 }
 
@@ -561,7 +633,7 @@
 	ret = strlen(item->name);
 	BUG_ON(ret > IDMAP_NAMESZ);
 	memcpy(name, item->name, ret);
-	ent_put(&item->h, &idtoname_cache);
+	cache_put(&item->h, &idtoname_cache);
 	return ret;
 }
 
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f6ab762..47ec112 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -49,6 +49,7 @@
 #include <linux/nfsd/state.h>
 #include <linux/nfsd/xdr4.h>
 #include <linux/namei.h>
+#include <linux/mutex.h>
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
@@ -77,11 +78,11 @@
 
 /* Locking:
  *
- * client_sema: 
+ * client_mutex:
  * 	protects clientid_hashtbl[], clientstr_hashtbl[],
  * 	unconfstr_hashtbl[], uncofid_hashtbl[].
  */
-static DECLARE_MUTEX(client_sema);
+static DEFINE_MUTEX(client_mutex);
 
 static kmem_cache_t *stateowner_slab = NULL;
 static kmem_cache_t *file_slab = NULL;
@@ -91,13 +92,13 @@
 void
 nfs4_lock_state(void)
 {
-	down(&client_sema);
+	mutex_lock(&client_mutex);
 }
 
 void
 nfs4_unlock_state(void)
 {
-	up(&client_sema);
+	mutex_unlock(&client_mutex);
 }
 
 static inline u32
@@ -2749,37 +2750,31 @@
 	* Note: locks.c uses the BKL to protect the inode's lock list.
 	*/
 
-	status = posix_lock_file(filp, &file_lock);
-	dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",status);
+	/* XXX?: Just to divert the locks_release_private at the start of
+	 * locks_copy_lock: */
+	conflock.fl_ops = NULL;
+	conflock.fl_lmops = NULL;
+	status = posix_lock_file_conf(filp, &file_lock, &conflock);
+	dprintk("NFSD: nfsd4_lock: posix_lock_file_conf status %d\n",status);
 	switch (-status) {
 	case 0: /* success! */
 		update_stateid(&lock_stp->st_stateid);
 		memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid, 
 				sizeof(stateid_t));
-		goto out;
-	case (EAGAIN):
-		goto conflicting_lock;
+		break;
+	case (EAGAIN):		/* conflock holds conflicting lock */
+		status = nfserr_denied;
+		dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
+		nfs4_set_lock_denied(&conflock, &lock->lk_denied);
+		break;
 	case (EDEADLK):
 		status = nfserr_deadlock;
-		dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status);
-		goto out;
+		break;
 	default:        
-		status = nfserrno(status);
-		dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status);
-		goto out;
+		dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",status);
+		status = nfserr_resource;
+		break;
 	}
-
-conflicting_lock:
-	dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
-	status = nfserr_denied;
-	/* XXX There is a race here. Future patch needed to provide 
-	 * an atomic posix_lock_and_test_file
-	 */
-	if (!posix_test_lock(filp, &file_lock, &conflock)) {
-		status = nfserr_serverfault;
-		goto out;
-	}
-	nfs4_set_lock_denied(&conflock, &lock->lk_denied);
 out:
 	if (status && lock->lk_is_new && lock_sop)
 		release_stateowner(lock_sop);
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index c8960af..3ef017b 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -134,7 +134,7 @@
 	return simple_transaction_read(file, buf, size, pos);
 }
 
-static struct file_operations transaction_ops = {
+static const struct file_operations transaction_ops = {
 	.write		= nfsctl_transaction_write,
 	.read		= nfsctl_transaction_read,
 	.release	= simple_transaction_release,
@@ -146,7 +146,7 @@
 	return seq_open(file, &nfs_exports_op);
 }
 
-static struct file_operations exports_operations = {
+static const struct file_operations exports_operations = {
 	.open		= exports_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 7a3e397..3f2ec2e 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -506,7 +506,7 @@
 		nfsd_nr_put++;
 	}
 	if (exp) {
-		svc_export_put(&exp->h, &svc_export_cache);
+		cache_put(&exp->h, &svc_export_cache);
 		fhp->fh_export = NULL;
 	}
 	return;
diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c
index 1cf955b..57265d5 100644
--- a/fs/nfsd/stats.c
+++ b/fs/nfsd/stats.c
@@ -80,7 +80,7 @@
 	return single_open(file, nfsd_proc_show, NULL);
 }
 
-static struct file_operations nfsd_proc_fops = {
+static const struct file_operations nfsd_proc_fops = {
 	.owner = THIS_MODULE,
 	.open = nfsd_proc_open,
 	.read  = seq_read,
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 5320e5a..3101833 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -706,7 +706,7 @@
  * after it.
  */
 static inline int nfsd_dosync(struct file *filp, struct dentry *dp,
-			      struct file_operations *fop)
+			      const struct file_operations *fop)
 {
 	struct inode *inode = dp->d_inode;
 	int (*fsync) (struct file *, struct dentry *, int);
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
index 9d9ed3f..d1e2c6f 100644
--- a/fs/ntfs/dir.c
+++ b/fs/ntfs/dir.c
@@ -1553,7 +1553,7 @@
 
 #endif /* NTFS_RW */
 
-struct file_operations ntfs_dir_ops = {
+const struct file_operations ntfs_dir_ops = {
 	.llseek		= generic_file_llseek,	/* Seek inside directory. */
 	.read		= generic_read_dir,	/* Return -EISDIR. */
 	.readdir	= ntfs_readdir,		/* Read directory contents. */
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index f5d057e..c63a83e 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -2294,7 +2294,7 @@
 
 #endif /* NTFS_RW */
 
-struct file_operations ntfs_file_ops = {
+const struct file_operations ntfs_file_ops = {
 	.llseek		= generic_file_llseek,	 /* Seek inside file. */
 	.read		= generic_file_read,	 /* Read from file. */
 	.aio_read	= generic_file_aio_read, /* Async read from file. */
@@ -2337,6 +2337,6 @@
 #endif /* NTFS_RW */
 };
 
-struct file_operations ntfs_empty_file_ops = {};
+const struct file_operations ntfs_empty_file_ops = {};
 
 struct inode_operations ntfs_empty_inode_ops = {};
diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c
index 0fd7029..4af2ad1 100644
--- a/fs/ntfs/logfile.c
+++ b/fs/ntfs/logfile.c
@@ -515,10 +515,10 @@
 		log_page_size = PAGE_CACHE_SIZE;
 	log_page_mask = log_page_size - 1;
 	/*
-	 * Use generic_ffs() instead of ffs() to enable the compiler to
+	 * Use ntfs_ffs() instead of ffs() to enable the compiler to
 	 * optimize log_page_size and log_page_bits into constants.
 	 */
-	log_page_bits = generic_ffs(log_page_size) - 1;
+	log_page_bits = ntfs_ffs(log_page_size) - 1;
 	size &= ~(s64)(log_page_size - 1);
 	/*
 	 * Ensure the log file is big enough to store at least the two restart
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
index 4e72bc7..2438c00 100644
--- a/fs/ntfs/mft.c
+++ b/fs/ntfs/mft.c
@@ -2670,7 +2670,7 @@
 			ni->name_len = 4;
 
 			ni->itype.index.block_size = 4096;
-			ni->itype.index.block_size_bits = generic_ffs(4096) - 1;
+			ni->itype.index.block_size_bits = ntfs_ffs(4096) - 1;
 			ni->itype.index.collation_rule = COLLATION_FILE_NAME;
 			if (vol->cluster_size <= ni->itype.index.block_size) {
 				ni->itype.index.vcn_size = vol->cluster_size;
diff --git a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h
index 0624c8e..bf7b3d7 100644
--- a/fs/ntfs/ntfs.h
+++ b/fs/ntfs/ntfs.h
@@ -60,13 +60,13 @@
 extern struct address_space_operations ntfs_aops;
 extern struct address_space_operations ntfs_mst_aops;
 
-extern struct  file_operations ntfs_file_ops;
+extern const struct  file_operations ntfs_file_ops;
 extern struct inode_operations ntfs_file_inode_ops;
 
-extern struct  file_operations ntfs_dir_ops;
+extern const struct  file_operations ntfs_dir_ops;
 extern struct inode_operations ntfs_dir_inode_ops;
 
-extern struct  file_operations ntfs_empty_file_ops;
+extern const struct  file_operations ntfs_empty_file_ops;
 extern struct inode_operations ntfs_empty_inode_ops;
 
 extern struct export_operations ntfs_export_ops;
@@ -132,4 +132,33 @@
 /* From fs/ntfs/upcase.c */
 extern ntfschar *generate_default_upcase(void);
 
+static inline int ntfs_ffs(int x)
+{
+	int r = 1;
+
+	if (!x)
+		return 0;
+	if (!(x & 0xffff)) {
+		x >>= 16;
+		r += 16;
+	}
+	if (!(x & 0xff)) {
+		x >>= 8;
+		r += 8;
+	}
+	if (!(x & 0xf)) {
+		x >>= 4;
+		r += 4;
+	}
+	if (!(x & 3)) {
+		x >>= 2;
+		r += 2;
+	}
+	if (!(x & 1)) {
+		x >>= 1;
+		r += 1;
+	}
+	return r;
+}
+
 #endif /* _LINUX_NTFS_H */
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index bf931ba..0d858d0 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -540,7 +540,6 @@
  * 					fs_count, map_bh, dio->rw == WRITE);
  */
 static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
-				     unsigned long max_blocks,
 				     struct buffer_head *bh_result, int create)
 {
 	int ret;
@@ -548,6 +547,7 @@
 	u64 p_blkno;
 	int contig_blocks;
 	unsigned char blocksize_bits;
+	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
 
 	if (!inode || !bh_result) {
 		mlog(ML_ERROR, "inode or bh_result is null\n");
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 84f153a..64cd528 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -2017,7 +2017,7 @@
 	return ret;
 }
 
-static struct file_operations ocfs2_dlm_debug_fops = {
+static const struct file_operations ocfs2_dlm_debug_fops = {
 	.open =		ocfs2_dlm_debug_open,
 	.release =	ocfs2_dlm_debug_release,
 	.read =		seq_read,
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 4b4cbad..34e903a 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1176,7 +1176,7 @@
 	.getattr	= ocfs2_getattr,
 };
 
-struct file_operations ocfs2_fops = {
+const struct file_operations ocfs2_fops = {
 	.read		= do_sync_read,
 	.write		= do_sync_write,
 	.sendfile	= generic_file_sendfile,
@@ -1188,7 +1188,7 @@
 	.aio_write	= ocfs2_file_aio_write,
 };
 
-struct file_operations ocfs2_dops = {
+const struct file_operations ocfs2_dops = {
 	.read		= generic_read_dir,
 	.readdir	= ocfs2_readdir,
 	.fsync		= ocfs2_sync_file,
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index a5ea33b..740c9e7 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -26,8 +26,8 @@
 #ifndef OCFS2_FILE_H
 #define OCFS2_FILE_H
 
-extern struct file_operations ocfs2_fops;
-extern struct file_operations ocfs2_dops;
+extern const struct file_operations ocfs2_fops;
+extern const struct file_operations ocfs2_dops;
 extern struct inode_operations ocfs2_file_iops;
 extern struct inode_operations ocfs2_special_file_iops;
 struct ocfs2_alloc_context;
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index ae3440c..6a610ae 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -377,7 +377,7 @@
 	BUG_ON(!bh);
 	BUG_ON(!(handle->flags & OCFS2_HANDLE_STARTED));
 
-	mlog_entry("bh->b_blocknr=%llu, type=%d (\"%s\"), bh->b_size = %hu\n",
+	mlog_entry("bh->b_blocknr=%llu, type=%d (\"%s\"), bh->b_size = %zu\n",
 		   (unsigned long long)bh->b_blocknr, type,
 		   (type == OCFS2_JOURNAL_ACCESS_CREATE) ?
 		   "OCFS2_JOURNAL_ACCESS_CREATE" :
@@ -582,7 +582,8 @@
 	}
 
 	mlog(0, "inode->i_size = %lld\n", inode->i_size);
-	mlog(0, "inode->i_blocks = %lu\n", inode->i_blocks);
+	mlog(0, "inode->i_blocks = %llu\n",
+			(unsigned long long)inode->i_blocks);
 	mlog(0, "inode->ip_clusters = %u\n", OCFS2_I(inode)->ip_clusters);
 
 	/* call the kernels journal init function now */
@@ -850,8 +851,9 @@
 
 	memset(bhs, 0, sizeof(struct buffer_head *) * CONCURRENT_JOURNAL_FILL);
 
-	mlog(0, "Force reading %lu blocks\n",
-	     (inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9)));
+	mlog(0, "Force reading %llu blocks\n",
+		(unsigned long long)(inode->i_blocks >>
+			(inode->i_sb->s_blocksize_bits - 9)));
 
 	v_blkno = 0;
 	while (v_blkno <
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 274f61d..0673862 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -1444,8 +1444,9 @@
 	 * write i_size + 1 bytes. */
 	blocks = (bytes_left + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
 
-	mlog_entry("i_blocks = %lu, i_size = %llu, blocks = %d\n",
-		       inode->i_blocks, i_size_read(inode), blocks);
+	mlog_entry("i_blocks = %llu, i_size = %llu, blocks = %d\n",
+			(unsigned long long)inode->i_blocks,
+			i_size_read(inode), blocks);
 
 	/* Sanity check -- make sure we're going to fit. */
 	if (bytes_left >
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index aeb0106..0f14276 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -581,17 +581,17 @@
 	return 0;
 }
 
-static struct file_operations openpromfs_prop_ops = {
+static const struct file_operations openpromfs_prop_ops = {
 	.read		= property_read,
 	.write		= property_write,
 	.release	= property_release,
 };
 
-static struct file_operations openpromfs_nodenum_ops = {
+static const struct file_operations openpromfs_nodenum_ops = {
 	.read		= nodenum_read,
 };
 
-static struct file_operations openprom_operations = {
+static const struct file_operations openprom_operations = {
 	.read		= generic_read_dir,
 	.readdir	= openpromfs_readdir,
 };
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index f924f45..af0cb4b 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -297,6 +297,25 @@
 	.sysfs_ops	= &part_sysfs_ops,
 };
 
+static inline void partition_sysfs_add_subdir(struct hd_struct *p)
+{
+	struct kobject *k;
+
+	k = kobject_get(&p->kobj);
+	p->holder_dir = kobject_add_dir(k, "holders");
+	kobject_put(k);
+}
+
+static inline void disk_sysfs_add_subdirs(struct gendisk *disk)
+{
+	struct kobject *k;
+
+	k = kobject_get(&disk->kobj);
+	disk->holder_dir = kobject_add_dir(k, "holders");
+	disk->slave_dir = kobject_add_dir(k, "slaves");
+	kobject_put(k);
+}
+
 void delete_partition(struct gendisk *disk, int part)
 {
 	struct hd_struct *p = disk->part[part-1];
@@ -310,6 +329,8 @@
 	p->ios[0] = p->ios[1] = 0;
 	p->sectors[0] = p->sectors[1] = 0;
 	devfs_remove("%s/part%d", disk->devfs_name, part);
+	if (p->holder_dir)
+		kobject_unregister(p->holder_dir);
 	kobject_unregister(&p->kobj);
 }
 
@@ -337,6 +358,7 @@
 	p->kobj.parent = &disk->kobj;
 	p->kobj.ktype = &ktype_part;
 	kobject_register(&p->kobj);
+	partition_sysfs_add_subdir(p);
 	disk->part[part-1] = p;
 }
 
@@ -383,6 +405,7 @@
 	if ((err = kobject_add(&disk->kobj)))
 		return;
 	disk_sysfs_symlinks(disk);
+ 	disk_sysfs_add_subdirs(disk);
 	kobject_uevent(&disk->kobj, KOBJ_ADD);
 
 	/* No minors to use for partitions */
@@ -483,6 +506,10 @@
 
 	devfs_remove_disk(disk);
 
+	if (disk->holder_dir)
+		kobject_unregister(disk->holder_dir);
+	if (disk->slave_dir)
+		kobject_unregister(disk->slave_dir);
 	if (disk->driverfs_dev) {
 		char *disk_name = make_block_name(disk);
 		sysfs_remove_link(&disk->kobj, "device");
diff --git a/fs/partitions/devfs.c b/fs/partitions/devfs.c
index 87f5044..3f0a780 100644
--- a/fs/partitions/devfs.c
+++ b/fs/partitions/devfs.c
@@ -6,7 +6,7 @@
 #include <linux/vmalloc.h>
 #include <linux/genhd.h>
 #include <linux/bitops.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 
 struct unique_numspace {
@@ -16,7 +16,7 @@
 	struct semaphore  mutex;
 };
 
-static DECLARE_MUTEX(numspace_mutex);
+static DEFINE_MUTEX(numspace_mutex);
 
 static int expand_numspace(struct unique_numspace *s)
 {
@@ -48,7 +48,7 @@
 {
 	int rval = 0;
 
-	down(&numspace_mutex);
+	mutex_lock(&numspace_mutex);
 	if (s->num_free < 1)
 		rval = expand_numspace(s);
 	if (!rval) {
@@ -56,7 +56,7 @@
 		--s->num_free;
 		__set_bit(rval, s->bits);
 	}
-	up(&numspace_mutex);
+	mutex_unlock(&numspace_mutex);
 
 	return rval;
 }
@@ -66,11 +66,11 @@
 	int old_val;
 
 	if (number >= 0) {
-		down(&numspace_mutex);
+		mutex_lock(&numspace_mutex);
 		old_val = __test_and_clear_bit(number, s->bits);
 		if (old_val)
 			++s->num_free;
-		up(&numspace_mutex);
+		mutex_unlock(&numspace_mutex);
 	}
 }
 
diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c
index bb22cdd..813292f 100644
--- a/fs/partitions/mac.c
+++ b/fs/partitions/mac.c
@@ -12,6 +12,7 @@
 #include "mac.h"
 
 #ifdef CONFIG_PPC_PMAC
+#include <asm/machdep.h>
 extern void note_bootable_part(dev_t dev, int part, int goodness);
 #endif
 
@@ -79,7 +80,7 @@
 		 * If this is the first bootable partition, tell the
 		 * setup code, in case it wants to make this the root.
 		 */
-		if (_machine == _MACH_Pmac) {
+		if (machine_is(powermac)) {
 			int goodness = 0;
 
 			mac_fix_string(part->processor, 16);
diff --git a/fs/pipe.c b/fs/pipe.c
index d976866..109a102 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -15,6 +15,7 @@
 #include <linux/pipe_fs_i.h>
 #include <linux/uio.h>
 #include <linux/highmem.h>
+#include <linux/pagemap.h>
 
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
@@ -94,11 +95,20 @@
 {
 	struct page *page = buf->page;
 
-	if (info->tmp_page) {
-		__free_page(page);
+	/*
+	 * If nobody else uses this page, and we don't already have a
+	 * temporary page, let's keep track of it as a one-deep
+	 * allocation cache
+	 */
+	if (page_count(page) == 1 && !info->tmp_page) {
+		info->tmp_page = page;
 		return;
 	}
-	info->tmp_page = page;
+
+	/*
+	 * Otherwise just release our reference to it
+	 */
+	page_cache_release(page);
 }
 
 static void *anon_pipe_buf_map(struct file *file, struct pipe_inode_info *info, struct pipe_buffer *buf)
@@ -111,11 +121,19 @@
 	kunmap(buf->page);
 }
 
+static int anon_pipe_buf_steal(struct pipe_inode_info *info,
+			       struct pipe_buffer *buf)
+{
+	buf->stolen = 1;
+	return 0;
+}
+
 static struct pipe_buf_operations anon_pipe_buf_ops = {
 	.can_merge = 1,
 	.map = anon_pipe_buf_map,
 	.unmap = anon_pipe_buf_unmap,
 	.release = anon_pipe_buf_release,
+	.steal = anon_pipe_buf_steal,
 };
 
 static ssize_t
@@ -152,6 +170,11 @@
 				chars = total_len;
 
 			addr = ops->map(filp, info, buf);
+			if (IS_ERR(addr)) {
+				if (!ret)
+					ret = PTR_ERR(addr);
+				break;
+			}
 			error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars);
 			ops->unmap(info, buf);
 			if (unlikely(error)) {
@@ -254,8 +277,16 @@
 		struct pipe_buf_operations *ops = buf->ops;
 		int offset = buf->offset + buf->len;
 		if (ops->can_merge && offset + chars <= PAGE_SIZE) {
-			void *addr = ops->map(filp, info, buf);
-			int error = pipe_iov_copy_from_user(offset + addr, iov, chars);
+			void *addr;
+			int error;
+
+			addr = ops->map(filp, info, buf);
+			if (IS_ERR(addr)) {
+				error = PTR_ERR(addr);
+				goto out;
+			}
+			error = pipe_iov_copy_from_user(offset + addr, iov,
+							chars);
 			ops->unmap(info, buf);
 			ret = error;
 			do_wakeup = 1;
@@ -568,7 +599,7 @@
  * The file_operations structs are not static because they
  * are also used in linux/fs/fifo.c to do operations on FIFOs.
  */
-struct file_operations read_fifo_fops = {
+const struct file_operations read_fifo_fops = {
 	.llseek		= no_llseek,
 	.read		= pipe_read,
 	.readv		= pipe_readv,
@@ -580,7 +611,7 @@
 	.fasync		= pipe_read_fasync,
 };
 
-struct file_operations write_fifo_fops = {
+const struct file_operations write_fifo_fops = {
 	.llseek		= no_llseek,
 	.read		= bad_pipe_r,
 	.write		= pipe_write,
@@ -592,7 +623,7 @@
 	.fasync		= pipe_write_fasync,
 };
 
-struct file_operations rdwr_fifo_fops = {
+const struct file_operations rdwr_fifo_fops = {
 	.llseek		= no_llseek,
 	.read		= pipe_read,
 	.readv		= pipe_readv,
@@ -675,7 +706,7 @@
 	return NULL;
 }
 
-static struct vfsmount *pipe_mnt;
+static struct vfsmount *pipe_mnt __read_mostly;
 static int pipefs_delete_dentry(struct dentry *dentry)
 {
 	return 1;
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 7eb1bd7..7a76ad5 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -330,7 +330,6 @@
 	unsigned long  min_flt = 0,  maj_flt = 0;
 	cputime_t cutime, cstime, utime, stime;
 	unsigned long rsslim = 0;
-	DEFINE_KTIME(it_real_value);
 	struct task_struct *t;
 	char tcomm[sizeof(task->comm)];
 
@@ -386,7 +385,6 @@
 			utime = cputime_add(utime, task->signal->utime);
 			stime = cputime_add(stime, task->signal->stime);
 		}
-		it_real_value = task->signal->real_timer.expires;
 	}
 	ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0;
 	read_unlock(&tasklist_lock);
@@ -413,7 +411,7 @@
 	start_time = nsec_to_clock_t(start_time);
 
 	res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
-%lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \
+%lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
 %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n",
 		task->pid,
 		tcomm,
@@ -435,7 +433,6 @@
 		priority,
 		nice,
 		num_threads,
-		(long) ktime_to_clock_t(it_real_value),
 		start_time,
 		vsize,
 		mm ? get_mm_rss(mm) : 0,
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 8f1f49c..a3a3eec 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -534,12 +534,15 @@
 
 /* If the process being read is separated by chroot from the reading process,
  * don't let the reader access the threads.
+ *
+ * note: this does dput(root) and mntput(vfsmnt) on exit.
  */
 static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt)
 {
 	struct dentry *de, *base;
 	struct vfsmount *our_vfsmnt, *mnt;
 	int res = 0;
+
 	read_lock(&current->fs->lock);
 	our_vfsmnt = mntget(current->fs->rootmnt);
 	base = dget(current->fs->root);
@@ -549,11 +552,11 @@
 	de = root;
 	mnt = vfsmnt;
 
-	while (vfsmnt != our_vfsmnt) {
-		if (vfsmnt == vfsmnt->mnt_parent)
+	while (mnt != our_vfsmnt) {
+		if (mnt == mnt->mnt_parent)
 			goto out;
-		de = vfsmnt->mnt_mountpoint;
-		vfsmnt = vfsmnt->mnt_parent;
+		de = mnt->mnt_mountpoint;
+		mnt = mnt->mnt_parent;
 	}
 
 	if (!is_subdir(de, base))
@@ -564,7 +567,7 @@
 	dput(base);
 	mntput(our_vfsmnt);
 	dput(root);
-	mntput(mnt);
+	mntput(vfsmnt);
 	return res;
 out:
 	spin_unlock(&vfsmount_lock);
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 20e5c45..4ba0300 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -19,6 +19,7 @@
 #include <linux/idr.h>
 #include <linux/namei.h>
 #include <linux/bitops.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
 #include "internal.h"
@@ -29,6 +30,8 @@
 			       size_t count, loff_t *ppos);
 static loff_t proc_file_lseek(struct file *, loff_t, int);
 
+DEFINE_SPINLOCK(proc_subdir_lock);
+
 int proc_match(int len, const char *name, struct proc_dir_entry *de)
 {
 	if (de->namelen != len)
@@ -277,7 +280,9 @@
 	const char     		*cp = name, *next;
 	struct proc_dir_entry	*de;
 	int			len;
+	int 			rtn = 0;
 
+	spin_lock(&proc_subdir_lock);
 	de = &proc_root;
 	while (1) {
 		next = strchr(cp, '/');
@@ -289,13 +294,17 @@
 			if (proc_match(len, cp, de))
 				break;
 		}
-		if (!de)
-			return -ENOENT;
+		if (!de) {
+			rtn = -ENOENT;
+			goto out;
+		}
 		cp += len + 1;
 	}
 	*residual = cp;
 	*ret = de;
-	return 0;
+out:
+	spin_unlock(&proc_subdir_lock);
+	return rtn;
 }
 
 static DEFINE_IDR(proc_inum_idr);
@@ -380,6 +389,7 @@
 	int error = -ENOENT;
 
 	lock_kernel();
+	spin_lock(&proc_subdir_lock);
 	de = PDE(dir);
 	if (de) {
 		for (de = de->subdir; de ; de = de->next) {
@@ -388,12 +398,15 @@
 			if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
 				unsigned int ino = de->low_ino;
 
+				spin_unlock(&proc_subdir_lock);
 				error = -EINVAL;
 				inode = proc_get_inode(dir->i_sb, ino, de);
+				spin_lock(&proc_subdir_lock);
 				break;
 			}
 		}
 	}
+	spin_unlock(&proc_subdir_lock);
 	unlock_kernel();
 
 	if (inode) {
@@ -447,11 +460,13 @@
 			filp->f_pos++;
 			/* fall through */
 		default:
+			spin_lock(&proc_subdir_lock);
 			de = de->subdir;
 			i -= 2;
 			for (;;) {
 				if (!de) {
 					ret = 1;
+					spin_unlock(&proc_subdir_lock);
 					goto out;
 				}
 				if (!i)
@@ -461,12 +476,16 @@
 			}
 
 			do {
+				/* filldir passes info to user space */
+				spin_unlock(&proc_subdir_lock);
 				if (filldir(dirent, de->name, de->namelen, filp->f_pos,
 					    de->low_ino, de->mode >> 12) < 0)
 					goto out;
+				spin_lock(&proc_subdir_lock);
 				filp->f_pos++;
 				de = de->next;
 			} while (de);
+			spin_unlock(&proc_subdir_lock);
 	}
 	ret = 1;
 out:	unlock_kernel();
@@ -500,9 +519,13 @@
 	if (i == 0)
 		return -EAGAIN;
 	dp->low_ino = i;
+
+	spin_lock(&proc_subdir_lock);
 	dp->next = dir->subdir;
 	dp->parent = dir;
 	dir->subdir = dp;
+	spin_unlock(&proc_subdir_lock);
+
 	if (S_ISDIR(dp->mode)) {
 		if (dp->proc_iops == NULL) {
 			dp->proc_fops = &proc_dir_operations;
@@ -537,7 +560,7 @@
 		struct file * filp = list_entry(p, struct file, f_u.fu_list);
 		struct dentry * dentry = filp->f_dentry;
 		struct inode * inode;
-		struct file_operations *fops;
+		const struct file_operations *fops;
 
 		if (dentry->d_op != &proc_dentry_operations)
 			continue;
@@ -694,6 +717,8 @@
 	if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
 		goto out;
 	len = strlen(fn);
+
+	spin_lock(&proc_subdir_lock);
 	for (p = &parent->subdir; *p; p=&(*p)->next ) {
 		if (!proc_match(len, fn, *p))
 			continue;
@@ -714,6 +739,7 @@
 		}
 		break;
 	}
+	spin_unlock(&proc_subdir_lock);
 out:
 	return;
 }
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 95a1cf3..0502f17 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -30,7 +30,7 @@
 
 #endif
 
-extern void create_seq_entry(char *name, mode_t mode, struct file_operations *f);
+extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f);
 extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **);
 extern int proc_tid_stat(struct task_struct *,  char *);
 extern int proc_tgid_stat(struct task_struct *, char *);
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index adc2cd9..17f6e8f 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -31,7 +31,7 @@
 
 static ssize_t read_kcore(struct file *, char __user *, size_t, loff_t *);
 
-struct file_operations proc_kcore_operations = {
+const struct file_operations proc_kcore_operations = {
 	.read		= read_kcore,
 	.open		= open_kcore,
 };
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
index 10d37bf..ff3b90b 100644
--- a/fs/proc/kmsg.c
+++ b/fs/proc/kmsg.c
@@ -47,7 +47,7 @@
 }
 
 
-struct file_operations proc_kmsg_operations = {
+const struct file_operations proc_kmsg_operations = {
 	.read		= kmsg_read,
 	.poll		= kmsg_poll,
 	.open		= kmsg_open,
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index 9bdd077..abdf068 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -52,7 +52,8 @@
  * Add a property to a node
  */
 static struct proc_dir_entry *
-__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp)
+__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp,
+		const char *name)
 {
 	struct proc_dir_entry *ent;
 
@@ -60,14 +61,14 @@
 	 * Unfortunately proc_register puts each new entry
 	 * at the beginning of the list.  So we rearrange them.
 	 */
-	ent = create_proc_read_entry(pp->name,
-				     strncmp(pp->name, "security-", 9)
+	ent = create_proc_read_entry(name,
+				     strncmp(name, "security-", 9)
 				     ? S_IRUGO : S_IRUSR, de,
 				     property_read_proc, pp);
 	if (ent == NULL)
 		return NULL;
 
-	if (!strncmp(pp->name, "security-", 9))
+	if (!strncmp(name, "security-", 9))
 		ent->size = 0; /* don't leak number of password chars */
 	else
 		ent->size = pp->length;
@@ -78,7 +79,7 @@
 
 void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop)
 {
-	__proc_device_tree_add_prop(pde, prop);
+	__proc_device_tree_add_prop(pde, prop, prop->name);
 }
 
 void proc_device_tree_remove_prop(struct proc_dir_entry *pde,
@@ -106,6 +107,69 @@
 }
 
 /*
+ * Various dodgy firmware might give us nodes and/or properties with
+ * conflicting names. That's generally ok, except for exporting via /proc,
+ * so munge names here to ensure they're unique.
+ */
+
+static int duplicate_name(struct proc_dir_entry *de, const char *name)
+{
+	struct proc_dir_entry *ent;
+	int found = 0;
+
+	spin_lock(&proc_subdir_lock);
+
+	for (ent = de->subdir; ent != NULL; ent = ent->next) {
+		if (strcmp(ent->name, name) == 0) {
+			found = 1;
+			break;
+		}
+	}
+
+	spin_unlock(&proc_subdir_lock);
+
+	return found;
+}
+
+static const char *fixup_name(struct device_node *np, struct proc_dir_entry *de,
+		const char *name)
+{
+	char *fixed_name;
+	int fixup_len = strlen(name) + 2 + 1; /* name + #x + \0 */
+	int i = 1, size;
+
+realloc:
+	fixed_name = kmalloc(fixup_len, GFP_KERNEL);
+	if (fixed_name == NULL) {
+		printk(KERN_ERR "device-tree: Out of memory trying to fixup "
+				"name \"%s\"\n", name);
+		return name;
+	}
+
+retry:
+	size = snprintf(fixed_name, fixup_len, "%s#%d", name, i);
+	size++; /* account for NULL */
+
+	if (size > fixup_len) {
+		/* We ran out of space, free and reallocate. */
+		kfree(fixed_name);
+		fixup_len = size;
+		goto realloc;
+	}
+
+	if (duplicate_name(de, fixed_name)) {
+		/* Multiple duplicates. Retry with a different offset. */
+		i++;
+		goto retry;
+	}
+
+	printk(KERN_WARNING "device-tree: Duplicate name in %s, "
+			"renamed to \"%s\"\n", np->full_name, fixed_name);
+
+	return fixed_name;
+}
+
+/*
  * Process a node, adding entries for its children and its properties.
  */
 void proc_device_tree_add_node(struct device_node *np,
@@ -118,35 +182,30 @@
 
 	set_node_proc_entry(np, de);
 	for (child = NULL; (child = of_get_next_child(np, child));) {
+		/* Use everything after the last slash, or the full name */
 		p = strrchr(child->full_name, '/');
 		if (!p)
 			p = child->full_name;
 		else
 			++p;
+
+		if (duplicate_name(de, p))
+			p = fixup_name(np, de, p);
+
 		ent = proc_mkdir(p, de);
 		if (ent == 0)
 			break;
 		proc_device_tree_add_node(child, ent);
 	}
 	of_node_put(child);
-	for (pp = np->properties; pp != 0; pp = pp->next) {
-		/*
-		 * Yet another Apple device-tree bogosity: on some machines,
-		 * they have properties & nodes with the same name. Those
-		 * properties are quite unimportant for us though, thus we
-		 * simply "skip" them here, but we do have to check.
-		 */
-		for (ent = de->subdir; ent != NULL; ent = ent->next)
-			if (!strcmp(ent->name, pp->name))
-				break;
-		if (ent != NULL) {
-			printk(KERN_WARNING "device-tree: property \"%s\" name"
-			       " conflicts with node in %s\n", pp->name,
-			       np->full_name);
-			continue;
-		}
 
-		ent = __proc_device_tree_add_prop(de, pp);
+	for (pp = np->properties; pp != 0; pp = pp->next) {
+		p = pp->name;
+
+		if (duplicate_name(de, p))
+			p = fixup_name(np, de, p);
+
+		ent = __proc_device_tree_add_prop(de, pp, p);
 		if (ent == 0)
 			break;
 	}
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 1e9ea37..5c10ea1 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -249,155 +249,64 @@
 	return seq_open(file, &cpuinfo_op);
 }
 
-enum devinfo_states {
-	CHR_HDR,
-	CHR_LIST,
-	BLK_HDR,
-	BLK_LIST,
-	DEVINFO_DONE
-};
-
-struct devinfo_state {
-	void *chrdev;
-	void *blkdev;
-	unsigned int num_records;
-	unsigned int cur_record;
-	enum devinfo_states state;
-};
-
-static void *devinfo_start(struct seq_file *f, loff_t *pos)
-{
-	struct devinfo_state *info = f->private;
-
-	if (*pos) {
-		if ((info) && (*pos <= info->num_records))
-			return info;
-		return NULL;
-	}
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
-	f->private = info;
-	info->chrdev = acquire_chrdev_list();
-	info->blkdev = acquire_blkdev_list();
-	info->state = CHR_HDR;
-	info->num_records = count_chrdev_list();
-	info->num_records += count_blkdev_list();
-	info->num_records += 2; /* Character and Block headers */
-	*pos = 1;
-	info->cur_record = *pos;
-	return info;
-}
-
-static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos)
-{
-	int idummy;
-	char *ndummy;
-	struct devinfo_state *info = f->private;
-
-	switch (info->state) {
-		case CHR_HDR:
-			info->state = CHR_LIST;
-			(*pos)++;
-			/*fallthrough*/
-		case CHR_LIST:
-			if (get_chrdev_info(info->chrdev,&idummy,&ndummy)) {
-				/*
-				 * The character dev list is complete
-				 */
-				info->state = BLK_HDR;
-			} else {
-				info->chrdev = get_next_chrdev(info->chrdev);
-			}
-			(*pos)++;
-			break;
-		case BLK_HDR:
-			info->state = BLK_LIST;
-			(*pos)++;
-			/*fallthrough*/
-		case BLK_LIST:
-			if (get_blkdev_info(info->blkdev,&idummy,&ndummy)) {
-				/*
-				 * The block dev list is complete
-				 */
-				info->state = DEVINFO_DONE;
-			} else {
-				info->blkdev = get_next_blkdev(info->blkdev);
-			}
-			(*pos)++;
-			break;
-		case DEVINFO_DONE:
-			(*pos)++;
-			info->cur_record = *pos;
-			info = NULL;
-			break;
-		default:
-			break;
-	}
-	if (info)
-		info->cur_record = *pos;
-	return info;
-}
-
-static void devinfo_stop(struct seq_file *f, void *v)
-{
-	struct devinfo_state *info = f->private;
-
-	if (info) {
-		release_chrdev_list(info->chrdev);
-		release_blkdev_list(info->blkdev);
-		f->private = NULL;
-		kfree(info);
-	}
-}
-
-static int devinfo_show(struct seq_file *f, void *arg)
-{
-	int major;
-	char *name;
-	struct devinfo_state *info = f->private;
-
-	switch(info->state) {
-		case CHR_HDR:
-			seq_printf(f,"Character devices:\n");
-			/* fallthrough */
-		case CHR_LIST:
-			if (!get_chrdev_info(info->chrdev,&major,&name))
-				seq_printf(f,"%3d %s\n",major,name);
-			break;
-		case BLK_HDR:
-			seq_printf(f,"\nBlock devices:\n");
-			/* fallthrough */
-		case BLK_LIST:
-			if (!get_blkdev_info(info->blkdev,&major,&name))
-				seq_printf(f,"%3d %s\n",major,name);
-			break;
-		default:
-			break;
-	}
-
-	return 0;
-}
-
-static  struct seq_operations devinfo_op = {
-	.start  = devinfo_start,
-	.next   = devinfo_next,
-	.stop   = devinfo_stop,
-	.show   = devinfo_show,
-};
-
-static int devinfo_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &devinfo_op);
-}
-
-static struct file_operations proc_devinfo_operations = {
-	.open		= devinfo_open,
+static struct file_operations proc_cpuinfo_operations = {
+	.open		= cpuinfo_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
 	.release	= seq_release,
 };
 
-static struct file_operations proc_cpuinfo_operations = {
-	.open		= cpuinfo_open,
+static int devinfo_show(struct seq_file *f, void *v)
+{
+	int i = *(loff_t *) v;
+
+	if (i < CHRDEV_MAJOR_HASH_SIZE) {
+		if (i == 0)
+			seq_printf(f, "Character devices:\n");
+		chrdev_show(f, i);
+	} else {
+		i -= CHRDEV_MAJOR_HASH_SIZE;
+		if (i == 0)
+			seq_printf(f, "\nBlock devices:\n");
+		blkdev_show(f, i);
+	}
+	return 0;
+}
+
+static void *devinfo_start(struct seq_file *f, loff_t *pos)
+{
+	if (*pos < (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE))
+		return pos;
+	return NULL;
+}
+
+static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos)
+{
+	(*pos)++;
+	if (*pos >= (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE))
+		return NULL;
+	return pos;
+}
+
+static void devinfo_stop(struct seq_file *f, void *v)
+{
+	/* Nothing to do */
+}
+
+static struct seq_operations devinfo_ops = {
+	.start = devinfo_start,
+	.next  = devinfo_next,
+	.stop  = devinfo_stop,
+	.show  = devinfo_show
+};
+
+static int devinfo_open(struct inode *inode, struct file *filp)
+{
+	return seq_open(filp, &devinfo_ops);
+}
+
+static struct file_operations proc_devinfo_operations = {
+	.open		= devinfo_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
 	.release	= seq_release,
@@ -534,7 +443,7 @@
 	if (wall_to_monotonic.tv_nsec)
 		--jif;
 
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		int j;
 
 		user = cputime64_add(user, kstat_cpu(i).cpustat.user);
@@ -731,7 +640,7 @@
 
 struct proc_dir_entry *proc_root_kcore;
 
-void create_seq_entry(char *name, mode_t mode, struct file_operations *f)
+void create_seq_entry(char *name, mode_t mode, const struct file_operations *f)
 {
 	struct proc_dir_entry *entry;
 	entry = create_proc_entry(name, mode, NULL);
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 4063fb3..7efa73d 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -172,7 +172,7 @@
 	return 0;
 }
 
-struct file_operations proc_vmcore_operations = {
+const struct file_operations proc_vmcore_operations = {
 	.read		= read_vmcore,
 	.open		= open_vmcore,
 };
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c
index 7a8f559..9031948 100644
--- a/fs/qnx4/dir.c
+++ b/fs/qnx4/dir.c
@@ -81,7 +81,7 @@
 	return 0;
 }
 
-struct file_operations qnx4_dir_operations =
+const struct file_operations qnx4_dir_operations =
 {
 	.read		= generic_read_dir,
 	.readdir	= qnx4_readdir,
diff --git a/fs/qnx4/file.c b/fs/qnx4/file.c
index c33963f..62af4b1 100644
--- a/fs/qnx4/file.c
+++ b/fs/qnx4/file.c
@@ -19,7 +19,7 @@
  * We have mostly NULL's here: the current defaults are ok for
  * the qnx4 filesystem.
  */
-struct file_operations qnx4_file_operations =
+const struct file_operations qnx4_file_operations =
 {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
index 6ada209..00a933e 100644
--- a/fs/ramfs/file-mmu.c
+++ b/fs/ramfs/file-mmu.c
@@ -32,7 +32,7 @@
 	.commit_write	= simple_commit_write
 };
 
-struct file_operations ramfs_file_operations = {
+const struct file_operations ramfs_file_operations = {
 	.read		= generic_file_read,
 	.write		= generic_file_write,
 	.mmap		= generic_file_mmap,
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index b1ca234..f443a84 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -33,7 +33,7 @@
 	.commit_write		= simple_commit_write
 };
 
-struct file_operations ramfs_file_operations = {
+const struct file_operations ramfs_file_operations = {
 	.mmap			= ramfs_nommu_mmap,
 	.get_unmapped_area	= ramfs_nommu_get_unmapped_area,
 	.read			= generic_file_read,
diff --git a/fs/ramfs/internal.h b/fs/ramfs/internal.h
index 272c8a7..3132376 100644
--- a/fs/ramfs/internal.h
+++ b/fs/ramfs/internal.h
@@ -11,5 +11,5 @@
 
 
 extern struct address_space_operations ramfs_aops;
-extern struct file_operations ramfs_file_operations;
+extern const struct file_operations ramfs_file_operations;
 extern struct inode_operations ramfs_file_inode_operations;
diff --git a/fs/read_write.c b/fs/read_write.c
index 34b1bf2..6256ca8 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -19,7 +19,7 @@
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 
-struct file_operations generic_ro_fops = {
+const struct file_operations generic_ro_fops = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
 	.mmap		= generic_file_readonly_mmap,
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index d71ac65..973c819 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -18,7 +18,7 @@
 static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
 			      int datasync);
 
-struct file_operations reiserfs_dir_operations = {
+const struct file_operations reiserfs_dir_operations = {
 	.read = generic_read_dir,
 	.readdir = reiserfs_readdir,
 	.fsync = reiserfs_dir_fsync,
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index d0c1e86..cf6e1cf 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -1566,7 +1566,7 @@
 	return generic_file_aio_write(iocb, buf, count, pos);
 }
 
-struct file_operations reiserfs_file_operations = {
+const struct file_operations reiserfs_file_operations = {
 	.read = generic_file_read,
 	.write = reiserfs_file_write,
 	.ioctl = reiserfs_ioctl,
@@ -1576,6 +1576,8 @@
 	.sendfile = generic_file_sendfile,
 	.aio_read = generic_file_aio_read,
 	.aio_write = reiserfs_aio_write,
+	.splice_read = generic_file_splice_read,
+	.splice_write = generic_file_splice_write,
 };
 
 struct inode_operations reiserfs_file_inode_operations = {
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index d60f623..9857e50 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -466,7 +466,6 @@
    direct_IO request. */
 static int reiserfs_get_blocks_direct_io(struct inode *inode,
 					 sector_t iblock,
-					 unsigned long max_blocks,
 					 struct buffer_head *bh_result,
 					 int create)
 {
@@ -2793,7 +2792,7 @@
 }
 
 /* clm -- taken from fs/buffer.c:block_invalidate_page */
-static int reiserfs_invalidatepage(struct page *page, unsigned long offset)
+static void reiserfs_invalidatepage(struct page *page, unsigned long offset)
 {
 	struct buffer_head *head, *bh, *next;
 	struct inode *inode = page->mapping->host;
@@ -2832,10 +2831,12 @@
 	 * The get_block cached value has been unconditionally invalidated,
 	 * so real IO is not possible anymore.
 	 */
-	if (!offset && ret)
+	if (!offset && ret) {
 		ret = try_to_release_page(page, 0);
+		/* maybe should BUG_ON(!ret); - neilb */
+	}
       out:
-	return ret;
+	return;
 }
 
 static int reiserfs_set_page_dirty(struct page *page)
diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
index 78b4062..27bd3a1 100644
--- a/fs/reiserfs/prints.c
+++ b/fs/reiserfs/prints.c
@@ -143,7 +143,7 @@
 	char b[BDEVNAME_SIZE];
 
 	sprintf(buf,
-		"dev %s, size %d, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)",
+		"dev %s, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)",
 		bdevname(bh->b_bdev, b), bh->b_size,
 		(unsigned long long)bh->b_blocknr, atomic_read(&(bh->b_count)),
 		bh->b_state, bh->b_page,
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index ef6caed..731688e 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -470,7 +470,7 @@
 	return ret;
 }
 
-static struct file_operations r_file_operations = {
+static const struct file_operations r_file_operations = {
 	.open = r_open,
 	.read = seq_read,
 	.llseek = seq_lseek,
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index c2fc424..9b9eda7 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -463,7 +463,7 @@
 	.readpage = romfs_readpage
 };
 
-static struct file_operations romfs_dir_operations = {
+static const struct file_operations romfs_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= romfs_readdir,
 };
diff --git a/fs/select.c b/fs/select.c
index 1815a57..071660f 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -29,12 +29,6 @@
 #define ROUND_UP(x,y) (((x)+(y)-1)/(y))
 #define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
 
-struct poll_table_entry {
-	struct file * filp;
-	wait_queue_t wait;
-	wait_queue_head_t * wait_address;
-};
-
 struct poll_table_page {
 	struct poll_table_page * next;
 	struct poll_table_entry * entry;
@@ -64,13 +58,23 @@
 	init_poll_funcptr(&pwq->pt, __pollwait);
 	pwq->error = 0;
 	pwq->table = NULL;
+	pwq->inline_index = 0;
 }
 
 EXPORT_SYMBOL(poll_initwait);
 
+static void free_poll_entry(struct poll_table_entry *entry)
+{
+	remove_wait_queue(entry->wait_address,&entry->wait);
+	fput(entry->filp);
+}
+
 void poll_freewait(struct poll_wqueues *pwq)
 {
 	struct poll_table_page * p = pwq->table;
+	int i;
+	for (i = 0; i < pwq->inline_index; i++)
+		free_poll_entry(pwq->inline_entries + i);
 	while (p) {
 		struct poll_table_entry * entry;
 		struct poll_table_page *old;
@@ -78,8 +82,7 @@
 		entry = p->entry;
 		do {
 			entry--;
-			remove_wait_queue(entry->wait_address,&entry->wait);
-			fput(entry->filp);
+			free_poll_entry(entry);
 		} while (entry > p->entries);
 		old = p;
 		p = p->next;
@@ -89,12 +92,14 @@
 
 EXPORT_SYMBOL(poll_freewait);
 
-static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
-		       poll_table *_p)
+static struct poll_table_entry *poll_get_entry(poll_table *_p)
 {
 	struct poll_wqueues *p = container_of(_p, struct poll_wqueues, pt);
 	struct poll_table_page *table = p->table;
 
+	if (p->inline_index < N_INLINE_POLL_ENTRIES)
+		return p->inline_entries + p->inline_index++;
+
 	if (!table || POLL_TABLE_FULL(table)) {
 		struct poll_table_page *new_table;
 
@@ -102,7 +107,7 @@
 		if (!new_table) {
 			p->error = -ENOMEM;
 			__set_current_state(TASK_RUNNING);
-			return;
+			return NULL;
 		}
 		new_table->entry = new_table->entries;
 		new_table->next = table;
@@ -110,16 +115,21 @@
 		table = new_table;
 	}
 
-	/* Add a new entry */
-	{
-		struct poll_table_entry * entry = table->entry;
-		table->entry = entry+1;
-	 	get_file(filp);
-	 	entry->filp = filp;
-		entry->wait_address = wait_address;
-		init_waitqueue_entry(&entry->wait, current);
-		add_wait_queue(wait_address,&entry->wait);
-	}
+	return table->entry++;
+}
+
+/* Add a new entry */
+static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
+				poll_table *p)
+{
+	struct poll_table_entry *entry = poll_get_entry(p);
+	if (!entry)
+		return;
+	get_file(filp);
+	entry->filp = filp;
+	entry->wait_address = wait_address;
+	init_waitqueue_entry(&entry->wait, current);
+	add_wait_queue(wait_address,&entry->wait);
 }
 
 #define FDS_IN(fds, n)		(fds->in + n)
@@ -210,7 +220,7 @@
 		for (i = 0; i < n; ++rinp, ++routp, ++rexp) {
 			unsigned long in, out, ex, all_bits, bit = 1, mask, j;
 			unsigned long res_in = 0, res_out = 0, res_ex = 0;
-			struct file_operations *f_op = NULL;
+			const struct file_operations *f_op = NULL;
 			struct file *file = NULL;
 
 			in = *inp++; out = *outp++; ex = *exp++;
@@ -221,17 +231,18 @@
 			}
 
 			for (j = 0; j < __NFDBITS; ++j, ++i, bit <<= 1) {
+				int fput_needed;
 				if (i >= n)
 					break;
 				if (!(bit & all_bits))
 					continue;
-				file = fget(i);
+				file = fget_light(i, &fput_needed);
 				if (file) {
 					f_op = file->f_op;
 					mask = DEFAULT_POLLMASK;
 					if (f_op && f_op->poll)
 						mask = (*f_op->poll)(file, retval ? NULL : wait);
-					fput(file);
+					fput_light(file, fput_needed);
 					if ((mask & POLLIN_SET) && (in & bit)) {
 						res_in |= bit;
 						retval++;
@@ -284,16 +295,6 @@
 	return retval;
 }
 
-static void *select_bits_alloc(int size)
-{
-	return kmalloc(6 * size, GFP_KERNEL);
-}
-
-static void select_bits_free(void *bits, int size)
-{
-	kfree(bits);
-}
-
 /*
  * We can actually return ERESTARTSYS instead of EINTR, but I'd
  * like to be certain this leads to no problems. So I return
@@ -312,6 +313,8 @@
 	char *bits;
 	int ret, size, max_fdset;
 	struct fdtable *fdt;
+	/* Allocate small arguments on the stack to save memory and be faster */
+	long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
 
 	ret = -EINVAL;
 	if (n < 0)
@@ -332,7 +335,10 @@
 	 */
 	ret = -ENOMEM;
 	size = FDS_BYTES(n);
-	bits = select_bits_alloc(size);
+	if (6*size < SELECT_STACK_ALLOC)
+		bits = stack_fds;
+	else
+		bits = kmalloc(6 * size, GFP_KERNEL);
 	if (!bits)
 		goto out_nofds;
 	fds.in      = (unsigned long *)  bits;
@@ -367,7 +373,8 @@
 		ret = -EFAULT;
 
 out:
-	select_bits_free(bits, size);
+	if (bits != stack_fds)
+		kfree(bits);
 out_nofds:
 	return ret;
 }
@@ -551,14 +558,15 @@
 		fdp = fdpage+i;
 		fd = fdp->fd;
 		if (fd >= 0) {
-			struct file * file = fget(fd);
+			int fput_needed;
+			struct file * file = fget_light(fd, &fput_needed);
 			mask = POLLNVAL;
 			if (file != NULL) {
 				mask = DEFAULT_POLLMASK;
 				if (file->f_op && file->f_op->poll)
 					mask = file->f_op->poll(file, *pwait);
 				mask &= fdp->events | POLLERR | POLLHUP;
-				fput(file);
+				fput_light(file, fput_needed);
 			}
 			if (mask) {
 				*pwait = NULL;
@@ -619,6 +627,9 @@
 	return count;
 }
 
+#define N_STACK_PPS ((sizeof(stack_pps) - sizeof(struct poll_list))  / \
+			sizeof(struct pollfd))
+
 int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
 {
 	struct poll_wqueues table;
@@ -628,6 +639,11 @@
  	struct poll_list *walk;
 	struct fdtable *fdt;
 	int max_fdset;
+	/* Allocate small arguments on the stack to save memory and be
+	   faster - use long to make sure the buffer is aligned properly
+	   on 64 bit archs to avoid unaligned access */
+	long stack_pps[POLL_STACK_ALLOC/sizeof(long)];
+	struct poll_list *stack_pp = NULL;
 
 	/* Do a sanity check on nfds ... */
 	rcu_read_lock();
@@ -645,14 +661,23 @@
 	err = -ENOMEM;
 	while(i!=0) {
 		struct poll_list *pp;
-		pp = kmalloc(sizeof(struct poll_list)+
-				sizeof(struct pollfd)*
-				(i>POLLFD_PER_PAGE?POLLFD_PER_PAGE:i),
-					GFP_KERNEL);
-		if(pp==NULL)
-			goto out_fds;
+		int num, size;
+		if (stack_pp == NULL)
+			num = N_STACK_PPS;
+		else
+			num = POLLFD_PER_PAGE;
+		if (num > i)
+			num = i;
+		size = sizeof(struct poll_list) + sizeof(struct pollfd)*num;
+		if (!stack_pp)
+			stack_pp = pp = (struct poll_list *)stack_pps;
+		else {
+			pp = kmalloc(size, GFP_KERNEL);
+			if (!pp)
+				goto out_fds;
+		}
 		pp->next=NULL;
-		pp->len = (i>POLLFD_PER_PAGE?POLLFD_PER_PAGE:i);
+		pp->len = num;
 		if (head == NULL)
 			head = pp;
 		else
@@ -660,7 +685,7 @@
 
 		walk = pp;
 		if (copy_from_user(pp->entries, ufds + nfds-i, 
-				sizeof(struct pollfd)*pp->len)) {
+				sizeof(struct pollfd)*num)) {
 			err = -EFAULT;
 			goto out_fds;
 		}
@@ -689,7 +714,8 @@
 	walk = head;
 	while(walk!=NULL) {
 		struct poll_list *pp = walk->next;
-		kfree(walk);
+		if (walk != stack_pp)
+			kfree(walk);
 		walk = pp;
 	}
 	poll_freewait(&table);
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 0424d06..34c7a11 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -34,7 +34,7 @@
 static int smb_make_node(struct inode *,struct dentry *,int,dev_t);
 static int smb_link(struct dentry *, struct inode *, struct dentry *);
 
-struct file_operations smb_dir_operations =
+const struct file_operations smb_dir_operations =
 {
 	.read		= generic_read_dir,
 	.readdir	= smb_readdir,
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index 7042e62..c56bd99 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -401,7 +401,7 @@
 	return error;
 }
 
-struct file_operations smb_file_operations =
+const struct file_operations smb_file_operations =
 {
 	.llseek		= remote_llseek,
 	.read		= smb_file_read,
diff --git a/fs/smbfs/proto.h b/fs/smbfs/proto.h
index e866ec8..4766459 100644
--- a/fs/smbfs/proto.h
+++ b/fs/smbfs/proto.h
@@ -35,7 +35,7 @@
 extern int smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, struct dentry *new_dentry);
 extern void smb_install_null_ops(struct smb_ops *ops);
 /* dir.c */
-extern struct file_operations smb_dir_operations;
+extern const struct file_operations smb_dir_operations;
 extern struct inode_operations smb_dir_inode_operations;
 extern struct inode_operations smb_dir_inode_operations_unix;
 extern void smb_new_dentry(struct dentry *dentry);
@@ -64,7 +64,7 @@
 extern int smb_notify_change(struct dentry *dentry, struct iattr *attr);
 /* file.c */
 extern struct address_space_operations smb_file_aops;
-extern struct file_operations smb_file_operations;
+extern const struct file_operations smb_file_operations;
 extern struct inode_operations smb_file_inode_operations;
 /* ioctl.c */
 extern int smb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
diff --git a/fs/splice.c b/fs/splice.c
new file mode 100644
index 0000000..7c2bbf1
--- /dev/null
+++ b/fs/splice.c
@@ -0,0 +1,663 @@
+/*
+ * "splice": joining two ropes together by interweaving their strands.
+ *
+ * This is the "extended pipe" functionality, where a pipe is used as
+ * an arbitrary in-memory buffer. Think of a pipe as a small kernel
+ * buffer that you can use to transfer data from one end to the other.
+ *
+ * The traditional unix read/write is extended with a "splice()" operation
+ * that transfers data buffers to or from a pipe buffer.
+ *
+ * Named by Larry McVoy, original implementation from Linus, extended by
+ * Jens to support splicing to files and fixing the initial implementation
+ * bugs.
+ *
+ * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2005 Linus Torvalds <torvalds@osdl.org>
+ *
+ */
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/pagemap.h>
+#include <linux/pipe_fs_i.h>
+#include <linux/mm_inline.h>
+#include <linux/swap.h>
+#include <linux/module.h>
+
+/*
+ * Passed to the actors
+ */
+struct splice_desc {
+	unsigned int len, total_len;	/* current and remaining length */
+	unsigned int flags;		/* splice flags */
+	struct file *file;		/* file to read/write */
+	loff_t pos;			/* file position */
+};
+
+static int page_cache_pipe_buf_steal(struct pipe_inode_info *info,
+				     struct pipe_buffer *buf)
+{
+	struct page *page = buf->page;
+
+	WARN_ON(!PageLocked(page));
+	WARN_ON(!PageUptodate(page));
+
+	if (!remove_mapping(page_mapping(page), page))
+		return 1;
+
+	if (PageLRU(page)) {
+		struct zone *zone = page_zone(page);
+
+		spin_lock_irq(&zone->lru_lock);
+		BUG_ON(!PageLRU(page));
+		__ClearPageLRU(page);
+		del_page_from_lru(zone, page);
+		spin_unlock_irq(&zone->lru_lock);
+	}
+
+	buf->stolen = 1;
+	return 0;
+}
+
+static void page_cache_pipe_buf_release(struct pipe_inode_info *info,
+					struct pipe_buffer *buf)
+{
+	page_cache_release(buf->page);
+	buf->page = NULL;
+	buf->stolen = 0;
+}
+
+static void *page_cache_pipe_buf_map(struct file *file,
+				     struct pipe_inode_info *info,
+				     struct pipe_buffer *buf)
+{
+	struct page *page = buf->page;
+
+	lock_page(page);
+
+	if (!PageUptodate(page)) {
+		unlock_page(page);
+		return ERR_PTR(-EIO);
+	}
+
+	if (!page->mapping) {
+		unlock_page(page);
+		return ERR_PTR(-ENODATA);
+	}
+
+	return kmap(buf->page);
+}
+
+static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info,
+				      struct pipe_buffer *buf)
+{
+	if (!buf->stolen)
+		unlock_page(buf->page);
+	kunmap(buf->page);
+}
+
+static struct pipe_buf_operations page_cache_pipe_buf_ops = {
+	.can_merge = 0,
+	.map = page_cache_pipe_buf_map,
+	.unmap = page_cache_pipe_buf_unmap,
+	.release = page_cache_pipe_buf_release,
+	.steal = page_cache_pipe_buf_steal,
+};
+
+static ssize_t move_to_pipe(struct inode *inode, struct page **pages,
+			    int nr_pages, unsigned long offset,
+			    unsigned long len)
+{
+	struct pipe_inode_info *info;
+	int ret, do_wakeup, i;
+
+	ret = 0;
+	do_wakeup = 0;
+	i = 0;
+
+	mutex_lock(PIPE_MUTEX(*inode));
+
+	info = inode->i_pipe;
+	for (;;) {
+		int bufs;
+
+		if (!PIPE_READERS(*inode)) {
+			send_sig(SIGPIPE, current, 0);
+			if (!ret)
+				ret = -EPIPE;
+			break;
+		}
+
+		bufs = info->nrbufs;
+		if (bufs < PIPE_BUFFERS) {
+			int newbuf = (info->curbuf + bufs) & (PIPE_BUFFERS - 1);
+			struct pipe_buffer *buf = info->bufs + newbuf;
+			struct page *page = pages[i++];
+			unsigned long this_len;
+
+			this_len = PAGE_CACHE_SIZE - offset;
+			if (this_len > len)
+				this_len = len;
+
+			buf->page = page;
+			buf->offset = offset;
+			buf->len = this_len;
+			buf->ops = &page_cache_pipe_buf_ops;
+			info->nrbufs = ++bufs;
+			do_wakeup = 1;
+
+			ret += this_len;
+			len -= this_len;
+			offset = 0;
+			if (!--nr_pages)
+				break;
+			if (!len)
+				break;
+			if (bufs < PIPE_BUFFERS)
+				continue;
+
+			break;
+		}
+
+		if (signal_pending(current)) {
+			if (!ret)
+				ret = -ERESTARTSYS;
+			break;
+		}
+
+		if (do_wakeup) {
+			wake_up_interruptible_sync(PIPE_WAIT(*inode));
+			kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO,
+				    POLL_IN);
+			do_wakeup = 0;
+		}
+
+		PIPE_WAITING_WRITERS(*inode)++;
+		pipe_wait(inode);
+		PIPE_WAITING_WRITERS(*inode)--;
+	}
+
+	mutex_unlock(PIPE_MUTEX(*inode));
+
+	if (do_wakeup) {
+		wake_up_interruptible(PIPE_WAIT(*inode));
+		kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN);
+	}
+
+	while (i < nr_pages)
+		page_cache_release(pages[i++]);
+
+	return ret;
+}
+
+static int __generic_file_splice_read(struct file *in, struct inode *pipe,
+				      size_t len)
+{
+	struct address_space *mapping = in->f_mapping;
+	unsigned int offset, nr_pages;
+	struct page *pages[PIPE_BUFFERS], *shadow[PIPE_BUFFERS];
+	struct page *page;
+	pgoff_t index, pidx;
+	int i, j;
+
+	index = in->f_pos >> PAGE_CACHE_SHIFT;
+	offset = in->f_pos & ~PAGE_CACHE_MASK;
+	nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+
+	if (nr_pages > PIPE_BUFFERS)
+		nr_pages = PIPE_BUFFERS;
+
+	/*
+	 * initiate read-ahead on this page range
+	 */
+	do_page_cache_readahead(mapping, in, index, nr_pages);
+
+	/*
+	 * Get as many pages from the page cache as possible..
+	 * Start IO on the page cache entries we create (we
+	 * can assume that any pre-existing ones we find have
+	 * already had IO started on them).
+	 */
+	i = find_get_pages(mapping, index, nr_pages, pages);
+
+	/*
+	 * common case - we found all pages and they are contiguous,
+	 * kick them off
+	 */
+	if (i && (pages[i - 1]->index == index + i - 1))
+		goto splice_them;
+
+	/*
+	 * fill shadow[] with pages at the right locations, so we only
+	 * have to fill holes
+	 */
+	memset(shadow, 0, i * sizeof(struct page *));
+	for (j = 0, pidx = index; j < i; pidx++, j++)
+		shadow[pages[j]->index - pidx] = pages[j];
+
+	/*
+	 * now fill in the holes
+	 */
+	for (i = 0, pidx = index; i < nr_pages; pidx++, i++) {
+		int error;
+
+		if (shadow[i])
+			continue;
+
+		/*
+		 * no page there, look one up / create it
+		 */
+		page = find_or_create_page(mapping, pidx,
+						   mapping_gfp_mask(mapping));
+		if (!page)
+			break;
+
+		if (PageUptodate(page))
+			unlock_page(page);
+		else {
+			error = mapping->a_ops->readpage(in, page);
+
+			if (unlikely(error)) {
+				page_cache_release(page);
+				break;
+			}
+		}
+		shadow[i] = page;
+	}
+
+	if (!i) {
+		for (i = 0; i < nr_pages; i++) {
+			 if (shadow[i])
+				page_cache_release(shadow[i]);
+		}
+		return 0;
+	}
+
+	memcpy(pages, shadow, i * sizeof(struct page *));
+
+	/*
+	 * Now we splice them into the pipe..
+	 */
+splice_them:
+	return move_to_pipe(pipe, pages, i, offset, len);
+}
+
+ssize_t generic_file_splice_read(struct file *in, struct inode *pipe,
+				 size_t len, unsigned int flags)
+{
+	ssize_t spliced;
+	int ret;
+
+	ret = 0;
+	spliced = 0;
+	while (len) {
+		ret = __generic_file_splice_read(in, pipe, len);
+
+		if (ret <= 0)
+			break;
+
+		in->f_pos += ret;
+		len -= ret;
+		spliced += ret;
+	}
+
+	if (spliced)
+		return spliced;
+
+	return ret;
+}
+
+/*
+ * Send 'len' bytes to socket from 'file' at position 'pos' using sendpage().
+ */
+static int pipe_to_sendpage(struct pipe_inode_info *info,
+			    struct pipe_buffer *buf, struct splice_desc *sd)
+{
+	struct file *file = sd->file;
+	loff_t pos = sd->pos;
+	unsigned int offset;
+	ssize_t ret;
+	void *ptr;
+
+	/*
+	 * sub-optimal, but we are limited by the pipe ->map. we don't
+	 * need a kmap'ed buffer here, we just want to make sure we
+	 * have the page pinned if the pipe page originates from the
+	 * page cache
+	 */
+	ptr = buf->ops->map(file, info, buf);
+	if (IS_ERR(ptr))
+		return PTR_ERR(ptr);
+
+	offset = pos & ~PAGE_CACHE_MASK;
+
+	ret = file->f_op->sendpage(file, buf->page, offset, sd->len, &pos,
+					sd->len < sd->total_len);
+
+	buf->ops->unmap(info, buf);
+	if (ret == sd->len)
+		return 0;
+
+	return -EIO;
+}
+
+/*
+ * This is a little more tricky than the file -> pipe splicing. There are
+ * basically three cases:
+ *
+ *	- Destination page already exists in the address space and there
+ *	  are users of it. For that case we have no other option that
+ *	  copying the data. Tough luck.
+ *	- Destination page already exists in the address space, but there
+ *	  are no users of it. Make sure it's uptodate, then drop it. Fall
+ *	  through to last case.
+ *	- Destination page does not exist, we can add the pipe page to
+ *	  the page cache and avoid the copy.
+ *
+ * For now we just do the slower thing and always copy pages over, it's
+ * easier than migrating pages from the pipe to the target file. For the
+ * case of doing file | file splicing, the migrate approach had some LRU
+ * nastiness...
+ */
+static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf,
+			struct splice_desc *sd)
+{
+	struct file *file = sd->file;
+	struct address_space *mapping = file->f_mapping;
+	unsigned int offset;
+	struct page *page;
+	pgoff_t index;
+	char *src;
+	int ret;
+
+	/*
+	 * after this, page will be locked and unmapped
+	 */
+	src = buf->ops->map(file, info, buf);
+	if (IS_ERR(src))
+		return PTR_ERR(src);
+
+	index = sd->pos >> PAGE_CACHE_SHIFT;
+	offset = sd->pos & ~PAGE_CACHE_MASK;
+
+	/*
+	 * reuse buf page, if SPLICE_F_MOVE is set
+	 */
+	if (sd->flags & SPLICE_F_MOVE) {
+		if (buf->ops->steal(info, buf))
+			goto find_page;
+
+		page = buf->page;
+		if (add_to_page_cache_lru(page, mapping, index,
+						mapping_gfp_mask(mapping)))
+			goto find_page;
+	} else {
+find_page:
+		ret = -ENOMEM;
+		page = find_or_create_page(mapping, index,
+						mapping_gfp_mask(mapping));
+		if (!page)
+			goto out;
+
+		/*
+		 * If the page is uptodate, it is also locked. If it isn't
+		 * uptodate, we can mark it uptodate if we are filling the
+		 * full page. Otherwise we need to read it in first...
+		 */
+		if (!PageUptodate(page)) {
+			if (sd->len < PAGE_CACHE_SIZE) {
+				ret = mapping->a_ops->readpage(file, page);
+				if (unlikely(ret))
+					goto out;
+
+				lock_page(page);
+
+				if (!PageUptodate(page)) {
+					/*
+					 * page got invalidated, repeat
+					 */
+					if (!page->mapping) {
+						unlock_page(page);
+						page_cache_release(page);
+						goto find_page;
+					}
+					ret = -EIO;
+					goto out;
+				}
+			} else {
+				WARN_ON(!PageLocked(page));
+				SetPageUptodate(page);
+			}
+		}
+	}
+
+	ret = mapping->a_ops->prepare_write(file, page, 0, sd->len);
+	if (ret)
+		goto out;
+
+	if (!buf->stolen) {
+		char *dst = kmap_atomic(page, KM_USER0);
+
+		memcpy(dst + offset, src + buf->offset, sd->len);
+		flush_dcache_page(page);
+		kunmap_atomic(dst, KM_USER0);
+	}
+
+	ret = mapping->a_ops->commit_write(file, page, 0, sd->len);
+	if (ret < 0)
+		goto out;
+
+	set_page_dirty(page);
+	ret = write_one_page(page, 0);
+out:
+	if (ret < 0)
+		unlock_page(page);
+	if (!buf->stolen)
+		page_cache_release(page);
+	buf->ops->unmap(info, buf);
+	return ret;
+}
+
+typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *,
+			   struct splice_desc *);
+
+static ssize_t move_from_pipe(struct inode *inode, struct file *out,
+			      size_t len, unsigned int flags,
+			      splice_actor *actor)
+{
+	struct pipe_inode_info *info;
+	int ret, do_wakeup, err;
+	struct splice_desc sd;
+
+	ret = 0;
+	do_wakeup = 0;
+
+	sd.total_len = len;
+	sd.flags = flags;
+	sd.file = out;
+	sd.pos = out->f_pos;
+
+	mutex_lock(PIPE_MUTEX(*inode));
+
+	info = inode->i_pipe;
+	for (;;) {
+		int bufs = info->nrbufs;
+
+		if (bufs) {
+			int curbuf = info->curbuf;
+			struct pipe_buffer *buf = info->bufs + curbuf;
+			struct pipe_buf_operations *ops = buf->ops;
+
+			sd.len = buf->len;
+			if (sd.len > sd.total_len)
+				sd.len = sd.total_len;
+
+			err = actor(info, buf, &sd);
+			if (err) {
+				if (!ret && err != -ENODATA)
+					ret = err;
+
+				break;
+			}
+
+			ret += sd.len;
+			buf->offset += sd.len;
+			buf->len -= sd.len;
+			if (!buf->len) {
+				buf->ops = NULL;
+				ops->release(info, buf);
+				curbuf = (curbuf + 1) & (PIPE_BUFFERS - 1);
+				info->curbuf = curbuf;
+				info->nrbufs = --bufs;
+				do_wakeup = 1;
+			}
+
+			sd.pos += sd.len;
+			sd.total_len -= sd.len;
+			if (!sd.total_len)
+				break;
+		}
+
+		if (bufs)
+			continue;
+		if (!PIPE_WRITERS(*inode))
+			break;
+		if (!PIPE_WAITING_WRITERS(*inode)) {
+			if (ret)
+				break;
+		}
+
+		if (signal_pending(current)) {
+			if (!ret)
+				ret = -ERESTARTSYS;
+			break;
+		}
+
+		if (do_wakeup) {
+			wake_up_interruptible_sync(PIPE_WAIT(*inode));
+			kill_fasync(PIPE_FASYNC_WRITERS(*inode),SIGIO,POLL_OUT);
+			do_wakeup = 0;
+		}
+
+		pipe_wait(inode);
+	}
+
+	mutex_unlock(PIPE_MUTEX(*inode));
+
+	if (do_wakeup) {
+		wake_up_interruptible(PIPE_WAIT(*inode));
+		kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT);
+	}
+
+	mutex_lock(&out->f_mapping->host->i_mutex);
+	out->f_pos = sd.pos;
+	mutex_unlock(&out->f_mapping->host->i_mutex);
+	return ret;
+
+}
+
+ssize_t generic_file_splice_write(struct inode *inode, struct file *out,
+				  size_t len, unsigned int flags)
+{
+	return move_from_pipe(inode, out, len, flags, pipe_to_file);
+}
+
+ssize_t generic_splice_sendpage(struct inode *inode, struct file *out,
+				size_t len, unsigned int flags)
+{
+	return move_from_pipe(inode, out, len, flags, pipe_to_sendpage);
+}
+
+EXPORT_SYMBOL(generic_file_splice_write);
+EXPORT_SYMBOL(generic_file_splice_read);
+
+static long do_splice_from(struct inode *pipe, struct file *out, size_t len,
+			   unsigned int flags)
+{
+	loff_t pos;
+	int ret;
+
+	if (!out->f_op || !out->f_op->splice_write)
+		return -EINVAL;
+
+	if (!(out->f_mode & FMODE_WRITE))
+		return -EBADF;
+
+	pos = out->f_pos;
+	ret = rw_verify_area(WRITE, out, &pos, len);
+	if (unlikely(ret < 0))
+		return ret;
+
+	return out->f_op->splice_write(pipe, out, len, flags);
+}
+
+static long do_splice_to(struct file *in, struct inode *pipe, size_t len,
+			 unsigned int flags)
+{
+	loff_t pos, isize, left;
+	int ret;
+
+	if (!in->f_op || !in->f_op->splice_read)
+		return -EINVAL;
+
+	if (!(in->f_mode & FMODE_READ))
+		return -EBADF;
+
+	pos = in->f_pos;
+	ret = rw_verify_area(READ, in, &pos, len);
+	if (unlikely(ret < 0))
+		return ret;
+
+	isize = i_size_read(in->f_mapping->host);
+	if (unlikely(in->f_pos >= isize))
+		return 0;
+	
+	left = isize - in->f_pos;
+	if (left < len)
+		len = left;
+
+	return in->f_op->splice_read(in, pipe, len, flags);
+}
+
+static long do_splice(struct file *in, struct file *out, size_t len,
+		      unsigned int flags)
+{
+	struct inode *pipe;
+
+	pipe = in->f_dentry->d_inode;
+	if (pipe->i_pipe)
+		return do_splice_from(pipe, out, len, flags);
+
+	pipe = out->f_dentry->d_inode;
+	if (pipe->i_pipe)
+		return do_splice_to(in, pipe, len, flags);
+
+	return -EINVAL;
+}
+
+asmlinkage long sys_splice(int fdin, int fdout, size_t len, unsigned int flags)
+{
+	long error;
+	struct file *in, *out;
+	int fput_in, fput_out;
+
+	if (unlikely(!len))
+		return 0;
+
+	error = -EBADF;
+	in = fget_light(fdin, &fput_in);
+	if (in) {
+		if (in->f_mode & FMODE_READ) {
+			out = fget_light(fdout, &fput_out);
+			if (out) {
+				if (out->f_mode & FMODE_WRITE)
+					error = do_splice(in, out, len, flags);
+				fput_light(out, fput_out);
+			}
+		}
+
+		fput_light(in, fput_in);
+	}
+
+	return error;
+}
diff --git a/fs/super.c b/fs/super.c
index 8743e9b..a66f66b 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -37,6 +37,7 @@
 #include <linux/writeback.h>		/* for the emergency remount stuff */
 #include <linux/idr.h>
 #include <linux/kobject.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 
@@ -380,9 +381,9 @@
 void sync_filesystems(int wait)
 {
 	struct super_block *sb;
-	static DECLARE_MUTEX(mutex);
+	static DEFINE_MUTEX(mutex);
 
-	down(&mutex);		/* Could be down_interruptible */
+	mutex_lock(&mutex);		/* Could be down_interruptible */
 	spin_lock(&sb_lock);
 	list_for_each_entry(sb, &super_blocks, s_list) {
 		if (!sb->s_op->sync_fs)
@@ -411,7 +412,7 @@
 			goto restart;
 	}
 	spin_unlock(&sb_lock);
-	up(&mutex);
+	mutex_unlock(&mutex);
 }
 
 /**
diff --git a/fs/sync.c b/fs/sync.c
new file mode 100644
index 0000000..8616006
--- /dev/null
+++ b/fs/sync.c
@@ -0,0 +1,164 @@
+/*
+ * High-level sync()-related operations
+ */
+
+#include <linux/kernel.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/writeback.h>
+#include <linux/syscalls.h>
+#include <linux/linkage.h>
+#include <linux/pagemap.h>
+
+#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
+			SYNC_FILE_RANGE_WAIT_AFTER)
+
+/*
+ * sys_sync_file_range() permits finely controlled syncing over a segment of
+ * a file in the range offset .. (offset+nbytes-1) inclusive.  If nbytes is
+ * zero then sys_sync_file_range() will operate from offset out to EOF.
+ *
+ * The flag bits are:
+ *
+ * SYNC_FILE_RANGE_WAIT_BEFORE: wait upon writeout of all pages in the range
+ * before performing the write.
+ *
+ * SYNC_FILE_RANGE_WRITE: initiate writeout of all those dirty pages in the
+ * range which are not presently under writeback.
+ *
+ * SYNC_FILE_RANGE_WAIT_AFTER: wait upon writeout of all pages in the range
+ * after performing the write.
+ *
+ * Useful combinations of the flag bits are:
+ *
+ * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE: ensures that all pages
+ * in the range which were dirty on entry to sys_sync_file_range() are placed
+ * under writeout.  This is a start-write-for-data-integrity operation.
+ *
+ * SYNC_FILE_RANGE_WRITE: start writeout of all dirty pages in the range which
+ * are not presently under writeout.  This is an asynchronous flush-to-disk
+ * operation.  Not suitable for data integrity operations.
+ *
+ * SYNC_FILE_RANGE_WAIT_BEFORE (or SYNC_FILE_RANGE_WAIT_AFTER): wait for
+ * completion of writeout of all pages in the range.  This will be used after an
+ * earlier SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE operation to wait
+ * for that operation to complete and to return the result.
+ *
+ * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER:
+ * a traditional sync() operation.  This is a write-for-data-integrity operation
+ * which will ensure that all pages in the range which were dirty on entry to
+ * sys_sync_file_range() are committed to disk.
+ *
+ *
+ * SYNC_FILE_RANGE_WAIT_BEFORE and SYNC_FILE_RANGE_WAIT_AFTER will detect any
+ * I/O errors or ENOSPC conditions and will return those to the caller, after
+ * clearing the EIO and ENOSPC flags in the address_space.
+ *
+ * It should be noted that none of these operations write out the file's
+ * metadata.  So unless the application is strictly performing overwrites of
+ * already-instantiated disk blocks, there are no guarantees here that the data
+ * will be available after a crash.
+ */
+asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
+					int flags)
+{
+	int ret;
+	struct file *file;
+	loff_t endbyte;			/* inclusive */
+	int fput_needed;
+	umode_t i_mode;
+
+	ret = -EINVAL;
+	if (flags & ~VALID_FLAGS)
+		goto out;
+
+	endbyte = offset + nbytes;
+
+	if ((s64)offset < 0)
+		goto out;
+	if ((s64)endbyte < 0)
+		goto out;
+	if (endbyte < offset)
+		goto out;
+
+	if (sizeof(pgoff_t) == 4) {
+		if (offset >= (0x100000000ULL << PAGE_CACHE_SHIFT)) {
+			/*
+			 * The range starts outside a 32 bit machine's
+			 * pagecache addressing capabilities.  Let it "succeed"
+			 */
+			ret = 0;
+			goto out;
+		}
+		if (endbyte >= (0x100000000ULL << PAGE_CACHE_SHIFT)) {
+			/*
+			 * Out to EOF
+			 */
+			nbytes = 0;
+		}
+	}
+
+	if (nbytes == 0)
+		endbyte = -1;
+	else
+		endbyte--;		/* inclusive */
+
+	ret = -EBADF;
+	file = fget_light(fd, &fput_needed);
+	if (!file)
+		goto out;
+
+	i_mode = file->f_dentry->d_inode->i_mode;
+	ret = -ESPIPE;
+	if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) &&
+			!S_ISLNK(i_mode))
+		goto out_put;
+
+	ret = do_sync_file_range(file, offset, endbyte, flags);
+out_put:
+	fput_light(file, fput_needed);
+out:
+	return ret;
+}
+
+/*
+ * `endbyte' is inclusive
+ */
+int do_sync_file_range(struct file *file, loff_t offset, loff_t endbyte,
+			int flags)
+{
+	int ret;
+	struct address_space *mapping;
+
+	mapping = file->f_mapping;
+	if (!mapping) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = 0;
+	if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) {
+		ret = wait_on_page_writeback_range(mapping,
+					offset >> PAGE_CACHE_SHIFT,
+					endbyte >> PAGE_CACHE_SHIFT);
+		if (ret < 0)
+			goto out;
+	}
+
+	if (flags & SYNC_FILE_RANGE_WRITE) {
+		ret = __filemap_fdatawrite_range(mapping, offset, endbyte,
+						WB_SYNC_NONE);
+		if (ret < 0)
+			goto out;
+	}
+
+	if (flags & SYNC_FILE_RANGE_WAIT_AFTER) {
+		ret = wait_on_page_writeback_range(mapping,
+					offset >> PAGE_CACHE_SHIFT,
+					endbyte >> PAGE_CACHE_SHIFT);
+	}
+out:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(do_sync_file_range);
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index 78899ee..c16a93c 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -163,7 +163,7 @@
 	return 0;
 }
 
-struct file_operations bin_fops = {
+const struct file_operations bin_fops = {
 	.read		= read,
 	.write		= write,
 	.mmap		= mmap,
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 9ee9568..f26880a 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -503,7 +503,7 @@
 	return offset;
 }
 
-struct file_operations sysfs_dir_operations = {
+const struct file_operations sysfs_dir_operations = {
 	.open		= sysfs_dir_open,
 	.release	= sysfs_dir_close,
 	.llseek		= sysfs_dir_lseek,
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 5e83e72..830f76f 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -348,7 +348,7 @@
 	return 0;
 }
 
-struct file_operations sysfs_file_operations = {
+const struct file_operations sysfs_file_operations = {
 	.read		= sysfs_read_file,
 	.write		= sysfs_write_file,
 	.llseek		= generic_file_llseek,
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index cf11d5b..32958a7 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -21,9 +21,9 @@
 
 extern struct rw_semaphore sysfs_rename_sem;
 extern struct super_block * sysfs_sb;
-extern struct file_operations sysfs_dir_operations;
-extern struct file_operations sysfs_file_operations;
-extern struct file_operations bin_fops;
+extern const struct file_operations sysfs_dir_operations;
+extern const struct file_operations sysfs_file_operations;
+extern const struct file_operations bin_fops;
 extern struct inode_operations sysfs_dir_inode_operations;
 extern struct inode_operations sysfs_symlink_inode_operations;
 
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index cce8b05..8c66e92 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -20,7 +20,7 @@
 
 static int sysv_readdir(struct file *, void *, filldir_t);
 
-struct file_operations sysv_dir_operations = {
+const struct file_operations sysv_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= sysv_readdir,
 	.fsync		= sysv_sync_file,
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
index da69abc..a59e303 100644
--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -19,7 +19,7 @@
  * We have mostly NULLs here: the current defaults are OK for
  * the coh filesystem.
  */
-struct file_operations sysv_file_operations = {
+const struct file_operations sysv_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
 	.write		= generic_file_write,
diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h
index b7f9b4a..393a480 100644
--- a/fs/sysv/sysv.h
+++ b/fs/sysv/sysv.h
@@ -159,8 +159,8 @@
 extern struct inode_operations sysv_file_inode_operations;
 extern struct inode_operations sysv_dir_inode_operations;
 extern struct inode_operations sysv_fast_symlink_inode_operations;
-extern struct file_operations sysv_file_operations;
-extern struct file_operations sysv_dir_operations;
+extern const struct file_operations sysv_file_operations;
+extern const struct file_operations sysv_dir_operations;
 extern struct address_space_operations sysv_aops;
 extern struct super_operations sysv_sops;
 extern struct dentry_operations sysv_dentry_operations;
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index f522252..8c28efa 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -42,7 +42,7 @@
 
 /* readdir and lookup functions */
 
-struct file_operations udf_dir_operations = {
+const struct file_operations udf_dir_operations = {
 	.read			= generic_read_dir,
 	.readdir		= udf_readdir,
 	.ioctl			= udf_ioctl,
diff --git a/fs/udf/file.c b/fs/udf/file.c
index a6f2acc..e34b00e 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -248,7 +248,7 @@
 	return 0;
 }
 
-struct file_operations udf_file_operations = {
+const struct file_operations udf_file_operations = {
 	.read			= generic_file_read,
 	.ioctl			= udf_ioctl,
 	.open			= generic_file_open,
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 1d5800e..023e19b 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -44,9 +44,9 @@
 struct super_block;
 
 extern struct inode_operations udf_dir_inode_operations;
-extern struct file_operations udf_dir_operations;
+extern const struct file_operations udf_dir_operations;
 extern struct inode_operations udf_file_inode_operations;
-extern struct file_operations udf_file_operations;
+extern const struct file_operations udf_file_operations;
 extern struct address_space_operations udf_aops;
 extern struct address_space_operations udf_adinicb_aops;
 extern struct address_space_operations udf_symlink_aops;
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 7c10c68..1a56120 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -620,7 +620,7 @@
 	return 1;
 }
 
-struct file_operations ufs_dir_operations = {
+const struct file_operations ufs_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= ufs_readdir,
 	.fsync		= file_fsync,
diff --git a/fs/ufs/file.c b/fs/ufs/file.c
index 62ad481..312fd3f 100644
--- a/fs/ufs/file.c
+++ b/fs/ufs/file.c
@@ -31,7 +31,7 @@
  * the ufs filesystem.
  */
  
-struct file_operations ufs_file_operations = {
+const struct file_operations ufs_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
 	.write		= generic_file_write,
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index ef46939..a56cec3 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -185,24 +185,6 @@
 		return -EINVAL;
 	if (len >= 256)
 		return -ENAMETOOLONG;
-
-	/* MS-DOS "device special files" */
-	if (len == 3 || (len > 3 && name[3] == '.')) {	/* basename == 3 */
-		if (!strnicmp(name, "aux", 3) ||
-		    !strnicmp(name, "con", 3) ||
-		    !strnicmp(name, "nul", 3) ||
-		    !strnicmp(name, "prn", 3))
-			return -EINVAL;
-	}
-	if (len == 4 || (len > 4 && name[4] == '.')) {	/* basename == 4 */
-		/* "com1", "com2", ... */
-		if ('1' <= name[3] && name[3] <= '9') {
-			if (!strnicmp(name, "com", 3) ||
-			    !strnicmp(name, "lpt", 3))
-				return -EINVAL;
-		}
-	}
-
 	return 0;
 }
 
diff --git a/fs/xfs/linux-2.6/mrlock.h b/fs/xfs/linux-2.6/mrlock.h
index 16b44c3..1b262b7 100644
--- a/fs/xfs/linux-2.6/mrlock.h
+++ b/fs/xfs/linux-2.6/mrlock.h
@@ -79,7 +79,7 @@
  * Debug-only routine, without some platform-specific asm code, we can
  * now only answer requests regarding whether we hold the lock for write
  * (reader state is outside our visibility, we only track writer state).
- * Note: means !ismrlocked would give false positivies, so don't do that.
+ * Note: means !ismrlocked would give false positives, so don't do that.
  */
 static inline int ismrlocked(mrlock_t *mrp, int type)
 {
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 97fc056..6cbbd16 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -372,7 +372,7 @@
  * assumes that all buffers on the page are started at the same time.
  *
  * The fix is two passes across the ioend list - one to start writeback on the
- * bufferheads, and then the second one submit them for I/O.
+ * buffer_heads, and then submit them for I/O on the second pass.
  */
 STATIC void
 xfs_submit_ioend(
@@ -699,7 +699,7 @@
 
 	/*
 	 * page_dirty is initially a count of buffers on the page before
-	 * EOF and is decrememted as we move each into a cleanable state.
+	 * EOF and is decremented as we move each into a cleanable state.
 	 *
 	 * Derivation:
 	 *
@@ -842,7 +842,7 @@
  * page if possible.
  * The bh->b_state's cannot know if any of the blocks or which block for
  * that matter are dirty due to mmap writes, and therefore bh uptodate is
- * only vaild if the page itself isn't completely uptodate.  Some layers
+ * only valid if the page itself isn't completely uptodate.  Some layers
  * may clear the page dirty flag prior to calling write page, under the
  * assumption the entire page will be written out; by not writing out the
  * whole page the page can be reused before all valid dirty data is
@@ -892,7 +892,7 @@
 
 	/*
 	 * page_dirty is initially a count of buffers on the page before
-	 * EOF and is decrememted as we move each into a cleanable state.
+	 * EOF and is decremented as we move each into a cleanable state.
 	 *
 	 * Derivation:
 	 *
@@ -1223,10 +1223,9 @@
 }
 
 STATIC int
-__xfs_get_block(
+__xfs_get_blocks(
 	struct inode		*inode,
 	sector_t		iblock,
-	unsigned long		blocks,
 	struct buffer_head	*bh_result,
 	int			create,
 	int			direct,
@@ -1236,22 +1235,17 @@
 	xfs_iomap_t		iomap;
 	xfs_off_t		offset;
 	ssize_t			size;
-	int			retpbbm = 1;
+	int			niomap = 1;
 	int			error;
 
 	offset = (xfs_off_t)iblock << inode->i_blkbits;
-	if (blocks)
-		size = (ssize_t) min_t(xfs_off_t, LONG_MAX,
-					(xfs_off_t)blocks << inode->i_blkbits);
-	else
-		size = 1 << inode->i_blkbits;
-
+	ASSERT(bh_result->b_size >= (1 << inode->i_blkbits));
+	size = bh_result->b_size;
 	VOP_BMAP(vp, offset, size,
-		create ? flags : BMAPI_READ, &iomap, &retpbbm, error);
+		create ? flags : BMAPI_READ, &iomap, &niomap, error);
 	if (error)
 		return -error;
-
-	if (retpbbm == 0)
+	if (niomap == 0)
 		return 0;
 
 	if (iomap.iomap_bn != IOMAP_DADDR_NULL) {
@@ -1271,12 +1265,16 @@
 		}
 	}
 
-	/* If this is a realtime file, data might be on a new device */
+	/*
+	 * If this is a realtime file, data may be on a different device.
+	 * to that pointed to from the buffer_head b_bdev currently.
+	 */
 	bh_result->b_bdev = iomap.iomap_target->bt_bdev;
 
-	/* If we previously allocated a block out beyond eof and
-	 * we are now coming back to use it then we will need to
-	 * flag it as new even if it has a disk address.
+	/*
+	 * If we previously allocated a block out beyond eof and we are
+	 * now coming back to use it then we will need to flag it as new
+	 * even if it has a disk address.
 	 */
 	if (create &&
 	    ((!buffer_mapped(bh_result) && !buffer_uptodate(bh_result)) ||
@@ -1292,38 +1290,36 @@
 		}
 	}
 
-	if (blocks) {
+	if (direct || size > (1 << inode->i_blkbits)) {
 		ASSERT(iomap.iomap_bsize - iomap.iomap_delta > 0);
 		offset = min_t(xfs_off_t,
-				iomap.iomap_bsize - iomap.iomap_delta,
-				(xfs_off_t)blocks << inode->i_blkbits);
-		bh_result->b_size = (u32) min_t(xfs_off_t, UINT_MAX, offset);
+				iomap.iomap_bsize - iomap.iomap_delta, size);
+		bh_result->b_size = (ssize_t)min_t(xfs_off_t, LONG_MAX, offset);
 	}
 
 	return 0;
 }
 
 int
-xfs_get_block(
+xfs_get_blocks(
 	struct inode		*inode,
 	sector_t		iblock,
 	struct buffer_head	*bh_result,
 	int			create)
 {
-	return __xfs_get_block(inode, iblock, 0, bh_result,
-					create, 0, BMAPI_WRITE);
+	return __xfs_get_blocks(inode, iblock,
+				bh_result, create, 0, BMAPI_WRITE);
 }
 
 STATIC int
 xfs_get_blocks_direct(
 	struct inode		*inode,
 	sector_t		iblock,
-	unsigned long		max_blocks,
 	struct buffer_head	*bh_result,
 	int			create)
 {
-	return __xfs_get_block(inode, iblock, max_blocks, bh_result,
-					create, 1, BMAPI_WRITE|BMAPI_DIRECT);
+	return __xfs_get_blocks(inode, iblock,
+				bh_result, create, 1, BMAPI_WRITE|BMAPI_DIRECT);
 }
 
 STATIC void
@@ -1338,9 +1334,9 @@
 	/*
 	 * Non-NULL private data means we need to issue a transaction to
 	 * convert a range from unwritten to written extents.  This needs
-	 * to happen from process contect but aio+dio I/O completion
+	 * to happen from process context but aio+dio I/O completion
 	 * happens from irq context so we need to defer it to a workqueue.
-	 * This is not nessecary for synchronous direct I/O, but we do
+	 * This is not necessary for synchronous direct I/O, but we do
 	 * it anyway to keep the code uniform and simpler.
 	 *
 	 * The core direct I/O code might be changed to always call the
@@ -1357,7 +1353,7 @@
 	}
 
 	/*
-	 * blockdev_direct_IO can return an error even afer the I/O
+	 * blockdev_direct_IO can return an error even after the I/O
 	 * completion handler was called.  Thus we need to protect
 	 * against double-freeing.
 	 */
@@ -1404,7 +1400,7 @@
 	unsigned int		from,
 	unsigned int		to)
 {
-	return block_prepare_write(page, from, to, xfs_get_block);
+	return block_prepare_write(page, from, to, xfs_get_blocks);
 }
 
 STATIC sector_t
@@ -1421,7 +1417,7 @@
 	VOP_RWLOCK(vp, VRWLOCK_READ);
 	VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, 0, FI_REMAPF, error);
 	VOP_RWUNLOCK(vp, VRWLOCK_READ);
-	return generic_block_bmap(mapping, block, xfs_get_block);
+	return generic_block_bmap(mapping, block, xfs_get_blocks);
 }
 
 STATIC int
@@ -1429,7 +1425,7 @@
 	struct file		*unused,
 	struct page		*page)
 {
-	return mpage_readpage(page, xfs_get_block);
+	return mpage_readpage(page, xfs_get_blocks);
 }
 
 STATIC int
@@ -1439,17 +1435,17 @@
 	struct list_head	*pages,
 	unsigned		nr_pages)
 {
-	return mpage_readpages(mapping, pages, nr_pages, xfs_get_block);
+	return mpage_readpages(mapping, pages, nr_pages, xfs_get_blocks);
 }
 
-STATIC int
+STATIC void
 xfs_vm_invalidatepage(
 	struct page		*page,
 	unsigned long		offset)
 {
 	xfs_page_trace(XFS_INVALIDPAGE_ENTER,
 			page->mapping->host, page, offset);
-	return block_invalidatepage(page, offset);
+	block_invalidatepage(page, offset);
 }
 
 struct address_space_operations xfs_address_space_operations = {
diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h
index 795699f..6071654 100644
--- a/fs/xfs/linux-2.6/xfs_aops.h
+++ b/fs/xfs/linux-2.6/xfs_aops.h
@@ -41,6 +41,6 @@
 } xfs_ioend_t;
 
 extern struct address_space_operations xfs_address_space_operations;
-extern int xfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
+extern int xfs_get_blocks(struct inode *, sector_t, struct buffer_head *, int);
 
 #endif /* __XFS_IOPS_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_export.h b/fs/xfs/linux-2.6/xfs_export.h
index e5b0559..e794ca4 100644
--- a/fs/xfs/linux-2.6/xfs_export.h
+++ b/fs/xfs/linux-2.6/xfs_export.h
@@ -54,7 +54,7 @@
  * Note, the NFS filehandle also includes an fsid portion which
  * may have an inode number in it.  That number is hardcoded to
  * 32bits and there is no way for XFS to intercept it.  In
- * practice this means when exporting an XFS filesytem with 64bit
+ * practice this means when exporting an XFS filesystem with 64bit
  * inodes you should either export the mountpoint (rather than
  * a subdirectory) or use the "fsid" export option.
  */
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index 185567a..85997b1 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -528,7 +528,7 @@
 }
 #endif /* HAVE_FOP_OPEN_EXEC */
 
-struct file_operations xfs_file_operations = {
+const struct file_operations xfs_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= do_sync_read,
 	.write		= do_sync_write,
@@ -550,7 +550,7 @@
 #endif
 };
 
-struct file_operations xfs_invis_file_operations = {
+const struct file_operations xfs_invis_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= do_sync_read,
 	.write		= do_sync_write,
@@ -570,7 +570,7 @@
 };
 
 
-struct file_operations xfs_dir_file_operations = {
+const struct file_operations xfs_dir_file_operations = {
 	.read		= generic_read_dir,
 	.readdir	= xfs_file_readdir,
 	.unlocked_ioctl	= xfs_file_ioctl,
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
index b6321ab..251bfe4 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -72,7 +72,7 @@
 	    copy_in_user(&p->l_pid,	&p32->l_pid,	sizeof(u32)) ||
 	    copy_in_user(&p->l_pad,	&p32->l_pad,	4*sizeof(u32)))
 		return -EFAULT;
-	
+
 	return (unsigned long)p;
 }
 
@@ -107,11 +107,15 @@
 #endif
 
 STATIC long
-xfs_compat_ioctl(int mode, struct file *f, unsigned cmd, unsigned long arg)
+xfs_compat_ioctl(
+	int		mode,
+	struct file	*file,
+	unsigned	cmd,
+	unsigned long	arg)
 {
+	struct inode	*inode = file->f_dentry->d_inode;
+	vnode_t		*vp = vn_from_inode(inode);
 	int		error;
-	struct		inode *inode = f->f_dentry->d_inode;
-	vnode_t		*vp = vn_to_inode(inode);
 
 	switch (cmd) {
 	case XFS_IOC_DIOINFO:
@@ -189,7 +193,7 @@
 		return -ENOIOCTLCMD;
 	}
 
-	VOP_IOCTL(vp, inode, f, mode, cmd, (void __user *)arg, error);
+	VOP_IOCTL(vp, inode, file, mode, cmd, (void __user *)arg, error);
 	VMODIFY(vp);
 
 	return error;
@@ -197,18 +201,18 @@
 
 long
 xfs_file_compat_ioctl(
-	struct file		*f,
+	struct file		*file,
 	unsigned		cmd,
 	unsigned long		arg)
 {
-	return xfs_compat_ioctl(0, f, cmd, arg);
+	return xfs_compat_ioctl(0, file, cmd, arg);
 }
 
 long
 xfs_file_compat_invis_ioctl(
-	struct file		*f,
+	struct file		*file,
 	unsigned		cmd,
 	unsigned long		arg)
 {
-	return xfs_compat_ioctl(IO_INVIS, f, cmd, arg);
+	return xfs_compat_ioctl(IO_INVIS, file, cmd, arg);
 }
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index af48743..1492373 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -708,7 +708,7 @@
 xfs_vn_truncate(
 	struct inode	*inode)
 {
-	block_truncate_page(inode->i_mapping, inode->i_size, xfs_get_block);
+	block_truncate_page(inode->i_mapping, inode->i_size, xfs_get_blocks);
 }
 
 STATIC int
diff --git a/fs/xfs/linux-2.6/xfs_iops.h b/fs/xfs/linux-2.6/xfs_iops.h
index a8417d7..ad6173d 100644
--- a/fs/xfs/linux-2.6/xfs_iops.h
+++ b/fs/xfs/linux-2.6/xfs_iops.h
@@ -22,9 +22,9 @@
 extern struct inode_operations xfs_dir_inode_operations;
 extern struct inode_operations xfs_symlink_inode_operations;
 
-extern struct file_operations xfs_file_operations;
-extern struct file_operations xfs_dir_file_operations;
-extern struct file_operations xfs_invis_file_operations;
+extern const struct file_operations xfs_file_operations;
+extern const struct file_operations xfs_dir_file_operations;
+extern const struct file_operations xfs_invis_file_operations;
 
 extern int xfs_ioctl(struct bhv_desc *, struct inode *, struct file *,
                         int, unsigned int, void __user *);
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index 0169360..84ddf18 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -681,7 +681,7 @@
 		eventsent = 1;
 
 		/*
-		 * The iolock was dropped and reaquired in XFS_SEND_DATA
+		 * The iolock was dropped and reacquired in XFS_SEND_DATA
 		 * so we have to recheck the size when appending.
 		 * We will only "goto start;" once, since having sent the
 		 * event prevents another call to XFS_SEND_DATA, which is
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 8355faf..1884300 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -375,9 +375,8 @@
 	if (!xfs_ioend_zone)
 		goto out_destroy_vnode_zone;
 
-	xfs_ioend_pool = mempool_create(4 * MAX_BUF_PER_PAGE,
-					mempool_alloc_slab, mempool_free_slab,
-					xfs_ioend_zone);
+	xfs_ioend_pool = mempool_create_slab_pool(4 * MAX_BUF_PER_PAGE,
+						  xfs_ioend_zone);
 	if (!xfs_ioend_pool)
 		goto out_free_ioend_zone;
 	return 0;
diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h
index 8fed356..841200c 100644
--- a/fs/xfs/linux-2.6/xfs_vfs.h
+++ b/fs/xfs/linux-2.6/xfs_vfs.h
@@ -92,7 +92,7 @@
 #define SYNC_FSDATA		0x0020	/* flush fs data (e.g. superblocks) */
 #define SYNC_REFCACHE		0x0040  /* prune some of the nfs ref cache */
 #define SYNC_REMOUNT		0x0080  /* remount readonly, no dummy LRs */
-#define SYNC_QUIESCE		0x0100  /* quiesce fileystem for a snapshot */
+#define SYNC_QUIESCE		0x0100  /* quiesce filesystem for a snapshot */
 
 typedef int	(*vfs_mount_t)(bhv_desc_t *,
 				struct xfs_mount_args *, struct cred *);
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c
index e4e5f05..546f48a 100644
--- a/fs/xfs/quota/xfs_dquot_item.c
+++ b/fs/xfs/quota/xfs_dquot_item.c
@@ -221,7 +221,7 @@
  * as possible.
  *
  * We must not be holding the AIL_LOCK at this point. Calling incore() to
- * search the buffercache can be a time consuming thing, and AIL_LOCK is a
+ * search the buffer cache can be a time consuming thing, and AIL_LOCK is a
  * spinlock.
  */
 STATIC void
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 1fb757e..73c1e5e 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -289,7 +289,7 @@
 
 /*
  * This is called at mount time from xfs_mountfs to initialize the quotainfo
- * structure and start the global quotamanager (xfs_Gqm) if it hasn't done
+ * structure and start the global quota manager (xfs_Gqm) if it hasn't done
  * so already.	Note that the superblock has not been read in yet.
  */
 void
@@ -807,7 +807,7 @@
  * Given a udquot and gdquot, attach a ptr to the group dquot in the
  * udquot as a hint for future lookups. The idea sounds simple, but the
  * execution isn't, because the udquot might have a group dquot attached
- * already and getting rid of that gets us into lock ordering contraints.
+ * already and getting rid of that gets us into lock ordering constraints.
  * The process is complicated more by the fact that the dquots may or may not
  * be locked on entry.
  */
@@ -1094,10 +1094,10 @@
 			}
 			/*
 			 * If we can't grab the flush lock then if the caller
-			 * really wanted us to give this our best shot,
+			 * really wanted us to give this our best shot, so
 			 * see if we can give a push to the buffer before we wait
 			 * on the flush lock. At this point, we know that
-			 * eventhough the dquot is being flushed,
+			 * even though the dquot is being flushed,
 			 * it has (new) dirty data.
 			 */
 			xfs_qm_dqflock_pushbuf_wait(dqp);
@@ -1491,7 +1491,7 @@
 		/*
 		 * Do a sanity check, and if needed, repair the dqblk. Don't
 		 * output any warnings because it's perfectly possible to
-		 * find unitialized dquot blks. See comment in xfs_qm_dqcheck.
+		 * find uninitialised dquot blks. See comment in xfs_qm_dqcheck.
 		 */
 		(void) xfs_qm_dqcheck(ddq, id+j, type, XFS_QMOPT_DQREPAIR,
 				      "xfs_quotacheck");
@@ -1580,7 +1580,7 @@
 
 	error = 0;
 	/*
-	 * This looks racey, but we can't keep an inode lock across a
+	 * This looks racy, but we can't keep an inode lock across a
 	 * trans_reserve. But, this gets called during quotacheck, and that
 	 * happens only at mount time which is single threaded.
 	 */
@@ -1824,7 +1824,7 @@
 	 * we have to start from the beginning anyway.
 	 * Once we're done, we'll log all the dquot bufs.
 	 *
-	 * The *QUOTA_ON checks below may look pretty racey, but quotachecks
+	 * The *QUOTA_ON checks below may look pretty racy, but quotachecks
 	 * and quotaoffs don't race. (Quotachecks happen at mount time only).
 	 */
 	if (XFS_IS_UQUOTA_ON(mp)) {
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
index 6768843..c55db46 100644
--- a/fs/xfs/quota/xfs_qm_syscalls.c
+++ b/fs/xfs/quota/xfs_qm_syscalls.c
@@ -912,7 +912,7 @@
 
 	/*
 	 * Internally, we don't reset all the timers when quota enforcement
-	 * gets turned off. No need to confuse the userlevel code,
+	 * gets turned off. No need to confuse the user level code,
 	 * so return zeroes in that case.
 	 */
 	if (! XFS_IS_QUOTA_ENFORCED(mp)) {
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c
index 3290975..d8e131e 100644
--- a/fs/xfs/quota/xfs_trans_dquot.c
+++ b/fs/xfs/quota/xfs_trans_dquot.c
@@ -804,7 +804,7 @@
 	}
 
 	/*
-	 * Didnt change anything critical, so, no need to log
+	 * Didn't change anything critical, so, no need to log
 	 */
 	return (0);
 }
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 4ff0f4e..2539af3 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -395,7 +395,7 @@
  * The access control process to determine the access permission:
  *	if uid == file owner id, use the file owner bits.
  *	if gid == file owner group id, use the file group bits.
- *	scan ACL for a maching user or group, and use matched entry
+ *	scan ACL for a matching user or group, and use matched entry
  *	permission. Use total permissions of all matching group entries,
  *	until all acl entries are exhausted. The final permission produced
  *	by matching acl entry or entries needs to be & with group permission.
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h
index a96e2ff..dc2361d 100644
--- a/fs/xfs/xfs_ag.h
+++ b/fs/xfs/xfs_ag.h
@@ -179,7 +179,7 @@
 {
 	char		pagf_init;	/* this agf's entry is initialized */
 	char		pagi_init;	/* this agi's entry is initialized */
-	char		pagf_metadata;	/* the agf is prefered to be metadata */
+	char		pagf_metadata;	/* the agf is preferred to be metadata */
 	char		pagi_inodeok;	/* The agi is ok for inodes */
 	__uint8_t	pagf_levels[XFS_BTNUM_AGF];
 					/* # of levels in bno & cnt btree */
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index f4328e1..64ee07d 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -511,7 +511,7 @@
 xfs_alloc_trace_busy(
 	char		*name,		/* function tag string */
 	char		*str,		/* additional string */
-	xfs_mount_t	*mp,		/* file system mount poing */
+	xfs_mount_t	*mp,		/* file system mount point */
 	xfs_agnumber_t	agno,		/* allocation group number */
 	xfs_agblock_t	agbno,		/* a.g. relative block number */
 	xfs_extlen_t	len,		/* length of extent */
@@ -1843,7 +1843,7 @@
 	} else
 		agbp = NULL;
 
-	/* If this is a metadata prefered pag and we are user data
+	/* If this is a metadata preferred pag and we are user data
 	 * then try somewhere else if we are not being asked to
 	 * try harder at this point
 	 */
@@ -2458,7 +2458,7 @@
 /*
  * AG Busy list management
  * The busy list contains block ranges that have been freed but whose
- * transacations have not yet hit disk.  If any block listed in a busy
+ * transactions have not yet hit disk.  If any block listed in a busy
  * list is reused, the transaction that freed it must be forced to disk
  * before continuing to use the block.
  *
diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h
index 3546dea..2d1f892 100644
--- a/fs/xfs/xfs_alloc.h
+++ b/fs/xfs/xfs_alloc.h
@@ -68,7 +68,7 @@
 	xfs_alloctype_t	otype;		/* original allocation type */
 	char		wasdel;		/* set if allocation was prev delayed */
 	char		wasfromfl;	/* set if allocation is from freelist */
-	char		isfl;		/* set if is freelist blocks - !actg */
+	char		isfl;		/* set if is freelist blocks - !acctg */
 	char		userdata;	/* set if this is user data */
 } xfs_alloc_arg_t;
 
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
index 093fac4..b6e1e02 100644
--- a/fs/xfs/xfs_attr.c
+++ b/fs/xfs/xfs_attr.c
@@ -294,7 +294,7 @@
 	xfs_trans_ihold(args.trans, dp);
 
 	/*
-	 * If the attribute list is non-existant or a shortform list,
+	 * If the attribute list is non-existent or a shortform list,
 	 * upgrade it to a single-leaf-block attribute list.
 	 */
 	if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
@@ -1584,7 +1584,7 @@
  * Fill in the disk block numbers in the state structure for the buffers
  * that are attached to the state structure.
  * This is done so that we can quickly reattach ourselves to those buffers
- * after some set of transaction commit's has released these buffers.
+ * after some set of transaction commits have released these buffers.
  */
 STATIC int
 xfs_attr_fillstate(xfs_da_state_t *state)
@@ -1631,7 +1631,7 @@
 /*
  * Reattach the buffers to the state structure based on the disk block
  * numbers stored in the state structure.
- * This is done after some set of transaction commit's has released those
+ * This is done after some set of transaction commits have released those
  * buffers from our grip.
  */
 STATIC int
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
index 7176827..9462be8 100644
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -524,7 +524,7 @@
 
 /*
  * Copy out entries of shortform attribute lists for attr_list().
- * Shortform atrtribute lists are not stored in hashval sorted order.
+ * Shortform attribute lists are not stored in hashval sorted order.
  * If the output buffer is not large enough to hold them all, then we
  * we have to calculate each entries' hashvalue and sort them before
  * we can begin returning them to the user.
@@ -1541,7 +1541,7 @@
 	/*
 	 * Check for the degenerate case of the block being empty.
 	 * If the block is empty, we'll simply delete it, no need to
-	 * coalesce it with a sibling block.  We choose (aribtrarily)
+	 * coalesce it with a sibling block.  We choose (arbitrarily)
 	 * to merge with the forward block unless it is NULL.
 	 */
 	if (count == 0) {
diff --git a/fs/xfs/xfs_behavior.c b/fs/xfs/xfs_behavior.c
index 9880ada..f4fe371 100644
--- a/fs/xfs/xfs_behavior.c
+++ b/fs/xfs/xfs_behavior.c
@@ -31,7 +31,7 @@
  * The behavior chain is ordered based on the 'position' number which
  * lives in the first field of the ops vector (higher numbers first).
  *
- * Attemps to insert duplicate ops result in an EINVAL return code.
+ * Attempts to insert duplicate ops result in an EINVAL return code.
  * Otherwise, return 0 to indicate success.
  */
 int
@@ -84,7 +84,7 @@
 
 /*
  * Remove a behavior descriptor from a position in a behavior chain;
- * the postition is guaranteed not to be the first position.
+ * the position is guaranteed not to be the first position.
  * Should only be called by the bhv_remove() macro.
  */
 void
diff --git a/fs/xfs/xfs_behavior.h b/fs/xfs/xfs_behavior.h
index 2cd89bb..1d8ff10 100644
--- a/fs/xfs/xfs_behavior.h
+++ b/fs/xfs/xfs_behavior.h
@@ -39,7 +39,7 @@
  * behaviors is synchronized with operations-in-progress (oip's) so that
  * the oip's always see a consistent view of the chain.
  *
- * The term "interpostion" is used to refer to the act of inserting
+ * The term "interposition" is used to refer to the act of inserting
  * a behavior such that it interposes on (i.e., is inserted in front
  * of) a particular other behavior.  A key example of this is when a
  * system implementing distributed single system image wishes to
@@ -51,7 +51,7 @@
  *
  * Behavior synchronization is logic which is necessary under certain
  * circumstances that there is no conflict between ongoing operations
- * traversing the behavior chain and those dunamically modifying the
+ * traversing the behavior chain and those dynamically modifying the
  * behavior chain.  Because behavior synchronization adds extra overhead
  * to virtual operation invocation, we want to restrict, as much as
  * we can, the requirement for this extra code, to those situations
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 2d702e4..d384e48 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -3467,113 +3467,6 @@
 	return error;
 }
 
-xfs_bmbt_rec_t *			/* pointer to found extent entry */
-xfs_bmap_do_search_extents(
-	xfs_bmbt_rec_t	*base,		/* base of extent list */
-	xfs_extnum_t	lastx,		/* last extent index used */
-	xfs_extnum_t	nextents,	/* number of file extents */
-	xfs_fileoff_t	bno,		/* block number searched for */
-	int		*eofp,		/* out: end of file found */
-	xfs_extnum_t	*lastxp,	/* out: last extent index */
-	xfs_bmbt_irec_t	*gotp,		/* out: extent entry found */
-	xfs_bmbt_irec_t	*prevp)		/* out: previous extent entry found */
-{
-	xfs_bmbt_rec_t	*ep;		/* extent list entry pointer */
-	xfs_bmbt_irec_t	got;		/* extent list entry, decoded */
-	int		high;		/* high index of binary search */
-	int		low;		/* low index of binary search */
-
-	/*
-	 * Initialize the extent entry structure to catch access to
-	 * uninitialized br_startblock field.
-	 */
-	got.br_startoff = 0xffa5a5a5a5a5a5a5LL;
-	got.br_blockcount = 0xa55a5a5a5a5a5a5aLL;
-	got.br_state = XFS_EXT_INVALID;
-
-#if XFS_BIG_BLKNOS
-	got.br_startblock = 0xffffa5a5a5a5a5a5LL;
-#else
-	got.br_startblock = 0xffffa5a5;
-#endif
-
-	if (lastx != NULLEXTNUM && lastx < nextents)
-		ep = base + lastx;
-	else
-		ep = NULL;
-	prevp->br_startoff = NULLFILEOFF;
-	if (ep && bno >= (got.br_startoff = xfs_bmbt_get_startoff(ep)) &&
-	    bno < got.br_startoff +
-		  (got.br_blockcount = xfs_bmbt_get_blockcount(ep)))
-		*eofp = 0;
-	else if (ep && lastx < nextents - 1 &&
-		 bno >= (got.br_startoff = xfs_bmbt_get_startoff(ep + 1)) &&
-		 bno < got.br_startoff +
-		       (got.br_blockcount = xfs_bmbt_get_blockcount(ep + 1))) {
-		lastx++;
-		ep++;
-		*eofp = 0;
-	} else if (nextents == 0)
-		*eofp = 1;
-	else if (bno == 0 &&
-		 (got.br_startoff = xfs_bmbt_get_startoff(base)) == 0) {
-		ep = base;
-		lastx = 0;
-		got.br_blockcount = xfs_bmbt_get_blockcount(ep);
-		*eofp = 0;
-	} else {
-		low = 0;
-		high = nextents - 1;
-		/* binary search the extents array */
-		while (low <= high) {
-			XFS_STATS_INC(xs_cmp_exlist);
-			lastx = (low + high) >> 1;
-			ep = base + lastx;
-			got.br_startoff = xfs_bmbt_get_startoff(ep);
-			got.br_blockcount = xfs_bmbt_get_blockcount(ep);
-			if (bno < got.br_startoff)
-				high = lastx - 1;
-			else if (bno >= got.br_startoff + got.br_blockcount)
-				low = lastx + 1;
-			else {
-				got.br_startblock = xfs_bmbt_get_startblock(ep);
-				got.br_state = xfs_bmbt_get_state(ep);
-				*eofp = 0;
-				*lastxp = lastx;
-				*gotp = got;
-				return ep;
-			}
-		}
-		if (bno >= got.br_startoff + got.br_blockcount) {
-			lastx++;
-			if (lastx == nextents) {
-				*eofp = 1;
-				got.br_startblock = xfs_bmbt_get_startblock(ep);
-				got.br_state = xfs_bmbt_get_state(ep);
-				*prevp = got;
-				ep = NULL;
-			} else {
-				*eofp = 0;
-				xfs_bmbt_get_all(ep, prevp);
-				ep++;
-				got.br_startoff = xfs_bmbt_get_startoff(ep);
-				got.br_blockcount = xfs_bmbt_get_blockcount(ep);
-			}
-		} else {
-			*eofp = 0;
-			if (ep > base)
-				xfs_bmbt_get_all(ep - 1, prevp);
-		}
-	}
-	if (ep) {
-		got.br_startblock = xfs_bmbt_get_startblock(ep);
-		got.br_state = xfs_bmbt_get_state(ep);
-	}
-	*lastxp = lastx;
-	*gotp = got;
-	return ep;
-}
-
 /*
  * Search the extent records for the entry containing block bno.
  * If bno lies in a hole, point to the next entry.  If bno lies
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h
index 011ccaa..f83399c 100644
--- a/fs/xfs/xfs_bmap.h
+++ b/fs/xfs/xfs_bmap.h
@@ -362,14 +362,6 @@
 xfs_bmap_search_multi_extents(struct xfs_ifork *, xfs_fileoff_t, int *,
 			xfs_extnum_t *, xfs_bmbt_irec_t *, xfs_bmbt_irec_t *);
 
-/*
- * Search an extent list for the extent which includes block
- * bno.
- */
-xfs_bmbt_rec_t *xfs_bmap_do_search_extents(xfs_bmbt_rec_t *,
-			xfs_extnum_t, xfs_extnum_t, xfs_fileoff_t, int *,
-			xfs_extnum_t *, xfs_bmbt_irec_t *, xfs_bmbt_irec_t *);
-
 #endif	/* __KERNEL__ */
 
 #endif	/* __XFS_BMAP_H__ */
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 07e2324..5fed156 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -98,12 +98,12 @@
 }
 
 /*
- * This function is called to verify that our caller's have logged
+ * This function is called to verify that our callers have logged
  * all the bytes that they changed.
  *
  * It does this by comparing the original copy of the buffer stored in
  * the buf log item's bli_orig array to the current copy of the buffer
- * and ensuring that all bytes which miscompare are set in the bli_logged
+ * and ensuring that all bytes which mismatch are set in the bli_logged
  * array of the buf log item.
  */
 STATIC void
diff --git a/fs/xfs/xfs_cap.h b/fs/xfs/xfs_cap.h
index 433ec53..d0035c6e 100644
--- a/fs/xfs/xfs_cap.h
+++ b/fs/xfs/xfs_cap.h
@@ -38,7 +38,7 @@
 /*
  * For Linux, we take the bitfields directly from capability.h
  * and no longer attempt to keep this attribute ondisk compatible
- * with IRIX.  Since this attribute is only set on exectuables,
+ * with IRIX.  Since this attribute is only set on executables,
  * it just doesn't make much sense to try.  We do use a different
  * named attribute though, to avoid confusion.
  */
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c
index 4bae3a7..8988b90 100644
--- a/fs/xfs/xfs_da_btree.c
+++ b/fs/xfs/xfs_da_btree.c
@@ -840,7 +840,7 @@
 	/*
 	 * Check for the degenerate case of the block being empty.
 	 * If the block is empty, we'll simply delete it, no need to
-	 * coalesce it with a sibling block.  We choose (aribtrarily)
+	 * coalesce it with a sibling block.  We choose (arbitrarily)
 	 * to merge with the forward block unless it is NULL.
 	 */
 	if (count == 0) {
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index bd5cee6..972ded5 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -533,7 +533,7 @@
 
 	/*
 	 * Reached the end of the block.
-	 * Set the offset to a nonexistent block 1 and return.
+	 * Set the offset to a non-existent block 1 and return.
 	 */
 	*eofp = 1;
 
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index 08648b18..0f5e2f2 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -515,7 +515,7 @@
 			ASSERT(be32_to_cpu(leaf->ents[highstale].address) ==
 			       XFS_DIR2_NULL_DATAPTR);
 			/*
-			 * Copy entries down to copver the stale entry
+			 * Copy entries down to cover the stale entry
 			 * and make room for the new entry.
 			 */
 			if (highstale - index > 0)
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
index af556f1..ac511ab 100644
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -830,7 +830,7 @@
 		state->inleaf = 1;
 		blk2->index = 0;
 		cmn_err(CE_ALERT,
-			"xfs_dir2_leafn_rebalance: picked the wrong leaf? reverting orignal leaf: "
+			"xfs_dir2_leafn_rebalance: picked the wrong leaf? reverting original leaf: "
 			"blk1->index %d\n",
 			blk1->index);
 	}
diff --git a/fs/xfs/xfs_dir_leaf.c b/fs/xfs/xfs_dir_leaf.c
index ee88751..6d71186 100644
--- a/fs/xfs/xfs_dir_leaf.c
+++ b/fs/xfs/xfs_dir_leaf.c
@@ -1341,7 +1341,7 @@
 	/*
 	 * Check for the degenerate case of the block being empty.
 	 * If the block is empty, we'll simply delete it, no need to
-	 * coalesce it with a sibling block.  We choose (aribtrarily)
+	 * coalesce it with a sibling block.  We choose (arbitrarily)
 	 * to merge with the forward block unless it is NULL.
 	 */
 	if (count == 0) {
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 56caa88..dfa3527 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -477,7 +477,7 @@
  *
  * xfs_reserve_blocks is called to set m_resblks
  * in the in-core mount table. The number of unused reserved blocks
- * is kept in m_resbls_avail.
+ * is kept in m_resblks_avail.
  *
  * Reserve the requested number of blocks if available. Otherwise return
  * as many as possible to satisfy the request. The actual number
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
index 0024892..4eeb856 100644
--- a/fs/xfs/xfs_ialloc.c
+++ b/fs/xfs/xfs_ialloc.c
@@ -136,7 +136,7 @@
 	int		ninodes;	/* num inodes per buf */
 	xfs_agino_t	thisino;	/* current inode number, for loop */
 	int		version;	/* inode version number to use */
-	int		isaligned;	/* inode allocation at stripe unit */
+	int		isaligned = 0;	/* inode allocation at stripe unit */
 					/* boundary */
 
 	args.tp = tp;
@@ -152,47 +152,75 @@
 		return XFS_ERROR(ENOSPC);
 	args.minlen = args.maxlen = XFS_IALLOC_BLOCKS(args.mp);
 	/*
-	 * Set the alignment for the allocation.
-	 * If stripe alignment is turned on then align at stripe unit
-	 * boundary.
-	 * If the cluster size is smaller than a filesystem block
-	 * then we're doing I/O for inodes in filesystem block size pieces,
-	 * so don't need alignment anyway.
-	 */
-	isaligned = 0;
-	if (args.mp->m_sinoalign) {
-		ASSERT(!(args.mp->m_flags & XFS_MOUNT_NOALIGN));
-		args.alignment = args.mp->m_dalign;
-		isaligned = 1;
-	} else if (XFS_SB_VERSION_HASALIGN(&args.mp->m_sb) &&
-	    args.mp->m_sb.sb_inoalignmt >=
-	    XFS_B_TO_FSBT(args.mp, XFS_INODE_CLUSTER_SIZE(args.mp)))
-		args.alignment = args.mp->m_sb.sb_inoalignmt;
-	else
-		args.alignment = 1;
+	 * First try to allocate inodes contiguous with the last-allocated
+	 * chunk of inodes.  If the filesystem is striped, this will fill
+	 * an entire stripe unit with inodes.
+ 	 */
 	agi = XFS_BUF_TO_AGI(agbp);
-	/*
-	 * Need to figure out where to allocate the inode blocks.
-	 * Ideally they should be spaced out through the a.g.
-	 * For now, just allocate blocks up front.
-	 */
-	args.agbno = be32_to_cpu(agi->agi_root);
-	args.fsbno = XFS_AGB_TO_FSB(args.mp, be32_to_cpu(agi->agi_seqno),
-				    args.agbno);
-	/*
-	 * Allocate a fixed-size extent of inodes.
-	 */
-	args.type = XFS_ALLOCTYPE_NEAR_BNO;
-	args.mod = args.total = args.wasdel = args.isfl = args.userdata =
-		args.minalignslop = 0;
-	args.prod = 1;
-	/*
-	 * Allow space for the inode btree to split.
-	 */
-	args.minleft = XFS_IN_MAXLEVELS(args.mp) - 1;
-	if ((error = xfs_alloc_vextent(&args)))
-		return error;
+	newino = be32_to_cpu(agi->agi_newino);
+	if(likely(newino != NULLAGINO)) {
+		args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) +
+				XFS_IALLOC_BLOCKS(args.mp);
+		args.fsbno = XFS_AGB_TO_FSB(args.mp,
+				be32_to_cpu(agi->agi_seqno), args.agbno);
+		args.type = XFS_ALLOCTYPE_THIS_BNO;
+		args.mod = args.total = args.wasdel = args.isfl =
+			args.userdata = args.minalignslop = 0;
+		args.prod = 1;
+		args.alignment = 1;
+		/*
+		 * Allow space for the inode btree to split.
+		 */
+		args.minleft = XFS_IN_MAXLEVELS(args.mp) - 1;
+		if ((error = xfs_alloc_vextent(&args)))
+			return error;
+	} else
+		args.fsbno = NULLFSBLOCK;
 
+	if (unlikely(args.fsbno == NULLFSBLOCK)) {
+		/*
+		 * Set the alignment for the allocation.
+		 * If stripe alignment is turned on then align at stripe unit
+		 * boundary.
+		 * If the cluster size is smaller than a filesystem block 
+		 * then we're doing I/O for inodes in filesystem block size 
+		 * pieces, so don't need alignment anyway.
+		 */
+		isaligned = 0;
+		if (args.mp->m_sinoalign) {
+			ASSERT(!(args.mp->m_flags & XFS_MOUNT_NOALIGN));
+			args.alignment = args.mp->m_dalign;
+			isaligned = 1;
+		} else if (XFS_SB_VERSION_HASALIGN(&args.mp->m_sb) &&
+			   args.mp->m_sb.sb_inoalignmt >= 
+			   XFS_B_TO_FSBT(args.mp,
+			  	XFS_INODE_CLUSTER_SIZE(args.mp)))
+				args.alignment = args.mp->m_sb.sb_inoalignmt;
+		else
+			args.alignment = 1;
+		/*
+		 * Need to figure out where to allocate the inode blocks.
+		 * Ideally they should be spaced out through the a.g.
+		 * For now, just allocate blocks up front.
+		 */
+		args.agbno = be32_to_cpu(agi->agi_root);
+		args.fsbno = XFS_AGB_TO_FSB(args.mp,
+				be32_to_cpu(agi->agi_seqno), args.agbno);
+		/*
+		 * Allocate a fixed-size extent of inodes.
+		 */
+		args.type = XFS_ALLOCTYPE_NEAR_BNO;
+		args.mod = args.total = args.wasdel = args.isfl =
+			args.userdata = args.minalignslop = 0;
+		args.prod = 1;
+		/*
+		 * Allow space for the inode btree to split.
+		 */
+		args.minleft = XFS_IN_MAXLEVELS(args.mp) - 1;
+		if ((error = xfs_alloc_vextent(&args)))
+			return error;
+	}
+ 
 	/*
 	 * If stripe alignment is turned on, then try again with cluster
 	 * alignment.
@@ -1023,7 +1051,7 @@
 	rec.ir_freecount++;
 
 	/*
-	 * When an inode cluster is free, it becomes elgible for removal
+	 * When an inode cluster is free, it becomes eligible for removal
 	 */
 	if ((mp->m_flags & XFS_MOUNT_IDELETE) &&
 	    (rec.ir_freecount == XFS_IALLOC_INODES(mp))) {
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index 3ce35a6..bb33113 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -509,7 +509,7 @@
 		} else {
 			/*
 			 * If the inode is not fully constructed due to
-			 * filehandle mistmatches wait for the inode to go
+			 * filehandle mismatches wait for the inode to go
 			 * away and try again.
 			 *
 			 * iget_locked will call __wait_on_freeing_inode
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 88a517f..48146bd 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -160,7 +160,7 @@
 	xfs_dinode_t	*dip;
 
 	/*
-	 * Call the space managment code to find the location of the
+	 * Call the space management code to find the location of the
 	 * inode on disk.
 	 */
 	imap.im_blkno = 0;
@@ -837,7 +837,7 @@
 
 /*
  * Given a mount structure and an inode number, return a pointer
- * to a newly allocated in-core inode coresponding to the given
+ * to a newly allocated in-core inode corresponding to the given
  * inode number.
  *
  * Initialize the inode's attributes and extent pointers if it
@@ -2723,7 +2723,7 @@
 /*
  * Decrement the pin count of the given inode, and wake up
  * anyone in xfs_iwait_unpin() if the count goes to 0.  The
- * inode must have been previoulsy pinned with a call to xfs_ipin().
+ * inode must have been previously pinned with a call to xfs_ipin().
  */
 void
 xfs_iunpin(
@@ -3690,7 +3690,7 @@
 xfs_iext_add(
 	xfs_ifork_t	*ifp,		/* inode fork pointer */
 	xfs_extnum_t	idx,		/* index to begin adding exts */
-	int		ext_diff)	/* nubmer of extents to add */
+	int		ext_diff)	/* number of extents to add */
 {
 	int		byte_diff;	/* new bytes being added */
 	int		new_size;	/* size of extents after adding */
@@ -4038,7 +4038,7 @@
 	xfs_extnum_t	ext_diff;	/* extents to remove in current list */
 	xfs_extnum_t	nex1;		/* number of extents before idx */
 	xfs_extnum_t	nex2;		/* extents after idx + count */
-	int		nlists;		/* entries in indirecton array */
+	int		nlists;		/* entries in indirection array */
 	int		page_idx = idx;	/* index in target extent list */
 
 	ASSERT(ifp->if_flags & XFS_IFEXTIREC);
@@ -4291,9 +4291,9 @@
 	xfs_filblks_t	blockcount = 0;	/* number of blocks in extent */
 	xfs_bmbt_rec_t	*ep = NULL;	/* pointer to target extent */
 	xfs_ext_irec_t	*erp = NULL;	/* indirection array pointer */
-	int		high;		/* upper boundry in search */
+	int		high;		/* upper boundary in search */
 	xfs_extnum_t	idx = 0;	/* index of target extent */
-	int		low;		/* lower boundry in search */
+	int		low;		/* lower boundary in search */
 	xfs_extnum_t	nextents;	/* number of file extents */
 	xfs_fileoff_t	startoff = 0;	/* start offset of extent */
 
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 36aa1fc..7497a48 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -580,7 +580,7 @@
  * been or is in the process of being flushed, then (ideally) we'd like to
  * see if the inode's buffer is still incore, and if so give it a nudge.
  * We delay doing so until the pushbuf routine, though, to avoid holding
- * the AIL lock across a call to the blackhole which is the buffercache.
+ * the AIL lock across a call to the blackhole which is the buffer cache.
  * Also we don't want to sleep in any device strategy routines, which can happen
  * if we do the subsequent bawrite in here.
  */
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 32247b6..94068d0 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -272,7 +272,7 @@
 	size_t			statstruct_size, /* sizeof struct filling */
 	char			__user *ubuffer, /* buffer with inode stats */
 	int			flags,	/* defined in xfs_itable.h */
-	int			*done)	/* 1 if there're more stats to get */
+	int			*done)	/* 1 if there are more stats to get */
 {
 	xfs_agblock_t		agbno=0;/* allocation group block number */
 	xfs_buf_t		*agbp;	/* agi header buffer */
@@ -676,7 +676,7 @@
 	xfs_mount_t		*mp,	/* mount point for filesystem */
 	xfs_ino_t		*lastinop, /* inode to return */
 	char			__user *buffer, /* buffer with inode stats */
-	int			*done)	/* 1 if there're more stats to get */
+	int			*done)	/* 1 if there are more stats to get */
 {
 	int			count;	/* count value for bulkstat call */
 	int			error;	/* return value */
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
index 047d834..11eb4e1 100644
--- a/fs/xfs/xfs_itable.h
+++ b/fs/xfs/xfs_itable.h
@@ -60,7 +60,7 @@
 	size_t		statstruct_size,/* sizeof struct that we're filling */
 	char		__user *ubuffer,/* buffer with inode stats */
 	int		flags,		/* flag to control access method */
-	int		*done);		/* 1 if there're more stats to get */
+	int		*done);		/* 1 if there are more stats to get */
 
 int
 xfs_bulkstat_single(
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 9176995..32e841d 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -59,7 +59,7 @@
 				int		num_bblks);
 STATIC int	 xlog_space_left(xlog_t *log, int cycle, int bytes);
 STATIC int	 xlog_sync(xlog_t *log, xlog_in_core_t *iclog);
-STATIC void	 xlog_unalloc_log(xlog_t *log);
+STATIC void	 xlog_dealloc_log(xlog_t *log);
 STATIC int	 xlog_write(xfs_mount_t *mp, xfs_log_iovec_t region[],
 			    int nentries, xfs_log_ticket_t tic,
 			    xfs_lsn_t *start_lsn,
@@ -304,7 +304,7 @@
 	if ((ticket->t_flags & XLOG_TIC_PERM_RESERV) == 0 ||
 	    (flags & XFS_LOG_REL_PERM_RESERV)) {
 		/*
-		 * Release ticket if not permanent reservation or a specifc
+		 * Release ticket if not permanent reservation or a specific
 		 * request has been made to release a permanent reservation.
 		 */
 		xlog_trace_loggrant(log, ticket, "xfs_log_done: (non-permanent)");
@@ -511,7 +511,7 @@
 			vfsp->vfs_flag |= VFS_RDONLY;
 		if (error) {
 			cmn_err(CE_WARN, "XFS: log mount/recovery failed: error %d", error);
-			xlog_unalloc_log(mp->m_log);
+			xlog_dealloc_log(mp->m_log);
 			return error;
 		}
 	}
@@ -667,7 +667,7 @@
 		 *
 		 * Go through the motions of sync'ing and releasing
 		 * the iclog, even though no I/O will actually happen,
-		 * we need to wait for other log I/O's that may already
+		 * we need to wait for other log I/Os that may already
 		 * be in progress.  Do this as a separate section of
 		 * code so we'll know if we ever get stuck here that
 		 * we're in this odd situation of trying to unmount
@@ -704,7 +704,7 @@
 void
 xfs_log_unmount_dealloc(xfs_mount_t *mp)
 {
-	xlog_unalloc_log(mp->m_log);
+	xlog_dealloc_log(mp->m_log);
 }
 
 /*
@@ -1492,7 +1492,7 @@
 		ASSERT(XFS_BUF_ADDR(bp) <= log->l_logBBsize-1);
 		ASSERT(XFS_BUF_ADDR(bp) + BTOBB(count) <= log->l_logBBsize);
 
-		/* account for internal log which does't start at block #0 */
+		/* account for internal log which doesn't start at block #0 */
 		XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart);
 		XFS_BUF_WRITE(bp);
 		if ((error = XFS_bwrite(bp))) {
@@ -1506,10 +1506,10 @@
 
 
 /*
- * Unallocate a log structure
+ * Deallocate a log structure
  */
 void
-xlog_unalloc_log(xlog_t *log)
+xlog_dealloc_log(xlog_t *log)
 {
 	xlog_in_core_t	*iclog, *next_iclog;
 	xlog_ticket_t	*tic, *next_tic;
@@ -1539,7 +1539,7 @@
 	if ((log->l_ticket_cnt != log->l_ticket_tcnt)  &&
 	    !XLOG_FORCED_SHUTDOWN(log)) {
 		xfs_fs_cmn_err(CE_WARN, log->l_mp,
-			"xlog_unalloc_log: (cnt: %d, total: %d)",
+			"xlog_dealloc_log: (cnt: %d, total: %d)",
 			log->l_ticket_cnt, log->l_ticket_tcnt);
 		/* ASSERT(log->l_ticket_cnt == log->l_ticket_tcnt); */
 
@@ -1562,7 +1562,7 @@
 #endif
 	log->l_mp->m_log = NULL;
 	kmem_free(log, sizeof(xlog_t));
-}	/* xlog_unalloc_log */
+}	/* xlog_dealloc_log */
 
 /*
  * Update counters atomically now that memcpy is done.
@@ -2829,7 +2829,7 @@
 
 	/*
 	 * We let the log lock go, so it's possible that we hit a log I/O
-	 * error or someother SHUTDOWN condition that marks the iclog
+	 * error or some other SHUTDOWN condition that marks the iclog
 	 * as XLOG_STATE_IOERROR before the bwrite. However, we know that
 	 * this iclog has consistent data, so we ignore IOERROR
 	 * flags after this point.
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
index 4b2ac88..eacb3d4 100644
--- a/fs/xfs/xfs_log.h
+++ b/fs/xfs/xfs_log.h
@@ -27,7 +27,7 @@
 
 #ifdef __KERNEL__
 /*
- * By comparing each compnent, we don't have to worry about extra
+ * By comparing each component, we don't have to worry about extra
  * endian issues in treating two 32 bit numbers as one 64 bit number
  */
 static inline xfs_lsn_t	_lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index add13f5..1f0016b 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -583,7 +583,7 @@
 		 *        x | x ... | x - 1 | x
 		 * Another case that fits this picture would be
 		 *        x | x + 1 | x ... | x
-		 * In this case the head really is somwhere at the end of the
+		 * In this case the head really is somewhere at the end of the
 		 * log, as one of the latest writes at the beginning was
 		 * incomplete.
 		 * One more case is
@@ -2799,7 +2799,7 @@
 		 * we don't need to worry about the block number being
 		 * truncated in > 1 TB buffers because in user-land,
 		 * we're now n32 or 64-bit so xfs_daddr_t is 64-bits so
-		 * the blkno's will get through the user-mode buffer
+		 * the blknos will get through the user-mode buffer
 		 * cache properly.  The only bad case is o32 kernels
 		 * where xfs_daddr_t is 32-bits but mount will warn us
 		 * off a > 1 TB filesystem before we get here.
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 20e8abc..72e7e78 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -393,7 +393,7 @@
 				break;
 			}
 
-			/* This ag is prefered for inodes */
+			/* This ag is preferred for inodes */
 			pag = &mp->m_perag[index];
 			pag->pagi_inodeok = 1;
 			if (index < max_metadata)
@@ -1728,7 +1728,7 @@
  * We cannot use the hotcpu_register() function because it does
  * not allow notifier instances. We need a notifier per filesystem
  * as we need to be able to identify the filesystem to balance
- * the counters out. This is acheived by having a notifier block
+ * the counters out. This is achieved by having a notifier block
  * embedded in the xfs_mount_t and doing pointer magic to get the
  * mount pointer from the notifier block address.
  */
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index ebd7396..66cbee7 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -379,7 +379,7 @@
 #endif
 	int			m_dalign;	/* stripe unit */
 	int			m_swidth;	/* stripe width */
-	int			m_sinoalign;	/* stripe unit inode alignmnt */
+	int			m_sinoalign;	/* stripe unit inode alignment */
 	int			m_attr_magicpct;/* 37% of the blocksize */
 	int			m_dir_magicpct;	/* 37% of the dir blocksize */
 	__uint8_t		m_mk_sharedro;	/* mark shared ro on unmount */
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index 82a08ba..4f6a034 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -31,7 +31,7 @@
 typedef __uint32_t	xfs_dqid_t;
 
 /*
- * Eventhough users may not have quota limits occupying all 64-bits,
+ * Even though users may not have quota limits occupying all 64-bits,
  * they may need 64-bit accounting. Hence, 64-bit quota-counters,
  * and quota-limits. This is a waste in the common case, but hey ...
  */
@@ -246,7 +246,7 @@
 #ifdef __KERNEL__
 /*
  * This check is done typically without holding the inode lock;
- * that may seem racey, but it is harmless in the context that it is used.
+ * that may seem racy, but it is harmless in the context that it is used.
  * The inode cannot go inactive as long a reference is kept, and
  * therefore if dquot(s) were attached, they'll stay consistent.
  * If, for example, the ownership of the inode changes while
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 2918956..8d056ce 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -490,7 +490,7 @@
 	case XFS_TRANS_SB_RES_FREXTENTS:
 		/*
 		 * The allocation has already been applied to the
-		 * in-core superblocks's counter.  This should only
+		 * in-core superblock's counter.  This should only
 		 * be applied to the on-disk superblock.
 		 */
 		ASSERT(delta < 0);
@@ -611,7 +611,7 @@
 
 	if (whole)
 		/*
-		 * Log the whole thing, the fields are discontiguous.
+		 * Log the whole thing, the fields are noncontiguous.
 		 */
 		xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_sb_t) - 1);
 	else
@@ -669,7 +669,7 @@
 	/*
 	 * Apply any superblock modifications to the in-core version.
 	 * The t_res_fdblocks_delta and t_res_frextents_delta fields are
-	 * explicity NOT applied to the in-core superblock.
+	 * explicitly NOT applied to the in-core superblock.
 	 * The idea is that that has already been done.
 	 */
 	if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index e48befa..100d9a4 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -354,7 +354,7 @@
 	xfs_lsn_t		t_commit_lsn;	/* log seq num of end of
 						 * transaction. */
 	struct xfs_mount	*t_mountp;	/* ptr to fs mount struct */
-	struct xfs_dquot_acct   *t_dqinfo;	/* accting info for dquots */
+	struct xfs_dquot_acct   *t_dqinfo;	/* acctg info for dquots */
 	xfs_trans_callback_t	t_callback;	/* transaction callback */
 	void			*t_callarg;	/* callback arg */
 	unsigned int		t_flags;	/* misc flags */
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c
index e341409..7c5894d 100644
--- a/fs/xfs/xfs_trans_inode.c
+++ b/fs/xfs/xfs_trans_inode.c
@@ -272,7 +272,7 @@
 	 * This is to coordinate with the xfs_iflush() and xfs_iflush_done()
 	 * routines in the eventual clearing of the ilf_fields bits.
 	 * See the big comment in xfs_iflush() for an explanation of
-	 * this coorination mechanism.
+	 * this coordination mechanism.
 	 */
 	flags |= ip->i_itemp->ili_last_fields;
 	ip->i_itemp->ili_format.ilf_fields |= flags;
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
index d4ec4df..504d2a8 100644
--- a/fs/xfs/xfs_vfsops.c
+++ b/fs/xfs/xfs_vfsops.c
@@ -880,10 +880,10 @@
  *		       determine if they should be flushed sync, async, or
  *		       delwri.
  *      SYNC_CLOSE   - This flag is passed when the system is being
- *		       unmounted.  We should sync and invalidate everthing.
+ *		       unmounted.  We should sync and invalidate everything.
  *      SYNC_FSDATA  - This indicates that the caller would like to make
  *		       sure the superblock is safe on disk.  We can ensure
- *		       this by simply makeing sure the log gets flushed
+ *		       this by simply making sure the log gets flushed
  *		       if SYNC_BDFLUSH is set, and by actually writing it
  *		       out otherwise.
  *
@@ -908,7 +908,7 @@
  *
  * This routine supports all of the flags defined for the generic VFS_SYNC
  * interface as explained above under xfs_sync.  In the interests of not
- * changing interfaces within the 6.5 family, additional internallly-
+ * changing interfaces within the 6.5 family, additional internally-
  * required functions are specified within a separate xflags parameter,
  * only available by calling this routine.
  *
@@ -1090,7 +1090,7 @@
 		 * If this is just vfs_sync() or pflushd() calling
 		 * then we can skip inodes for which it looks like
 		 * there is nothing to do.  Since we don't have the
-		 * inode locked this is racey, but these are periodic
+		 * inode locked this is racy, but these are periodic
 		 * calls so it doesn't matter.  For the others we want
 		 * to know for sure, so we at least try to lock them.
 		 */
@@ -1429,7 +1429,7 @@
  *
  * This routine supports all of the flags defined for the generic VFS_SYNC
  * interface as explained above under xfs_sync.  In the interests of not
- * changing interfaces within the 6.5 family, additional internallly-
+ * changing interfaces within the 6.5 family, additional internally-
  * required functions are specified within a separate xflags parameter,
  * only available by calling this routine.
  *
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 0f0a64e..de49601 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -848,7 +848,7 @@
 	 * If this is a synchronous mount, make sure that the
 	 * transaction goes to disk before returning to the user.
 	 * This is slightly sub-optimal in that truncates require
-	 * two sync transactions instead of one for wsync filesytems.
+	 * two sync transactions instead of one for wsync filesystems.
 	 * One for the truncate and one for the timestamps since we
 	 * don't want to change the timestamps unless we're sure the
 	 * truncate worked.  Truncates are less than 1% of the laddis
@@ -1170,7 +1170,7 @@
 
 		/*
 		 * If this inode is on the RT dev we need to flush that
-		 * cache aswell.
+		 * cache as well.
 		 */
 		if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)
 			xfs_blkdev_issue_flush(ip->i_mount->m_rtdev_targp);
@@ -1380,7 +1380,7 @@
 	 */
 	ntp = xfs_trans_dup(tp);
 	/*
-	 * Commit the transaction containing extent freeing and EFD's.
+	 * Commit the transaction containing extent freeing and EFDs.
 	 * If we get an error on the commit here or on the reserve below,
 	 * we need to unlock the inode since the new transaction doesn't
 	 * have the inode attached.
@@ -2023,7 +2023,7 @@
 	XFS_QM_DQRELE(mp, gdqp);
 
 	/*
-	 * Propogate the fact that the vnode changed after the
+	 * Propagate the fact that the vnode changed after the
 	 * xfs_inode locks have been released.
 	 */
 	VOP_VNODE_CHANGE(vp, VCHANGE_FLAGS_TRUNCATED, 3);
@@ -2370,7 +2370,7 @@
 	 * for a log reservation. Since we'll have to wait for the
 	 * inactive code to complete before returning from xfs_iget,
 	 * we need to make sure that we don't have log space reserved
-	 * when we call xfs_iget.  Instead we get an unlocked referece
+	 * when we call xfs_iget.  Instead we get an unlocked reference
 	 * to the inode before getting our log reservation.
 	 */
 	error = xfs_get_dir_entry(dentry, &ip);
@@ -3020,7 +3020,7 @@
 	 * for a log reservation.  Since we'll have to wait for the
 	 * inactive code to complete before returning from xfs_iget,
 	 * we need to make sure that we don't have log space reserved
-	 * when we call xfs_iget.  Instead we get an unlocked referece
+	 * when we call xfs_iget.  Instead we get an unlocked reference
 	 * to the inode before getting our log reservation.
 	 */
 	error = xfs_get_dir_entry(dentry, &cdp);
diff --git a/include/asm-alpha/bitops.h b/include/asm-alpha/bitops.h
index 302201f..3f88715 100644
--- a/include/asm-alpha/bitops.h
+++ b/include/asm-alpha/bitops.h
@@ -261,7 +261,7 @@
 
 static inline unsigned long ffz(unsigned long word)
 {
-#if defined(__alpha_cix__) && defined(__alpha_fix__)
+#if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
 	/* Whee.  EV67 can calculate it directly.  */
 	return __kernel_cttz(~word);
 #else
@@ -281,7 +281,7 @@
  */
 static inline unsigned long __ffs(unsigned long word)
 {
-#if defined(__alpha_cix__) && defined(__alpha_fix__)
+#if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
 	/* Whee.  EV67 can calculate it directly.  */
 	return __kernel_cttz(word);
 #else
@@ -313,20 +313,20 @@
 /*
  * fls: find last bit set.
  */
-#if defined(__alpha_cix__) && defined(__alpha_fix__)
+#if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
 static inline int fls(int word)
 {
 	return 64 - __kernel_ctlz(word & 0xffffffff);
 }
 #else
-#define fls	generic_fls
+#include <asm-generic/bitops/fls.h>
 #endif
-#define fls64   generic_fls64
+#include <asm-generic/bitops/fls64.h>
 
 /* Compute powers of two for the given integer.  */
 static inline long floor_log2(unsigned long word)
 {
-#if defined(__alpha_cix__) && defined(__alpha_fix__)
+#if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
 	return 63 - __kernel_ctlz(word);
 #else
 	long bit;
@@ -347,7 +347,7 @@
  * of bits set) of a N-bit word
  */
 
-#if defined(__alpha_cix__) && defined(__alpha_fix__)
+#if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
 /* Whee.  EV67 can calculate it directly.  */
 static inline unsigned long hweight64(unsigned long w)
 {
@@ -358,112 +358,12 @@
 #define hweight16(x)	(unsigned int) hweight64((x) & 0xfffful)
 #define hweight8(x)	(unsigned int) hweight64((x) & 0xfful)
 #else
-static inline unsigned long hweight64(unsigned long w)
-{
-	unsigned long result;
-	for (result = 0; w ; w >>= 1)
-		result += (w & 1);
-	return result;
-}
-
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x)  generic_hweight8(x)
+#include <asm-generic/bitops/hweight.h>
 #endif
 
 #endif /* __KERNEL__ */
 
-/*
- * Find next zero bit in a bitmap reasonably efficiently..
- */
-static inline unsigned long
-find_next_zero_bit(const void *addr, unsigned long size, unsigned long offset)
-{
-	const unsigned long *p = addr;
-	unsigned long result = offset & ~63UL;
-	unsigned long tmp;
-
-	p += offset >> 6;
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 63UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (64-offset);
-		if (size < 64)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 64;
-		result += 64;
-	}
-	while (size & ~63UL) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += 64;
-		size -= 64;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
- found_first:
-	tmp |= ~0UL << size;
-	if (tmp == ~0UL)        /* Are any bits zero? */
-		return result + size; /* Nope. */
- found_middle:
-	return result + ffz(tmp);
-}
-
-/*
- * Find next one bit in a bitmap reasonably efficiently.
- */
-static inline unsigned long
-find_next_bit(const void * addr, unsigned long size, unsigned long offset)
-{
-	const unsigned long *p = addr;
-	unsigned long result = offset & ~63UL;
-	unsigned long tmp;
-
-	p += offset >> 6;
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 63UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp &= ~0UL << offset;
-		if (size < 64)
-			goto found_first;
-		if (tmp)
-			goto found_middle;
-		size -= 64;
-		result += 64;
-	}
-	while (size & ~63UL) {
-		if ((tmp = *(p++)))
-			goto found_middle;
-		result += 64;
-		size -= 64;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
- found_first:
-	tmp &= ~0UL >> (64 - size);
-	if (!tmp)
-		return result + size;
- found_middle:
-	return result + __ffs(tmp);
-}
-
-/*
- * The optimizer actually does good code for this case.
- */
-#define find_first_zero_bit(addr, size) \
-	find_next_zero_bit((addr), (size), 0)
-#define find_first_bit(addr, size) \
-	find_next_bit((addr), (size), 0)
+#include <asm-generic/bitops/find.h>
 
 #ifdef __KERNEL__
 
@@ -487,21 +387,12 @@
 	return __ffs(b0) + ofs;
 }
 
+#include <asm-generic/bitops/ext2-non-atomic.h>
 
-#define ext2_set_bit                 __test_and_set_bit
 #define ext2_set_bit_atomic(l,n,a)   test_and_set_bit(n,a)
-#define ext2_clear_bit               __test_and_clear_bit
 #define ext2_clear_bit_atomic(l,n,a) test_and_clear_bit(n,a)
-#define ext2_test_bit                test_bit
-#define ext2_find_first_zero_bit     find_first_zero_bit
-#define ext2_find_next_zero_bit      find_next_zero_bit
 
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit(nr,addr) __test_and_set_bit(nr,addr)
-#define minix_set_bit(nr,addr) __set_bit(nr,addr)
-#define minix_test_and_clear_bit(nr,addr) __test_and_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr) test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
+#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-alpha/fpu.h b/include/asm-alpha/fpu.h
index c203fc2..ecb17a7 100644
--- a/include/asm-alpha/fpu.h
+++ b/include/asm-alpha/fpu.h
@@ -130,7 +130,7 @@
 {
 	unsigned long tmp, ret;
 
-#if defined(__alpha_cix__) || defined(__alpha_fix__)
+#if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
 	__asm__ __volatile__ (
 		"ftoit $f0,%0\n\t"
 		"mf_fpcr $f0\n\t"
@@ -154,7 +154,7 @@
 {
 	unsigned long tmp;
 
-#if defined(__alpha_cix__) || defined(__alpha_fix__)
+#if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
 	__asm__ __volatile__ (
 		"ftoit $f0,%0\n\t"
 		"itoft %1,$f0\n\t"
diff --git a/include/asm-alpha/mmzone.h b/include/asm-alpha/mmzone.h
index a011ef4..192d80c 100644
--- a/include/asm-alpha/mmzone.h
+++ b/include/asm-alpha/mmzone.h
@@ -59,9 +59,6 @@
 #define kvaddr_to_nid(kaddr)	pa_to_nid(__pa(kaddr))
 #define node_start_pfn(nid)	(NODE_DATA(nid)->node_start_pfn)
 
-#define local_mapnr(kvaddr) \
-      ((__pa(kvaddr) >> PAGE_SHIFT) - node_start_pfn(kvaddr_to_nid(kvaddr)))
-
 /*
  * Given a kaddr, LOCAL_BASE_ADDR finds the owning node of the memory
  * and returns the kaddr corresponding to first physical page in the
@@ -86,8 +83,7 @@
 	pte_t pte;                                                           \
 	unsigned long pfn;                                                   \
 									     \
-	pfn = ((unsigned long)((page)-page_zone(page)->zone_mem_map)) << 32; \
-	pfn += page_zone(page)->zone_start_pfn << 32;			     \
+	pfn = page_to_pfn(page) << 32; \
 	pte_val(pte) = pfn | pgprot_val(pgprot);			     \
 									     \
 	pte;								     \
@@ -104,19 +100,8 @@
 	__xx;                                                           \
 })
 
-#define pfn_to_page(pfn)						\
-({									\
- 	unsigned long kaddr = (unsigned long)__va((pfn) << PAGE_SHIFT);	\
-	(NODE_DATA(kvaddr_to_nid(kaddr))->node_mem_map + local_mapnr(kaddr));	\
-})
-
-#define page_to_pfn(page)						\
-	((page) - page_zone(page)->zone_mem_map +			\
-	 (page_zone(page)->zone_start_pfn))
-
 #define page_to_pa(page)						\
-	((( (page) - page_zone(page)->zone_mem_map )			\
-	+ page_zone(page)->zone_start_pfn) << PAGE_SHIFT)
+	(page_to_pfn(page) << PAGE_SHIFT)
 
 #define pfn_to_nid(pfn)		pa_to_nid(((u64)(pfn) << PAGE_SHIFT))
 #define pfn_valid(pfn)							\
diff --git a/include/asm-alpha/page.h b/include/asm-alpha/page.h
index fa0b41b..61bcf70 100644
--- a/include/asm-alpha/page.h
+++ b/include/asm-alpha/page.h
@@ -85,8 +85,6 @@
 #define __pa(x)			((unsigned long) (x) - PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long) (x) + PAGE_OFFSET))
 #ifndef CONFIG_DISCONTIGMEM
-#define pfn_to_page(pfn)	(mem_map + (pfn))
-#define page_to_pfn(page)	((unsigned long)((page) - mem_map))
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 
 #define pfn_valid(pfn)		((pfn) < max_mapnr)
@@ -95,9 +93,9 @@
 
 #define VM_DATA_DEFAULT_FLAGS		(VM_READ | VM_WRITE | VM_EXEC | \
 					 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
 #endif /* __KERNEL__ */
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* _ALPHA_PAGE_H */
diff --git a/include/asm-alpha/poll.h b/include/asm-alpha/poll.h
index 9570718..76f8935 100644
--- a/include/asm-alpha/poll.h
+++ b/include/asm-alpha/poll.h
@@ -12,8 +12,8 @@
 #define POLLWRNORM	(1 << 8)
 #define POLLWRBAND	(1 << 9)
 #define POLLMSG		(1 << 10)
-#define POLLREMOVE	(1 << 11)
-#define POLLRDHUP       (1 << 12)
+#define POLLREMOVE	(1 << 12)
+#define POLLRDHUP       (1 << 13)
 
 
 struct pollfd {
diff --git a/include/asm-arm/arch-pxa/sharpsl.h b/include/asm-arm/arch-pxa/sharpsl.h
index 0b43495..94cb498 100644
--- a/include/asm-arm/arch-pxa/sharpsl.h
+++ b/include/asm-arm/arch-pxa/sharpsl.h
@@ -27,6 +27,8 @@
  */
 struct corgibl_machinfo {
 	int max_intensity;
+	int default_intensity;
+	int limit_mask;
 	void (*set_bl_intensity)(int intensity);
 };
 extern void corgibl_limit_intensity(int limit);
diff --git a/include/asm-arm/bitops.h b/include/asm-arm/bitops.h
index d02de72..0ac54b1 100644
--- a/include/asm-arm/bitops.h
+++ b/include/asm-arm/bitops.h
@@ -117,65 +117,7 @@
 	return res & mask;
 }
 
-/*
- * Now the non-atomic variants.  We let the compiler handle all
- * optimisations for these.  These are all _native_ endian.
- */
-static inline void __set_bit(int nr, volatile unsigned long *p)
-{
-	p[nr >> 5] |= (1UL << (nr & 31));
-}
-
-static inline void __clear_bit(int nr, volatile unsigned long *p)
-{
-	p[nr >> 5] &= ~(1UL << (nr & 31));
-}
-
-static inline void __change_bit(int nr, volatile unsigned long *p)
-{
-	p[nr >> 5] ^= (1UL << (nr & 31));
-}
-
-static inline int __test_and_set_bit(int nr, volatile unsigned long *p)
-{
-	unsigned long oldval, mask = 1UL << (nr & 31);
-
-	p += nr >> 5;
-
-	oldval = *p;
-	*p = oldval | mask;
-	return oldval & mask;
-}
-
-static inline int __test_and_clear_bit(int nr, volatile unsigned long *p)
-{
-	unsigned long oldval, mask = 1UL << (nr & 31);
-
-	p += nr >> 5;
-
-	oldval = *p;
-	*p = oldval & ~mask;
-	return oldval & mask;
-}
-
-static inline int __test_and_change_bit(int nr, volatile unsigned long *p)
-{
-	unsigned long oldval, mask = 1UL << (nr & 31);
-
-	p += nr >> 5;
-
-	oldval = *p;
-	*p = oldval ^ mask;
-	return oldval & mask;
-}
-
-/*
- * This routine doesn't need to be atomic.
- */
-static inline int __test_bit(int nr, const volatile unsigned long * p)
-{
-	return (p[nr >> 5] >> (nr & 31)) & 1UL;
-}
+#include <asm-generic/bitops/non-atomic.h>
 
 /*
  *  A note about Endian-ness.
@@ -261,7 +203,6 @@
 #define test_and_set_bit(nr,p)		ATOMIC_BITOP_LE(test_and_set_bit,nr,p)
 #define test_and_clear_bit(nr,p)	ATOMIC_BITOP_LE(test_and_clear_bit,nr,p)
 #define test_and_change_bit(nr,p)	ATOMIC_BITOP_LE(test_and_change_bit,nr,p)
-#define test_bit(nr,p)			__test_bit(nr,p)
 #define find_first_zero_bit(p,sz)	_find_first_zero_bit_le(p,sz)
 #define find_next_zero_bit(p,sz,off)	_find_next_zero_bit_le(p,sz,off)
 #define find_first_bit(p,sz)		_find_first_bit_le(p,sz)
@@ -280,7 +221,6 @@
 #define test_and_set_bit(nr,p)		ATOMIC_BITOP_BE(test_and_set_bit,nr,p)
 #define test_and_clear_bit(nr,p)	ATOMIC_BITOP_BE(test_and_clear_bit,nr,p)
 #define test_and_change_bit(nr,p)	ATOMIC_BITOP_BE(test_and_change_bit,nr,p)
-#define test_bit(nr,p)			__test_bit(nr,p)
 #define find_first_zero_bit(p,sz)	_find_first_zero_bit_be(p,sz)
 #define find_next_zero_bit(p,sz,off)	_find_next_zero_bit_be(p,sz,off)
 #define find_first_bit(p,sz)		_find_first_bit_be(p,sz)
@@ -292,97 +232,60 @@
 
 #if __LINUX_ARM_ARCH__ < 5
 
-/*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
- */
-static inline unsigned long ffz(unsigned long word)
-{
-	int k;
-
-	word = ~word;
-	k = 31;
-	if (word & 0x0000ffff) { k -= 16; word <<= 16; }
-	if (word & 0x00ff0000) { k -= 8;  word <<= 8;  }
-	if (word & 0x0f000000) { k -= 4;  word <<= 4;  }
-	if (word & 0x30000000) { k -= 2;  word <<= 2;  }
-	if (word & 0x40000000) { k -= 1; }
-        return k;
-}
-
-/*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
- */
-static inline unsigned long __ffs(unsigned long word)
-{
-	int k;
-
-	k = 31;
-	if (word & 0x0000ffff) { k -= 16; word <<= 16; }
-	if (word & 0x00ff0000) { k -= 8;  word <<= 8;  }
-	if (word & 0x0f000000) { k -= 4;  word <<= 4;  }
-	if (word & 0x30000000) { k -= 2;  word <<= 2;  }
-	if (word & 0x40000000) { k -= 1; }
-        return k;
-}
-
-/*
- * fls: find last bit set.
- */
-
-#define fls(x) generic_fls(x)
-#define fls64(x)   generic_fls64(x)
-
-/*
- * ffs: find first bit set. This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
- */
-
-#define ffs(x) generic_ffs(x)
+#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/ffs.h>
 
 #else
 
+static inline int constant_fls(int x)
+{
+	int r = 32;
+
+	if (!x)
+		return 0;
+	if (!(x & 0xffff0000u)) {
+		x <<= 16;
+		r -= 16;
+	}
+	if (!(x & 0xff000000u)) {
+		x <<= 8;
+		r -= 8;
+	}
+	if (!(x & 0xf0000000u)) {
+		x <<= 4;
+		r -= 4;
+	}
+	if (!(x & 0xc0000000u)) {
+		x <<= 2;
+		r -= 2;
+	}
+	if (!(x & 0x80000000u)) {
+		x <<= 1;
+		r -= 1;
+	}
+	return r;
+}
+
 /*
  * On ARMv5 and above those functions can be implemented around
  * the clz instruction for much better code efficiency.
  */
 
 #define fls(x) \
-	( __builtin_constant_p(x) ? generic_fls(x) : \
+	( __builtin_constant_p(x) ? constant_fls(x) : \
 	  ({ int __r; asm("clz\t%0, %1" : "=r"(__r) : "r"(x) : "cc"); 32-__r; }) )
-#define fls64(x)   generic_fls64(x)
 #define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); })
 #define __ffs(x) (ffs(x) - 1)
 #define ffz(x) __ffs( ~(x) )
 
 #endif
 
-/*
- * Find first bit set in a 168-bit bitmap, where the first
- * 128 bits are unlikely to be set.
- */
-static inline int sched_find_first_bit(const unsigned long *b)
-{
-	unsigned long v;
-	unsigned int off;
+#include <asm-generic/bitops/fls64.h>
 
-	for (off = 0; v = b[off], off < 4; off++) {
-		if (unlikely(v))
-			break;
-	}
-	return __ffs(v) + off * 32;
-}
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/hweight.h>
 
 /*
  * Ext2 is defined to use little-endian byte ordering.
@@ -397,7 +300,7 @@
 #define ext2_clear_bit_atomic(lock,nr,p)        \
                 test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
 #define ext2_test_bit(nr,p)			\
-		__test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
+		test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
 #define ext2_find_first_zero_bit(p,sz)		\
 		_find_first_zero_bit_le(p,sz)
 #define ext2_find_next_zero_bit(p,sz,off)	\
@@ -410,7 +313,7 @@
 #define minix_set_bit(nr,p)			\
 		__set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
 #define minix_test_bit(nr,p)			\
-		__test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
+		test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
 #define minix_test_and_set_bit(nr,p)		\
 		__test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
 #define minix_test_and_clear_bit(nr,p)		\
diff --git a/include/asm-arm/memory.h b/include/asm-arm/memory.h
index b4e1146..afa5c3e 100644
--- a/include/asm-arm/memory.h
+++ b/include/asm-arm/memory.h
@@ -172,9 +172,7 @@
  *  virt_addr_valid(k)	indicates whether a virtual address is valid
  */
 #ifndef CONFIG_DISCONTIGMEM
-
-#define page_to_pfn(page)	(((page) - mem_map) + PHYS_PFN_OFFSET)
-#define pfn_to_page(pfn)	((mem_map + (pfn)) - PHYS_PFN_OFFSET)
+#define ARCH_PFN_OFFSET		(PHYS_PFN_OFFSET)
 #define pfn_valid(pfn)		((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr))
 
 #define virt_to_page(kaddr)	(pfn_to_page(__pa(kaddr) >> PAGE_SHIFT))
@@ -189,13 +187,8 @@
  * around in memory.
  */
 #include <linux/numa.h>
-
-#define page_to_pfn(page)					\
-	(( (page) - page_zone(page)->zone_mem_map)		\
-	  + page_zone(page)->zone_start_pfn)
-
-#define pfn_to_page(pfn)					\
-	(PFN_TO_MAPBASE(pfn) + LOCAL_MAP_NR((pfn) << PAGE_SHIFT))
+#define arch_pfn_to_nid(pfn)	(PFN_TO_NID(pfn))
+#define arch_local_page_offset(pfn, nid) (LOCAL_MAP_NR((pfn) << PAGE_OFFSET))
 
 #define pfn_valid(pfn)						\
 	({							\
@@ -243,4 +236,6 @@
 
 #endif
 
+#include <asm-generic/memory_model.h>
+
 #endif
diff --git a/include/asm-arm/rtc.h b/include/asm-arm/rtc.h
index 370dfe7..1a5c923 100644
--- a/include/asm-arm/rtc.h
+++ b/include/asm-arm/rtc.h
@@ -25,9 +25,6 @@
 	int		(*proc)(char *buf);
 };
 
-void rtc_time_to_tm(unsigned long, struct rtc_time *);
-int rtc_tm_to_time(struct rtc_time *, unsigned long *);
-int rtc_valid_tm(struct rtc_time *);
 void rtc_next_alarm_time(struct rtc_time *, struct rtc_time *, struct rtc_time *);
 void rtc_update(unsigned long, unsigned long);
 int register_rtc(struct rtc_ops *);
diff --git a/include/asm-arm26/bitops.h b/include/asm-arm26/bitops.h
index d87f863..19a6957 100644
--- a/include/asm-arm26/bitops.h
+++ b/include/asm-arm26/bitops.h
@@ -117,65 +117,7 @@
 	return res & mask;
 }
 
-/*
- * Now the non-atomic variants.  We let the compiler handle all
- * optimisations for these.  These are all _native_ endian.
- */
-static inline void __set_bit(int nr, volatile unsigned long *p)
-{
-	p[nr >> 5] |= (1UL << (nr & 31));
-}
-
-static inline void __clear_bit(int nr, volatile unsigned long *p)
-{
-	p[nr >> 5] &= ~(1UL << (nr & 31));
-}
-
-static inline void __change_bit(int nr, volatile unsigned long *p)
-{
-	p[nr >> 5] ^= (1UL << (nr & 31));
-}
-
-static inline int __test_and_set_bit(int nr, volatile unsigned long *p)
-{
-	unsigned long oldval, mask = 1UL << (nr & 31);
-
-	p += nr >> 5;
-
-	oldval = *p;
-	*p = oldval | mask;
-	return oldval & mask;
-}
-
-static inline int __test_and_clear_bit(int nr, volatile unsigned long *p)
-{
-	unsigned long oldval, mask = 1UL << (nr & 31);
-
-	p += nr >> 5;
-
-	oldval = *p;
-	*p = oldval & ~mask;
-	return oldval & mask;
-}
-
-static inline int __test_and_change_bit(int nr, volatile unsigned long *p)
-{
-	unsigned long oldval, mask = 1UL << (nr & 31);
-
-	p += nr >> 5;
-
-	oldval = *p;
-	*p = oldval ^ mask;
-	return oldval & mask;
-}
-
-/*
- * This routine doesn't need to be atomic.
- */
-static inline int __test_bit(int nr, const volatile unsigned long * p)
-{
-	return (p[nr >> 5] >> (nr & 31)) & 1UL;
-}
+#include <asm-generic/bitops/non-atomic.h>
 
 /*
  * Little endian assembly bitops.  nr = 0 -> byte 0 bit 0.
@@ -211,7 +153,6 @@
 #define test_and_set_bit(nr,p)		ATOMIC_BITOP_LE(test_and_set_bit,nr,p)
 #define test_and_clear_bit(nr,p)	ATOMIC_BITOP_LE(test_and_clear_bit,nr,p)
 #define test_and_change_bit(nr,p)	ATOMIC_BITOP_LE(test_and_change_bit,nr,p)
-#define test_bit(nr,p)			__test_bit(nr,p)
 #define find_first_zero_bit(p,sz)	_find_first_zero_bit_le(p,sz)
 #define find_next_zero_bit(p,sz,off)	_find_next_zero_bit_le(p,sz,off)
 #define find_first_bit(p,sz)		_find_first_bit_le(p,sz)
@@ -219,80 +160,13 @@
 
 #define WORD_BITOFF_TO_LE(x)		((x))
 
-/*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
- */
-static inline unsigned long ffz(unsigned long word)
-{
-	int k;
-
-	word = ~word;
-	k = 31;
-	if (word & 0x0000ffff) { k -= 16; word <<= 16; }
-	if (word & 0x00ff0000) { k -= 8;  word <<= 8;  }
-	if (word & 0x0f000000) { k -= 4;  word <<= 4;  }
-	if (word & 0x30000000) { k -= 2;  word <<= 2;  }
-	if (word & 0x40000000) { k -= 1; }
-        return k;
-}
-
-/*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
- */
-static inline unsigned long __ffs(unsigned long word)
-{
-	int k;
-
-	k = 31;
-	if (word & 0x0000ffff) { k -= 16; word <<= 16; }
-	if (word & 0x00ff0000) { k -= 8;  word <<= 8;  }
-	if (word & 0x0f000000) { k -= 4;  word <<= 4;  }
-	if (word & 0x30000000) { k -= 2;  word <<= 2;  }
-	if (word & 0x40000000) { k -= 1; }
-        return k;
-}
-
-/*
- * fls: find last bit set.
- */
-
-#define fls(x) generic_fls(x)
-#define fls64(x)   generic_fls64(x)
-
-/*
- * ffs: find first bit set. This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
- */
-
-#define ffs(x) generic_ffs(x)
-
-/*
- * Find first bit set in a 168-bit bitmap, where the first
- * 128 bits are unlikely to be set.
- */
-static inline int sched_find_first_bit(unsigned long *b)
-{
-	unsigned long v;
-	unsigned int off;
-
-	for (off = 0; v = b[off], off < 4; off++) {
-		if (unlikely(v))
-			break;
-	}
-	return __ffs(v) + off * 32;
-}
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
+#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/hweight.h>
 
 /*
  * Ext2 is defined to use little-endian byte ordering.
@@ -307,7 +181,7 @@
 #define ext2_clear_bit_atomic(lock,nr,p)        \
                 test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
 #define ext2_test_bit(nr,p)			\
-		__test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
+		test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
 #define ext2_find_first_zero_bit(p,sz)		\
 		_find_first_zero_bit_le(p,sz)
 #define ext2_find_next_zero_bit(p,sz,off)	\
@@ -320,7 +194,7 @@
 #define minix_set_bit(nr,p)			\
 		__set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
 #define minix_test_bit(nr,p)			\
-		__test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
+		test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
 #define minix_test_and_set_bit(nr,p)		\
 		__test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
 #define minix_test_and_clear_bit(nr,p)		\
diff --git a/include/asm-arm26/memory.h b/include/asm-arm26/memory.h
index 20d7861..a65f10b 100644
--- a/include/asm-arm26/memory.h
+++ b/include/asm-arm26/memory.h
@@ -81,8 +81,7 @@
  *  virt_to_page(k)	convert a _valid_ virtual address to struct page *
  *  virt_addr_valid(k)	indicates whether a virtual address is valid
  */
-#define page_to_pfn(page)	(((page) - mem_map) + PHYS_PFN_OFFSET)
-#define pfn_to_page(pfn)	((mem_map + (pfn)) - PHYS_PFN_OFFSET)
+#define ARCH_PFN_OFFSET		(PHYS_PFN_OFFSET)
 #define pfn_valid(pfn)		((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr))
 
 #define virt_to_page(kaddr)	(pfn_to_page(__pa(kaddr) >> PAGE_SHIFT))
@@ -98,4 +97,5 @@
  */
 #define page_to_bus(page)	(page_address(page))
 
+#include <asm-generic/memory_model.h>
 #endif
diff --git a/include/asm-cris/bitops.h b/include/asm-cris/bitops.h
index b7fef15..a569065 100644
--- a/include/asm-cris/bitops.h
+++ b/include/asm-cris/bitops.h
@@ -39,8 +39,6 @@
 
 #define set_bit(nr, addr)    (void)test_and_set_bit(nr, addr)
 
-#define __set_bit(nr, addr)    (void)__test_and_set_bit(nr, addr)
-
 /*
  * clear_bit - Clears a bit in memory
  * @nr: Bit to clear
@@ -54,8 +52,6 @@
 
 #define clear_bit(nr, addr)  (void)test_and_clear_bit(nr, addr)
 
-#define __clear_bit(nr, addr)  (void)__test_and_clear_bit(nr, addr)
-
 /*
  * change_bit - Toggle a bit in memory
  * @nr: Bit to change
@@ -68,18 +64,6 @@
 
 #define change_bit(nr, addr) (void)test_and_change_bit(nr, addr)
 
-/*
- * __change_bit - Toggle a bit in memory
- * @nr: the bit to change
- * @addr: the address to start counting from
- *
- * Unlike change_bit(), this function is non-atomic and may be reordered.
- * If it's called on the same region of memory simultaneously, the effect
- * may be that only one operation succeeds.
- */
-
-#define __change_bit(nr, addr) (void)__test_and_change_bit(nr, addr)
-
 /**
  * test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
@@ -101,19 +85,6 @@
 	retval = (mask & *adr) != 0;
 	*adr |= mask;
 	cris_atomic_restore(addr, flags);
-	local_irq_restore(flags);
-	return retval;
-}
-
-static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned int mask, retval;
-	unsigned int *adr = (unsigned int *)addr;
-	
-	adr += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	retval = (mask & *adr) != 0;
-	*adr |= mask;
 	return retval;
 }
 
@@ -148,27 +119,6 @@
 }
 
 /**
- * __test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to clear
- * @addr: Address to count from
- *
- * This operation is non-atomic and can be reordered.  
- * If two examples of this operation race, one can appear to succeed
- * but actually fail.  You must protect multiple accesses with a lock.
- */
-
-static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned int mask, retval;
-	unsigned int *adr = (unsigned int *)addr;
-	
-	adr += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	retval = (mask & *adr) != 0;
-	*adr &= ~mask;
-	return retval;
-}
-/**
  * test_and_change_bit - Change a bit and return its old value
  * @nr: Bit to change
  * @addr: Address to count from
@@ -191,42 +141,7 @@
 	return retval;
 }
 
-/* WARNING: non atomic and it can be reordered! */
-
-static inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned int mask, retval;
-	unsigned int *adr = (unsigned int *)addr;
-
-	adr += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	retval = (mask & *adr) != 0;
-	*adr ^= mask;
-
-	return retval;
-}
-
-/**
- * test_bit - Determine whether a bit is set
- * @nr: bit number to test
- * @addr: Address to start counting from
- *
- * This routine doesn't need to be atomic.
- */
-
-static inline int test_bit(int nr, const volatile unsigned long *addr)
-{
-	unsigned int mask;
-	unsigned int *adr = (unsigned int *)addr;
-	
-	adr += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	return ((mask & *adr) != 0);
-}
-
-/*
- * Find-bit routines..
- */
+#include <asm-generic/bitops/non-atomic.h>
 
 /*
  * Since we define it "external", it collides with the built-in
@@ -235,152 +150,18 @@
  */
 #define ffs kernel_ffs
 
-/*
- * fls: find last bit set.
- */
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/find.h>
 
-#define fls(x) generic_fls(x)
-#define fls64(x)   generic_fls64(x)
+#include <asm-generic/bitops/ext2-non-atomic.h>
 
-/*
- * hweightN - returns the hamming weight of a N-bit word
- * @x: the word to weigh
- *
- * The Hamming Weight of a number is the total number of bits set in it.
- */
-
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
-
-/**
- * find_next_zero_bit - find the first zero bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-static inline int find_next_zero_bit (const unsigned long * addr, int size, int offset)
-{
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-	
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (32-offset);
-		if (size < 32)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size & ~31UL) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-	
- found_first:
-	tmp |= ~0UL << size;
- found_middle:
-	return result + ffz(tmp);
-}
-
-/**
- * find_next_bit - find the first set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-static __inline__ int find_next_bit(const unsigned long *addr, int size, int offset)
-{
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-        unsigned long result = offset & ~31UL;
-        unsigned long tmp;
-
-        if (offset >= size)
-                return size;
-        size -= result;
-        offset &= 31UL;
-        if (offset) {
-                tmp = *(p++);
-                tmp &= (~0UL << offset);
-                if (size < 32)
-                        goto found_first;
-                if (tmp)
-                        goto found_middle;
-                size -= 32;
-                result += 32;
-        }
-        while (size & ~31UL) {
-                if ((tmp = *(p++)))
-                        goto found_middle;
-                result += 32;
-                size -= 32;
-        }
-        if (!size)
-                return result;
-        tmp = *p;
-
-found_first:
-        tmp &= (~0UL >> (32 - size));
-        if (tmp == 0UL)        /* Are any bits set? */
-                return result + size; /* Nope. */
-found_middle:
-        return result + __ffs(tmp);
-}
-
-/**
- * find_first_zero_bit - find the first zero bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first zero bit, not the number of the byte
- * containing a bit.
- */
-
-#define find_first_zero_bit(addr, size) \
-        find_next_zero_bit((addr), (size), 0)
-#define find_first_bit(addr, size) \
-        find_next_bit((addr), (size), 0)
-
-#define ext2_set_bit                 test_and_set_bit
 #define ext2_set_bit_atomic(l,n,a)   test_and_set_bit(n,a)
-#define ext2_clear_bit               test_and_clear_bit
 #define ext2_clear_bit_atomic(l,n,a) test_and_clear_bit(n,a)
-#define ext2_test_bit                test_bit
-#define ext2_find_first_zero_bit     find_first_zero_bit
-#define ext2_find_next_zero_bit      find_next_zero_bit
 
-/* Bitmap functions for the minix filesystem.  */
-#define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
-#define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr) test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
-
-static inline int sched_find_first_bit(const unsigned long *b)
-{
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (unlikely(b[3]))
-		return __ffs(b[3]) + 96;
-	if (b[4])
-		return __ffs(b[4]) + 128;
-	return __ffs(b[5]) + 32 + 128;
-}
+#include <asm-generic/bitops/minix.h>
+#include <asm-generic/bitops/sched.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-cris/page.h b/include/asm-cris/page.h
index c99c478..3787633 100644
--- a/include/asm-cris/page.h
+++ b/include/asm-cris/page.h
@@ -43,8 +43,7 @@
 
 /* On CRIS the PFN numbers doesn't start at 0 so we have to compensate */
 /* for that before indexing into the page table starting at mem_map    */
-#define pfn_to_page(pfn)	(mem_map + ((pfn) - (PAGE_OFFSET >> PAGE_SHIFT)))
-#define page_to_pfn(page)	((unsigned long)((page) - mem_map) + (PAGE_OFFSET >> PAGE_SHIFT))
+#define ARCH_PFN_OFFSET		(PAGE_OFFSET >> PAGE_SHIFT)
 #define pfn_valid(pfn)		(((pfn) - (PAGE_OFFSET >> PAGE_SHIFT)) < max_mapnr)
 
 /* to index into the page map. our pages all start at physical addr PAGE_OFFSET so
@@ -77,6 +76,7 @@
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* _CRIS_PAGE_H */
diff --git a/include/asm-frv/bitops.h b/include/asm-frv/bitops.h
index f686b51..6344d06 100644
--- a/include/asm-frv/bitops.h
+++ b/include/asm-frv/bitops.h
@@ -22,20 +22,7 @@
 
 #ifdef __KERNEL__
 
-/*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
- */
-static inline unsigned long ffz(unsigned long word)
-{
-	unsigned long result = 0;
-
-	while (word & 1) {
-		result++;
-		word >>= 1;
-	}
-	return result;
-}
+#include <asm-generic/bitops/ffz.h>
 
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
@@ -171,51 +158,9 @@
  __constant_test_bit((nr),(addr)) : \
  __test_bit((nr),(addr)))
 
-extern int find_next_bit(const unsigned long *addr, int size, int offset);
-
-#define find_first_bit(addr, size) find_next_bit(addr, size, 0)
-
-#define find_first_zero_bit(addr, size) \
-        find_next_zero_bit((addr), (size), 0)
-
-static inline int find_next_zero_bit(const void *addr, int size, int offset)
-{
-	const unsigned long *p = ((const unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (32-offset);
-		if (size < 32)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size & ~31UL) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp |= ~0UL << size;
-found_middle:
-	return result + ffz(tmp);
-}
-
-#define ffs(x) generic_ffs(x)
-#define __ffs(x) (ffs(x) - 1)
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/find.h>
 
 /*
  * fls: find last bit set.
@@ -228,114 +173,17 @@
 							\
 	bit ? 33 - bit : bit;				\
 })
-#define fls64(x)   generic_fls64(x)
 
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-static inline int sched_find_first_bit(const unsigned long *b)
-{
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-}
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/hweight.h>
 
+#include <asm-generic/bitops/ext2-non-atomic.h>
 
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
+#define ext2_set_bit_atomic(lock,nr,addr)	test_and_set_bit  ((nr) ^ 0x18, (addr))
+#define ext2_clear_bit_atomic(lock,nr,addr)	test_and_clear_bit((nr) ^ 0x18, (addr))
 
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
-
-#define ext2_set_bit(nr, addr)		test_and_set_bit  ((nr) ^ 0x18, (addr))
-#define ext2_clear_bit(nr, addr)	test_and_clear_bit((nr) ^ 0x18, (addr))
-
-#define ext2_set_bit_atomic(lock,nr,addr)	ext2_set_bit((nr), addr)
-#define ext2_clear_bit_atomic(lock,nr,addr)	ext2_clear_bit((nr), addr)
-
-static inline int ext2_test_bit(int nr, const volatile void * addr)
-{
-	const volatile unsigned char *ADDR = (const unsigned char *) addr;
-	int mask;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	return ((mask & *ADDR) != 0);
-}
-
-#define ext2_find_first_zero_bit(addr, size) \
-        ext2_find_next_zero_bit((addr), (size), 0)
-
-static inline unsigned long ext2_find_next_zero_bit(const void *addr,
-						    unsigned long size,
-						    unsigned long offset)
-{
-	const unsigned long *p = ((const unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if(offset) {
-		/* We hold the little endian value in tmp, but then the
-		 * shift is illegal. So we could keep a big endian value
-		 * in tmp, like this:
-		 *
-		 * tmp = __swab32(*(p++));
-		 * tmp |= ~0UL >> (32-offset);
-		 *
-		 * but this would decrease preformance, so we change the
-		 * shift:
-		 */
-		tmp = *(p++);
-		tmp |= __swab32(~0UL >> (32-offset));
-		if(size < 32)
-			goto found_first;
-		if(~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while(size & ~31UL) {
-		if(~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if(!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	/* tmp is little endian, so we would have to swab the shift,
-	 * see above. But then we have to swab tmp below for ffz, so
-	 * we might as well do this here.
-	 */
-	return result + ffz(__swab32(tmp) | (~0UL << size));
-found_middle:
-	return result + ffz(__swab32(tmp));
-}
-
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit(nr,addr)		ext2_set_bit(nr,addr)
-#define minix_set_bit(nr,addr)			ext2_set_bit(nr,addr)
-#define minix_test_and_clear_bit(nr,addr)	ext2_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr)			ext2_test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size)	ext2_find_first_zero_bit(addr,size)
+#include <asm-generic/bitops/minix-le.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-frv/futex.h b/include/asm-frv/futex.h
index fca9d90..08b3d1d 100644
--- a/include/asm-frv/futex.h
+++ b/include/asm-frv/futex.h
@@ -9,5 +9,11 @@
 
 extern int futex_atomic_op_inuser(int encoded_op, int __user *uaddr);
 
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+	return -ENOSYS;
+}
+
 #endif
 #endif
diff --git a/include/asm-frv/page.h b/include/asm-frv/page.h
index b8221b6..dc0f7e0 100644
--- a/include/asm-frv/page.h
+++ b/include/asm-frv/page.h
@@ -57,13 +57,9 @@
 extern unsigned long max_pfn;
 
 #ifdef CONFIG_MMU
-#define pfn_to_page(pfn)	(mem_map + (pfn))
-#define page_to_pfn(page)	((unsigned long) ((page) - mem_map))
 #define pfn_valid(pfn)		((pfn) < max_mapnr)
-
 #else
-#define pfn_to_page(pfn)	(&mem_map[(pfn) - (PAGE_OFFSET >> PAGE_SHIFT)])
-#define page_to_pfn(page)	((PAGE_OFFSET >> PAGE_SHIFT) + (unsigned long) ((page) - mem_map))
+#define ARCH_PFN_OFFSET		(PAGE_OFFSET >> PAGE_SHIFT)
 #define pfn_valid(pfn)		((pfn) >= min_low_pfn && (pfn) < max_low_pfn)
 
 #endif
@@ -87,6 +83,7 @@
 #define WANT_PAGE_VIRTUAL	1
 #endif
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* _ASM_PAGE_H */
diff --git a/include/asm-generic/bitops.h b/include/asm-generic/bitops.h
index 0e6d985..1f9d991 100644
--- a/include/asm-generic/bitops.h
+++ b/include/asm-generic/bitops.h
@@ -5,77 +5,27 @@
  * For the benefit of those who are trying to port Linux to another
  * architecture, here are some C-language equivalents.  You should
  * recode these in the native assembly language, if at all possible.
- * To guarantee atomicity, these routines call cli() and sti() to
- * disable interrupts while they operate.  (You have to provide inline
- * routines to cli() and sti().)
- *
- * Also note, these routines assume that you have 32 bit longs.
- * You will have to change this if you are trying to port Linux to the
- * Alpha architecture or to a Cray.  :-)
  * 
  * C language equivalents written by Theodore Ts'o, 9/26/92
  */
 
-extern __inline__ int set_bit(int nr,long * addr)
-{
-	int	mask, retval;
-
-	addr += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	cli();
-	retval = (mask & *addr) != 0;
-	*addr |= mask;
-	sti();
-	return retval;
-}
-
-extern __inline__ int clear_bit(int nr, long * addr)
-{
-	int	mask, retval;
-
-	addr += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	cli();
-	retval = (mask & *addr) != 0;
-	*addr &= ~mask;
-	sti();
-	return retval;
-}
-
-extern __inline__ int test_bit(int nr, const unsigned long * addr)
-{
-	int	mask;
-
-	addr += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	return ((mask & *addr) != 0);
-}
-
-/*
- * fls: find last bit set.
- */
-
-#define fls(x) generic_fls(x)
-#define fls64(x)   generic_fls64(x)
+#include <asm-generic/bitops/atomic.h>
+#include <asm-generic/bitops/non-atomic.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/find.h>
 
 #ifdef __KERNEL__
 
-/*
- * ffs: find first bit set. This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
- */
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/hweight.h>
 
-#define ffs(x) generic_ffs(x)
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
+#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/ext2-atomic.h>
+#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-generic/bitops/__ffs.h b/include/asm-generic/bitops/__ffs.h
new file mode 100644
index 0000000..9a3274a
--- /dev/null
+++ b/include/asm-generic/bitops/__ffs.h
@@ -0,0 +1,43 @@
+#ifndef _ASM_GENERIC_BITOPS___FFS_H_
+#define _ASM_GENERIC_BITOPS___FFS_H_
+
+#include <asm/types.h>
+
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static inline unsigned long __ffs(unsigned long word)
+{
+	int num = 0;
+
+#if BITS_PER_LONG == 64
+	if ((word & 0xffffffff) == 0) {
+		num += 32;
+		word >>= 32;
+	}
+#endif
+	if ((word & 0xffff) == 0) {
+		num += 16;
+		word >>= 16;
+	}
+	if ((word & 0xff) == 0) {
+		num += 8;
+		word >>= 8;
+	}
+	if ((word & 0xf) == 0) {
+		num += 4;
+		word >>= 4;
+	}
+	if ((word & 0x3) == 0) {
+		num += 2;
+		word >>= 2;
+	}
+	if ((word & 0x1) == 0)
+		num += 1;
+	return num;
+}
+
+#endif /* _ASM_GENERIC_BITOPS___FFS_H_ */
diff --git a/include/asm-generic/bitops/atomic.h b/include/asm-generic/bitops/atomic.h
new file mode 100644
index 0000000..7833931
--- /dev/null
+++ b/include/asm-generic/bitops/atomic.h
@@ -0,0 +1,191 @@
+#ifndef _ASM_GENERIC_BITOPS_ATOMIC_H_
+#define _ASM_GENERIC_BITOPS_ATOMIC_H_
+
+#include <asm/types.h>
+
+#define BITOP_MASK(nr)		(1UL << ((nr) % BITS_PER_LONG))
+#define BITOP_WORD(nr)		((nr) / BITS_PER_LONG)
+
+#ifdef CONFIG_SMP
+#include <asm/spinlock.h>
+#include <asm/cache.h>		/* we use L1_CACHE_BYTES */
+
+/* Use an array of spinlocks for our atomic_ts.
+ * Hash function to index into a different SPINLOCK.
+ * Since "a" is usually an address, use one spinlock per cacheline.
+ */
+#  define ATOMIC_HASH_SIZE 4
+#  define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) a)/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ]))
+
+extern raw_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
+
+/* Can't use raw_spin_lock_irq because of #include problems, so
+ * this is the substitute */
+#define _atomic_spin_lock_irqsave(l,f) do {	\
+	raw_spinlock_t *s = ATOMIC_HASH(l);	\
+	local_irq_save(f);			\
+	__raw_spin_lock(s);			\
+} while(0)
+
+#define _atomic_spin_unlock_irqrestore(l,f) do {	\
+	raw_spinlock_t *s = ATOMIC_HASH(l);		\
+	__raw_spin_unlock(s);				\
+	local_irq_restore(f);				\
+} while(0)
+
+
+#else
+#  define _atomic_spin_lock_irqsave(l,f) do { local_irq_save(f); } while (0)
+#  define _atomic_spin_unlock_irqrestore(l,f) do { local_irq_restore(f); } while (0)
+#endif
+
+/*
+ * NMI events can occur at any time, including when interrupts have been
+ * disabled by *_irqsave().  So you can get NMI events occurring while a
+ * *_bit function is holding a spin lock.  If the NMI handler also wants
+ * to do bit manipulation (and they do) then you can get a deadlock
+ * between the original caller of *_bit() and the NMI handler.
+ *
+ * by Keith Owens
+ */
+
+/**
+ * set_bit - Atomically set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * This function is atomic and may not be reordered.  See __set_bit()
+ * if you do not require the atomic guarantees.
+ *
+ * Note: there are no guarantees that this function will not be reordered
+ * on non x86 architectures, so if you are writting portable code,
+ * make sure not to rely on its reordering guarantees.
+ *
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static inline void set_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+	unsigned long flags;
+
+	_atomic_spin_lock_irqsave(p, flags);
+	*p  |= mask;
+	_atomic_spin_unlock_irqrestore(p, flags);
+}
+
+/**
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * clear_bit() is atomic and may not be reordered.  However, it does
+ * not contain a memory barrier, so if it is used for locking purposes,
+ * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
+ * in order to ensure changes are visible on other processors.
+ */
+static inline void clear_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+	unsigned long flags;
+
+	_atomic_spin_lock_irqsave(p, flags);
+	*p &= ~mask;
+	_atomic_spin_unlock_irqrestore(p, flags);
+}
+
+/**
+ * change_bit - Toggle a bit in memory
+ * @nr: Bit to change
+ * @addr: Address to start counting from
+ *
+ * change_bit() is atomic and may not be reordered. It may be
+ * reordered on other architectures than x86.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static inline void change_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+	unsigned long flags;
+
+	_atomic_spin_lock_irqsave(p, flags);
+	*p ^= mask;
+	_atomic_spin_unlock_irqrestore(p, flags);
+}
+
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.
+ * It may be reordered on other architectures than x86.
+ * It also implies a memory barrier.
+ */
+static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+	unsigned long old;
+	unsigned long flags;
+
+	_atomic_spin_lock_irqsave(p, flags);
+	old = *p;
+	*p = old | mask;
+	_atomic_spin_unlock_irqrestore(p, flags);
+
+	return (old & mask) != 0;
+}
+
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.
+ * It can be reorderdered on other architectures other than x86.
+ * It also implies a memory barrier.
+ */
+static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+	unsigned long old;
+	unsigned long flags;
+
+	_atomic_spin_lock_irqsave(p, flags);
+	old = *p;
+	*p = old & ~mask;
+	_atomic_spin_unlock_irqrestore(p, flags);
+
+	return (old & mask) != 0;
+}
+
+/**
+ * test_and_change_bit - Change a bit and return its old value
+ * @nr: Bit to change
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.
+ * It also implies a memory barrier.
+ */
+static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+	unsigned long old;
+	unsigned long flags;
+
+	_atomic_spin_lock_irqsave(p, flags);
+	old = *p;
+	*p = old ^ mask;
+	_atomic_spin_unlock_irqrestore(p, flags);
+
+	return (old & mask) != 0;
+}
+
+#endif /* _ASM_GENERIC_BITOPS_ATOMIC_H */
diff --git a/include/asm-generic/bitops/ext2-atomic.h b/include/asm-generic/bitops/ext2-atomic.h
new file mode 100644
index 0000000..ab1c875
--- /dev/null
+++ b/include/asm-generic/bitops/ext2-atomic.h
@@ -0,0 +1,22 @@
+#ifndef _ASM_GENERIC_BITOPS_EXT2_ATOMIC_H_
+#define _ASM_GENERIC_BITOPS_EXT2_ATOMIC_H_
+
+#define ext2_set_bit_atomic(lock, nr, addr)		\
+	({						\
+		int ret;				\
+		spin_lock(lock);			\
+		ret = ext2_set_bit((nr), (unsigned long *)(addr)); \
+		spin_unlock(lock);			\
+		ret;					\
+	})
+
+#define ext2_clear_bit_atomic(lock, nr, addr)		\
+	({						\
+		int ret;				\
+		spin_lock(lock);			\
+		ret = ext2_clear_bit((nr), (unsigned long *)(addr)); \
+		spin_unlock(lock);			\
+		ret;					\
+	})
+
+#endif /* _ASM_GENERIC_BITOPS_EXT2_ATOMIC_H_ */
diff --git a/include/asm-generic/bitops/ext2-non-atomic.h b/include/asm-generic/bitops/ext2-non-atomic.h
new file mode 100644
index 0000000..1697404
--- /dev/null
+++ b/include/asm-generic/bitops/ext2-non-atomic.h
@@ -0,0 +1,18 @@
+#ifndef _ASM_GENERIC_BITOPS_EXT2_NON_ATOMIC_H_
+#define _ASM_GENERIC_BITOPS_EXT2_NON_ATOMIC_H_
+
+#include <asm-generic/bitops/le.h>
+
+#define ext2_set_bit(nr,addr)	\
+	generic___test_and_set_le_bit((nr),(unsigned long *)(addr))
+#define ext2_clear_bit(nr,addr)	\
+	generic___test_and_clear_le_bit((nr),(unsigned long *)(addr))
+
+#define ext2_test_bit(nr,addr)	\
+	generic_test_le_bit((nr),(unsigned long *)(addr))
+#define ext2_find_first_zero_bit(addr, size) \
+	generic_find_first_zero_le_bit((unsigned long *)(addr), (size))
+#define ext2_find_next_zero_bit(addr, size, off) \
+	generic_find_next_zero_le_bit((unsigned long *)(addr), (size), (off))
+
+#endif /* _ASM_GENERIC_BITOPS_EXT2_NON_ATOMIC_H_ */
diff --git a/include/asm-generic/bitops/ffs.h b/include/asm-generic/bitops/ffs.h
new file mode 100644
index 0000000..fbbb43a
--- /dev/null
+++ b/include/asm-generic/bitops/ffs.h
@@ -0,0 +1,41 @@
+#ifndef _ASM_GENERIC_BITOPS_FFS_H_
+#define _ASM_GENERIC_BITOPS_FFS_H_
+
+/**
+ * ffs - find first bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+static inline int ffs(int x)
+{
+	int r = 1;
+
+	if (!x)
+		return 0;
+	if (!(x & 0xffff)) {
+		x >>= 16;
+		r += 16;
+	}
+	if (!(x & 0xff)) {
+		x >>= 8;
+		r += 8;
+	}
+	if (!(x & 0xf)) {
+		x >>= 4;
+		r += 4;
+	}
+	if (!(x & 3)) {
+		x >>= 2;
+		r += 2;
+	}
+	if (!(x & 1)) {
+		x >>= 1;
+		r += 1;
+	}
+	return r;
+}
+
+#endif /* _ASM_GENERIC_BITOPS_FFS_H_ */
diff --git a/include/asm-generic/bitops/ffz.h b/include/asm-generic/bitops/ffz.h
new file mode 100644
index 0000000..6744bd4
--- /dev/null
+++ b/include/asm-generic/bitops/ffz.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_GENERIC_BITOPS_FFZ_H_
+#define _ASM_GENERIC_BITOPS_FFZ_H_
+
+/*
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+#define ffz(x)  __ffs(~(x))
+
+#endif /* _ASM_GENERIC_BITOPS_FFZ_H_ */
diff --git a/include/asm-generic/bitops/find.h b/include/asm-generic/bitops/find.h
new file mode 100644
index 0000000..72a51e5
--- /dev/null
+++ b/include/asm-generic/bitops/find.h
@@ -0,0 +1,13 @@
+#ifndef _ASM_GENERIC_BITOPS_FIND_H_
+#define _ASM_GENERIC_BITOPS_FIND_H_
+
+extern unsigned long find_next_bit(const unsigned long *addr, unsigned long
+		size, unsigned long offset);
+
+extern unsigned long find_next_zero_bit(const unsigned long *addr, unsigned
+		long size, unsigned long offset);
+
+#define find_first_bit(addr, size) find_next_bit((addr), (size), 0)
+#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
+
+#endif /*_ASM_GENERIC_BITOPS_FIND_H_ */
diff --git a/include/asm-generic/bitops/fls.h b/include/asm-generic/bitops/fls.h
new file mode 100644
index 0000000..850859b
--- /dev/null
+++ b/include/asm-generic/bitops/fls.h
@@ -0,0 +1,41 @@
+#ifndef _ASM_GENERIC_BITOPS_FLS_H_
+#define _ASM_GENERIC_BITOPS_FLS_H_
+
+/**
+ * fls - find last (most-significant) bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as ffs.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+
+static inline int fls(int x)
+{
+	int r = 32;
+
+	if (!x)
+		return 0;
+	if (!(x & 0xffff0000u)) {
+		x <<= 16;
+		r -= 16;
+	}
+	if (!(x & 0xff000000u)) {
+		x <<= 8;
+		r -= 8;
+	}
+	if (!(x & 0xf0000000u)) {
+		x <<= 4;
+		r -= 4;
+	}
+	if (!(x & 0xc0000000u)) {
+		x <<= 2;
+		r -= 2;
+	}
+	if (!(x & 0x80000000u)) {
+		x <<= 1;
+		r -= 1;
+	}
+	return r;
+}
+
+#endif /* _ASM_GENERIC_BITOPS_FLS_H_ */
diff --git a/include/asm-generic/bitops/fls64.h b/include/asm-generic/bitops/fls64.h
new file mode 100644
index 0000000..1b6b17c
--- /dev/null
+++ b/include/asm-generic/bitops/fls64.h
@@ -0,0 +1,14 @@
+#ifndef _ASM_GENERIC_BITOPS_FLS64_H_
+#define _ASM_GENERIC_BITOPS_FLS64_H_
+
+#include <asm/types.h>
+
+static inline int fls64(__u64 x)
+{
+	__u32 h = x >> 32;
+	if (h)
+		return fls(h) + 32;
+	return fls(x);
+}
+
+#endif /* _ASM_GENERIC_BITOPS_FLS64_H_ */
diff --git a/include/asm-generic/bitops/hweight.h b/include/asm-generic/bitops/hweight.h
new file mode 100644
index 0000000..fbbc383
--- /dev/null
+++ b/include/asm-generic/bitops/hweight.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_
+#define _ASM_GENERIC_BITOPS_HWEIGHT_H_
+
+#include <asm/types.h>
+
+extern unsigned int hweight32(unsigned int w);
+extern unsigned int hweight16(unsigned int w);
+extern unsigned int hweight8(unsigned int w);
+extern unsigned long hweight64(__u64 w);
+
+#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
diff --git a/include/asm-generic/bitops/le.h b/include/asm-generic/bitops/le.h
new file mode 100644
index 0000000..b9c7e5d
--- /dev/null
+++ b/include/asm-generic/bitops/le.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_GENERIC_BITOPS_LE_H_
+#define _ASM_GENERIC_BITOPS_LE_H_
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+#define BITOP_WORD(nr)		((nr) / BITS_PER_LONG)
+#define BITOP_LE_SWIZZLE	((BITS_PER_LONG-1) & ~0x7)
+
+#if defined(__LITTLE_ENDIAN)
+
+#define generic_test_le_bit(nr, addr) test_bit(nr, addr)
+#define generic___set_le_bit(nr, addr) __set_bit(nr, addr)
+#define generic___clear_le_bit(nr, addr) __clear_bit(nr, addr)
+
+#define generic_test_and_set_le_bit(nr, addr) test_and_set_bit(nr, addr)
+#define generic_test_and_clear_le_bit(nr, addr) test_and_clear_bit(nr, addr)
+
+#define generic___test_and_set_le_bit(nr, addr) __test_and_set_bit(nr, addr)
+#define generic___test_and_clear_le_bit(nr, addr) __test_and_clear_bit(nr, addr)
+
+#define generic_find_next_zero_le_bit(addr, size, offset) find_next_zero_bit(addr, size, offset)
+
+#elif defined(__BIG_ENDIAN)
+
+#define generic_test_le_bit(nr, addr) \
+	test_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
+#define generic___set_le_bit(nr, addr) \
+	__set_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
+#define generic___clear_le_bit(nr, addr) \
+	__clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
+
+#define generic_test_and_set_le_bit(nr, addr) \
+	test_and_set_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
+#define generic_test_and_clear_le_bit(nr, addr) \
+	test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
+
+#define generic___test_and_set_le_bit(nr, addr) \
+	__test_and_set_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
+#define generic___test_and_clear_le_bit(nr, addr) \
+	__test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
+
+extern unsigned long generic_find_next_zero_le_bit(const unsigned long *addr,
+		unsigned long size, unsigned long offset);
+
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+#define generic_find_first_zero_le_bit(addr, size) \
+        generic_find_next_zero_le_bit((addr), (size), 0)
+
+#endif /* _ASM_GENERIC_BITOPS_LE_H_ */
diff --git a/include/asm-generic/bitops/minix-le.h b/include/asm-generic/bitops/minix-le.h
new file mode 100644
index 0000000..4a981c1
--- /dev/null
+++ b/include/asm-generic/bitops/minix-le.h
@@ -0,0 +1,17 @@
+#ifndef _ASM_GENERIC_BITOPS_MINIX_LE_H_
+#define _ASM_GENERIC_BITOPS_MINIX_LE_H_
+
+#include <asm-generic/bitops/le.h>
+
+#define minix_test_and_set_bit(nr,addr)	\
+	generic___test_and_set_le_bit((nr),(unsigned long *)(addr))
+#define minix_set_bit(nr,addr)		\
+	generic___set_le_bit((nr),(unsigned long *)(addr))
+#define minix_test_and_clear_bit(nr,addr) \
+	generic___test_and_clear_le_bit((nr),(unsigned long *)(addr))
+#define minix_test_bit(nr,addr)		\
+	generic_test_le_bit((nr),(unsigned long *)(addr))
+#define minix_find_first_zero_bit(addr,size) \
+	generic_find_first_zero_le_bit((unsigned long *)(addr),(size))
+
+#endif /* _ASM_GENERIC_BITOPS_MINIX_LE_H_ */
diff --git a/include/asm-generic/bitops/minix.h b/include/asm-generic/bitops/minix.h
new file mode 100644
index 0000000..91f42e8
--- /dev/null
+++ b/include/asm-generic/bitops/minix.h
@@ -0,0 +1,15 @@
+#ifndef _ASM_GENERIC_BITOPS_MINIX_H_
+#define _ASM_GENERIC_BITOPS_MINIX_H_
+
+#define minix_test_and_set_bit(nr,addr)	\
+	__test_and_set_bit((nr),(unsigned long *)(addr))
+#define minix_set_bit(nr,addr)		\
+	__set_bit((nr),(unsigned long *)(addr))
+#define minix_test_and_clear_bit(nr,addr) \
+	__test_and_clear_bit((nr),(unsigned long *)(addr))
+#define minix_test_bit(nr,addr)		\
+	test_bit((nr),(unsigned long *)(addr))
+#define minix_find_first_zero_bit(addr,size) \
+	find_first_zero_bit((unsigned long *)(addr),(size))
+
+#endif /* _ASM_GENERIC_BITOPS_MINIX_H_ */
diff --git a/include/asm-generic/bitops/non-atomic.h b/include/asm-generic/bitops/non-atomic.h
new file mode 100644
index 0000000..46a825c
--- /dev/null
+++ b/include/asm-generic/bitops/non-atomic.h
@@ -0,0 +1,111 @@
+#ifndef _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
+#define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
+
+#include <asm/types.h>
+
+#define BITOP_MASK(nr)		(1UL << ((nr) % BITS_PER_LONG))
+#define BITOP_WORD(nr)		((nr) / BITS_PER_LONG)
+
+/**
+ * __set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike set_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static inline void __set_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+
+	*p  |= mask;
+}
+
+static inline void __clear_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+
+	*p &= ~mask;
+}
+
+/**
+ * __change_bit - Toggle a bit in memory
+ * @nr: the bit to change
+ * @addr: the address to start counting from
+ *
+ * Unlike change_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static inline void __change_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+
+	*p ^= mask;
+}
+
+/**
+ * __test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+	unsigned long old = *p;
+
+	*p = old | mask;
+	return (old & mask) != 0;
+}
+
+/**
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+	unsigned long old = *p;
+
+	*p = old & ~mask;
+	return (old & mask) != 0;
+}
+
+/* WARNING: non atomic and it can be reordered! */
+static inline int __test_and_change_bit(int nr,
+					    volatile unsigned long *addr)
+{
+	unsigned long mask = BITOP_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
+	unsigned long old = *p;
+
+	*p = old ^ mask;
+	return (old & mask) != 0;
+}
+
+/**
+ * test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
+static inline int test_bit(int nr, const volatile unsigned long *addr)
+{
+	return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
+}
+
+#endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */
diff --git a/include/asm-generic/bitops/sched.h b/include/asm-generic/bitops/sched.h
new file mode 100644
index 0000000..5ef93a4
--- /dev/null
+++ b/include/asm-generic/bitops/sched.h
@@ -0,0 +1,36 @@
+#ifndef _ASM_GENERIC_BITOPS_SCHED_H_
+#define _ASM_GENERIC_BITOPS_SCHED_H_
+
+#include <linux/compiler.h>	/* unlikely() */
+#include <asm/types.h>
+
+/*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 140-bit bitmap where the first 100 bits are
+ * unlikely to be set. It's guaranteed that at least one of the 140
+ * bits is cleared.
+ */
+static inline int sched_find_first_bit(const unsigned long *b)
+{
+#if BITS_PER_LONG == 64
+	if (unlikely(b[0]))
+		return __ffs(b[0]);
+	if (unlikely(b[1]))
+		return __ffs(b[1]) + 64;
+	return __ffs(b[2]) + 128;
+#elif BITS_PER_LONG == 32
+	if (unlikely(b[0]))
+		return __ffs(b[0]);
+	if (unlikely(b[1]))
+		return __ffs(b[1]) + 32;
+	if (unlikely(b[2]))
+		return __ffs(b[2]) + 64;
+	if (b[3])
+		return __ffs(b[3]) + 96;
+	return __ffs(b[4]) + 128;
+#else
+#error BITS_PER_LONG not defined
+#endif
+}
+
+#endif /* _ASM_GENERIC_BITOPS_SCHED_H_ */
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
index 3ae2c73..df893c1 100644
--- a/include/asm-generic/futex.h
+++ b/include/asm-generic/futex.h
@@ -49,5 +49,11 @@
 	return ret;
 }
 
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+	return -ENOSYS;
+}
+
 #endif
 #endif
diff --git a/include/asm-generic/local.h b/include/asm-generic/local.h
index 16fc003..9291c24 100644
--- a/include/asm-generic/local.h
+++ b/include/asm-generic/local.h
@@ -4,28 +4,35 @@
 #include <linux/config.h>
 #include <linux/percpu.h>
 #include <linux/hardirq.h>
+#include <asm/atomic.h>
 #include <asm/types.h>
 
-/* An unsigned long type for operations which are atomic for a single
- * CPU.  Usually used in combination with per-cpu variables. */
+/*
+ * A signed long type for operations which are atomic for a single CPU.
+ * Usually used in combination with per-cpu variables.
+ *
+ * This is the default implementation, which uses atomic_long_t.  Which is
+ * rather pointless.  The whole point behind local_t is that some processors
+ * can perform atomic adds and subtracts in a manner which is atomic wrt IRQs
+ * running on this CPU.  local_t allows exploitation of such capabilities.
+ */
 
-#if BITS_PER_LONG == 32
 /* Implement in terms of atomics. */
 
 /* Don't use typedef: don't want them to be mixed with atomic_t's. */
 typedef struct
 {
-	atomic_t a;
+	atomic_long_t a;
 } local_t;
 
-#define LOCAL_INIT(i)	{ ATOMIC_INIT(i) }
+#define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
 
-#define local_read(l)	((unsigned long)atomic_read(&(l)->a))
-#define local_set(l,i)	atomic_set((&(l)->a),(i))
-#define local_inc(l)	atomic_inc(&(l)->a)
-#define local_dec(l)	atomic_dec(&(l)->a)
-#define local_add(i,l)	atomic_add((i),(&(l)->a))
-#define local_sub(i,l)	atomic_sub((i),(&(l)->a))
+#define local_read(l)	atomic_long_read(&(l)->a)
+#define local_set(l,i)	atomic_long_set((&(l)->a),(i))
+#define local_inc(l)	atomic_long_inc(&(l)->a)
+#define local_dec(l)	atomic_long_dec(&(l)->a)
+#define local_add(i,l)	atomic_long_add((i),(&(l)->a))
+#define local_sub(i,l)	atomic_long_sub((i),(&(l)->a))
 
 /* Non-atomic variants, ie. preemption disabled and won't be touched
  * in interrupt, etc.  Some archs can optimize this case well. */
@@ -34,68 +41,6 @@
 #define __local_add(i,l)	local_set((l), local_read(l) + (i))
 #define __local_sub(i,l)	local_set((l), local_read(l) - (i))
 
-#else /* ... can't use atomics. */
-/* Implement in terms of three variables.
-   Another option would be to use local_irq_save/restore. */
-
-typedef struct
-{
-	/* 0 = in hardirq, 1 = in softirq, 2 = usermode. */
-	unsigned long v[3];
-} local_t;
-
-#define _LOCAL_VAR(l)	((l)->v[!in_interrupt() + !in_irq()])
-
-#define LOCAL_INIT(i)	{ { (i), 0, 0 } }
-
-static inline unsigned long local_read(local_t *l)
-{
-	return l->v[0] + l->v[1] + l->v[2];
-}
-
-static inline void local_set(local_t *l, unsigned long v)
-{
-	l->v[0] = v;
-	l->v[1] = l->v[2] = 0;
-}
-
-static inline void local_inc(local_t *l)
-{
-	preempt_disable();
-	_LOCAL_VAR(l)++;
-	preempt_enable();
-}
-
-static inline void local_dec(local_t *l)
-{
-	preempt_disable();
-	_LOCAL_VAR(l)--;
-	preempt_enable();
-}
-
-static inline void local_add(unsigned long v, local_t *l)
-{
-	preempt_disable();
-	_LOCAL_VAR(l) += v;
-	preempt_enable();
-}
-
-static inline void local_sub(unsigned long v, local_t *l)
-{
-	preempt_disable();
-	_LOCAL_VAR(l) -= v;
-	preempt_enable();
-}
-
-/* Non-atomic variants, ie. preemption disabled and won't be touched
- * in interrupt, etc.  Some archs can optimize this case well. */
-#define __local_inc(l)		((l)->v[0]++)
-#define __local_dec(l)		((l)->v[0]--)
-#define __local_add(i,l)	((l)->v[0] += (i))
-#define __local_sub(i,l)	((l)->v[0] -= (i))
-
-#endif /* Non-atomic implementation */
-
 /* Use these for per-cpu local_t variables: on some archs they are
  * much more efficient than these naive implementations.  Note they take
  * a variable (eg. mystruct.foo), not an address.
diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h
new file mode 100644
index 0000000..0cfb086
--- /dev/null
+++ b/include/asm-generic/memory_model.h
@@ -0,0 +1,77 @@
+#ifndef __ASM_MEMORY_MODEL_H
+#define __ASM_MEMORY_MODEL_H
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#if defined(CONFIG_FLATMEM)
+
+#ifndef ARCH_PFN_OFFSET
+#define ARCH_PFN_OFFSET		(0UL)
+#endif
+
+#elif defined(CONFIG_DISCONTIGMEM)
+
+#ifndef arch_pfn_to_nid
+#define arch_pfn_to_nid(pfn)	pfn_to_nid(pfn)
+#endif
+
+#ifndef arch_local_page_offset
+#define arch_local_page_offset(pfn, nid)	\
+	((pfn) - NODE_DATA(nid)->node_start_pfn)
+#endif
+
+#endif /* CONFIG_DISCONTIGMEM */
+
+#ifdef CONFIG_OUT_OF_LINE_PFN_TO_PAGE
+struct page;
+/* this is useful when inlined pfn_to_page is too big */
+extern struct page *pfn_to_page(unsigned long pfn);
+extern unsigned long page_to_pfn(struct page *page);
+#else
+/*
+ * supports 3 memory models.
+ */
+#if defined(CONFIG_FLATMEM)
+
+#define pfn_to_page(pfn)	(mem_map + ((pfn) - ARCH_PFN_OFFSET))
+#define page_to_pfn(page)	((unsigned long)((page) - mem_map) + \
+				 ARCH_PFN_OFFSET)
+#elif defined(CONFIG_DISCONTIGMEM)
+
+#define pfn_to_page(pfn)			\
+({	unsigned long __pfn = (pfn);		\
+	unsigned long __nid = arch_pfn_to_nid(pfn);  \
+	NODE_DATA(__nid)->node_mem_map + arch_local_page_offset(__pfn, __nid);\
+})
+
+#define page_to_pfn(pg)							\
+({	struct page *__pg = (pg);					\
+	struct pglist_data *__pgdat = NODE_DATA(page_to_nid(__pg));	\
+	(unsigned long)(__pg - __pgdat->node_mem_map) +			\
+	 __pgdat->node_start_pfn;					\
+})
+
+#elif defined(CONFIG_SPARSEMEM)
+/*
+ * Note: section's mem_map is encorded to reflect its start_pfn.
+ * section[i].section_mem_map == mem_map's address - start_pfn;
+ */
+#define page_to_pfn(pg)					\
+({	struct page *__pg = (pg);				\
+	int __sec = page_to_section(__pg);			\
+	__pg - __section_mem_map_addr(__nr_to_section(__sec));	\
+})
+
+#define pfn_to_page(pfn)				\
+({	unsigned long __pfn = (pfn);			\
+	struct mem_section *__sec = __pfn_to_section(__pfn);	\
+	__section_mem_map_addr(__sec) + __pfn;		\
+})
+#endif /* CONFIG_FLATMEM/DISCONTIGMEM/SPARSEMEM */
+#endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */
+
+#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/include/asm-generic/mutex-dec.h b/include/asm-generic/mutex-dec.h
index 40c6d1f..29c6ac3 100644
--- a/include/asm-generic/mutex-dec.h
+++ b/include/asm-generic/mutex-dec.h
@@ -17,13 +17,14 @@
  * it wasn't 1 originally. This function MUST leave the value lower than
  * 1 even when the "1" assertion wasn't true.
  */
-#define __mutex_fastpath_lock(count, fail_fn)				\
-do {									\
-	if (unlikely(atomic_dec_return(count) < 0))			\
-		fail_fn(count);						\
-	else								\
-		smp_mb();						\
-} while (0)
+static inline void
+__mutex_fastpath_lock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
+{
+	if (unlikely(atomic_dec_return(count) < 0))
+		fail_fn(count);
+	else
+		smp_mb();
+}
 
 /**
  *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
@@ -36,7 +37,7 @@
  * or anything the slow path function returns.
  */
 static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count, fastcall int (*fail_fn)(atomic_t *))
 {
 	if (unlikely(atomic_dec_return(count) < 0))
 		return fail_fn(count);
@@ -59,12 +60,13 @@
  * __mutex_slowpath_needs_to_unlock() macro needs to return 1, it needs
  * to return 0 otherwise.
  */
-#define __mutex_fastpath_unlock(count, fail_fn)				\
-do {									\
-	smp_mb();							\
-	if (unlikely(atomic_inc_return(count) <= 0))			\
-		fail_fn(count);						\
-} while (0)
+static inline void
+__mutex_fastpath_unlock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
+{
+	smp_mb();
+	if (unlikely(atomic_inc_return(count) <= 0))
+		fail_fn(count);
+}
 
 #define __mutex_slowpath_needs_to_unlock()		1
 
diff --git a/include/asm-generic/mutex-xchg.h b/include/asm-generic/mutex-xchg.h
index 1d24f47..32a2100 100644
--- a/include/asm-generic/mutex-xchg.h
+++ b/include/asm-generic/mutex-xchg.h
@@ -3,7 +3,7 @@
  *
  * Generic implementation of the mutex fastpath, based on xchg().
  *
- * NOTE: An xchg based implementation is less optimal than an atomic
+ * NOTE: An xchg based implementation might be less optimal than an atomic
  *       decrement/increment based implementation. If your architecture
  *       has a reasonable atomic dec/inc then you should probably use
  *	 asm-generic/mutex-dec.h instead, or you could open-code an
@@ -22,14 +22,14 @@
  * wasn't 1 originally. This function MUST leave the value lower than 1
  * even when the "1" assertion wasn't true.
  */
-#define __mutex_fastpath_lock(count, fail_fn)				\
-do {									\
-	if (unlikely(atomic_xchg(count, 0) != 1))			\
-		fail_fn(count);						\
-	else								\
-		smp_mb();						\
-} while (0)
-
+static inline void
+__mutex_fastpath_lock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
+{
+	if (unlikely(atomic_xchg(count, 0) != 1))
+		fail_fn(count);
+	else
+		smp_mb();
+}
 
 /**
  *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
@@ -42,7 +42,7 @@
  * or anything the slow path function returns
  */
 static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count, fastcall int (*fail_fn)(atomic_t *))
 {
 	if (unlikely(atomic_xchg(count, 0) != 1))
 		return fail_fn(count);
@@ -64,12 +64,13 @@
  * __mutex_slowpath_needs_to_unlock() macro needs to return 1, it needs
  * to return 0 otherwise.
  */
-#define __mutex_fastpath_unlock(count, fail_fn)				\
-do {									\
-	smp_mb();							\
-	if (unlikely(atomic_xchg(count, 1) != 0))			\
-		fail_fn(count);						\
-} while (0)
+static inline void
+__mutex_fastpath_unlock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
+{
+	smp_mb();
+	if (unlikely(atomic_xchg(count, 1) != 0))
+		fail_fn(count);
+}
 
 #define __mutex_slowpath_needs_to_unlock()		0
 
diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h
index 78cf455..c0caf43 100644
--- a/include/asm-generic/percpu.h
+++ b/include/asm-generic/percpu.h
@@ -19,7 +19,7 @@
 #define percpu_modcopy(pcpudst, src, size)			\
 do {								\
 	unsigned int __i;					\
-	for_each_cpu(__i)					\
+	for_each_possible_cpu(__i)				\
 		memcpy((pcpudst)+__per_cpu_offset[__i],		\
 		       (src), (size));				\
 } while (0)
diff --git a/include/asm-h8300/bitops.h b/include/asm-h8300/bitops.h
index ff7c2b7..574f57b6 100644
--- a/include/asm-h8300/bitops.h
+++ b/include/asm-h8300/bitops.h
@@ -8,7 +8,6 @@
 
 #include <linux/config.h>
 #include <linux/compiler.h>
-#include <asm/byteorder.h>	/* swab32 */
 #include <asm/system.h>
 
 #ifdef __KERNEL__
@@ -177,10 +176,7 @@
 #undef H8300_GEN_TEST_BITOP_CONST_INT
 #undef H8300_GEN_TEST_BITOP
 
-#define find_first_zero_bit(addr, size) \
-	find_next_zero_bit((addr), (size), 0)
-
-#define ffs(x) generic_ffs(x)
+#include <asm-generic/bitops/ffs.h>
 
 static __inline__ unsigned long __ffs(unsigned long word)
 {
@@ -196,216 +192,16 @@
 	return result;
 }
 
-static __inline__ int find_next_zero_bit (const unsigned long * addr, int size, int offset)
-{
-	unsigned long *p = (unsigned long *)(((unsigned long)addr + (offset >> 3)) & ~3);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (32-offset);
-		if (size < 32)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size & ~31UL) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp |= ~0UL << size;
-found_middle:
-	return result + ffz(tmp);
-}
-
-static __inline__ unsigned long find_next_bit(const unsigned long *addr,
-	unsigned long size, unsigned long offset)
-{
-	unsigned long *p = (unsigned long *)(((unsigned long)addr + (offset >> 3)) & ~3);
-	unsigned int result = offset & ~31UL;
-	unsigned int tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp &= ~0UL << offset;
-		if (size < 32)
-			goto found_first;
-		if (tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size >= 32) {
-		if ((tmp = *p++) != 0)
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp &= ~0UL >> (32 - size);
-	if (tmp == 0UL)
-		return result + size;
-found_middle:
-	return result + __ffs(tmp);
-}
-
-#define find_first_bit(addr, size) find_next_bit(addr, size, 0)
-
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-static inline int sched_find_first_bit(unsigned long *b)
-{
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-}
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
-
-static __inline__ int ext2_set_bit(int nr, volatile void * addr)
-{
-	int		mask, retval;
-	unsigned long	flags;
-	volatile unsigned char	*ADDR = (unsigned char *) addr;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	local_irq_save(flags);
-	retval = (mask & *ADDR) != 0;
-	*ADDR |= mask;
-	local_irq_restore(flags);
-	return retval;
-}
-#define ext2_set_bit_atomic(lock, nr, addr) ext2_set_bit(nr, addr)
-
-static __inline__ int ext2_clear_bit(int nr, volatile void * addr)
-{
-	int		mask, retval;
-	unsigned long	flags;
-	volatile unsigned char	*ADDR = (unsigned char *) addr;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	local_irq_save(flags);
-	retval = (mask & *ADDR) != 0;
-	*ADDR &= ~mask;
-	local_irq_restore(flags);
-	return retval;
-}
-#define ext2_clear_bit_atomic(lock, nr, addr) ext2_set_bit(nr, addr)
-
-static __inline__ int ext2_test_bit(int nr, const volatile void * addr)
-{
-	int			mask;
-	const volatile unsigned char	*ADDR = (const unsigned char *) addr;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	return ((mask & *ADDR) != 0);
-}
-
-#define ext2_find_first_zero_bit(addr, size) \
-	ext2_find_next_zero_bit((addr), (size), 0)
-
-static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
-{
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if(offset) {
-		/* We hold the little endian value in tmp, but then the
-		 * shift is illegal. So we could keep a big endian value
-		 * in tmp, like this:
-		 *
-		 * tmp = __swab32(*(p++));
-		 * tmp |= ~0UL >> (32-offset);
-		 *
-		 * but this would decrease performance, so we change the
-		 * shift:
-		 */
-		tmp = *(p++);
-		tmp |= __swab32(~0UL >> (32-offset));
-		if(size < 32)
-			goto found_first;
-		if(~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while(size & ~31UL) {
-		if(~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if(!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	/* tmp is little endian, so we would have to swab the shift,
-	 * see above. But then we have to swab tmp below for ffz, so
-	 * we might as well do this here.
-	 */
-	return result + ffz(__swab32(tmp) | (~0UL << size));
-found_middle:
-	return result + ffz(__swab32(tmp));
-}
-
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr) test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
+#include <asm-generic/bitops/find.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/ext2-atomic.h>
+#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
-#define fls(x) generic_fls(x)
-#define fls64(x)   generic_fls64(x)
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
 
 #endif /* _H8300_BITOPS_H */
diff --git a/include/asm-h8300/page.h b/include/asm-h8300/page.h
index cd35b1c..6472c9f 100644
--- a/include/asm-h8300/page.h
+++ b/include/asm-h8300/page.h
@@ -71,8 +71,7 @@
 #define page_to_virt(page)	((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
 #define pfn_valid(page)	        (page < max_mapnr)
 
-#define pfn_to_page(pfn)	virt_to_page(pfn_to_virt(pfn))
-#define page_to_pfn(page)	virt_to_pfn(page_to_virt(page))
+#define ARCH_PFN_OFFSET		(PAGE_OFFSET >> PAGE_SHIFT)
 
 #define	virt_addr_valid(kaddr)	(((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
 				((void *)(kaddr) < (void *)memory_end))
@@ -81,6 +80,7 @@
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* _H8300_PAGE_H */
diff --git a/include/asm-h8300/types.h b/include/asm-h8300/types.h
index bf91e0d..da2402b 100644
--- a/include/asm-h8300/types.h
+++ b/include/asm-h8300/types.h
@@ -58,6 +58,9 @@
 #define HAVE_SECTOR_T
 typedef u64 sector_t;
 
+#define HAVE_BLKCNT_T
+typedef u64 blkcnt_t;
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
diff --git a/include/asm-i386/apicdef.h b/include/asm-i386/apicdef.h
index 03185ce..5e4a35a 100644
--- a/include/asm-i386/apicdef.h
+++ b/include/asm-i386/apicdef.h
@@ -37,6 +37,7 @@
 #define			APIC_SPIV_FOCUS_DISABLED	(1<<9)
 #define			APIC_SPIV_APIC_ENABLED		(1<<8)
 #define		APIC_ISR	0x100
+#define         APIC_ISR_NR     0x8     /* Number of 32 bit ISR registers. */
 #define		APIC_TMR	0x180
 #define 	APIC_IRR	0x200
 #define 	APIC_ESR	0x280
diff --git a/include/asm-i386/bitops.h b/include/asm-i386/bitops.h
index 7d20b95..08deaee 100644
--- a/include/asm-i386/bitops.h
+++ b/include/asm-i386/bitops.h
@@ -362,28 +362,9 @@
 	return word;
 }
 
-#define fls64(x)   generic_fls64(x)
-
 #ifdef __KERNEL__
 
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-static inline int sched_find_first_bit(const unsigned long *b)
-{
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-}
+#include <asm-generic/bitops/sched.h>
 
 /**
  * ffs - find first bit set
@@ -421,42 +402,22 @@
 	return r+1;
 }
 
-/**
- * hweightN - returns the hamming weight of a N-bit word
- * @x: the word to weigh
- *
- * The Hamming Weight of a number is the total number of bits set in it.
- */
-
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
+#include <asm-generic/bitops/hweight.h>
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/bitops/fls64.h>
+
 #ifdef __KERNEL__
 
-#define ext2_set_bit(nr,addr) \
-	__test_and_set_bit((nr),(unsigned long*)addr)
+#include <asm-generic/bitops/ext2-non-atomic.h>
+
 #define ext2_set_bit_atomic(lock,nr,addr) \
         test_and_set_bit((nr),(unsigned long*)addr)
-#define ext2_clear_bit(nr, addr) \
-	__test_and_clear_bit((nr),(unsigned long*)addr)
 #define ext2_clear_bit_atomic(lock,nr, addr) \
 	        test_and_clear_bit((nr),(unsigned long*)addr)
-#define ext2_test_bit(nr, addr)      test_bit((nr),(unsigned long*)addr)
-#define ext2_find_first_zero_bit(addr, size) \
-	find_first_zero_bit((unsigned long*)addr, size)
-#define ext2_find_next_zero_bit(addr, size, off) \
-	find_next_zero_bit((unsigned long*)addr, size, off)
 
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit(nr,addr) __test_and_set_bit(nr,(void*)addr)
-#define minix_set_bit(nr,addr) __set_bit(nr,(void*)addr)
-#define minix_test_and_clear_bit(nr,addr) __test_and_clear_bit(nr,(void*)addr)
-#define minix_test_bit(nr,addr) test_bit(nr,(void*)addr)
-#define minix_find_first_zero_bit(addr,size) \
-	find_first_zero_bit((void*)addr,size)
+#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-i386/floppy.h b/include/asm-i386/floppy.h
index 79727af..0340304 100644
--- a/include/asm-i386/floppy.h
+++ b/include/asm-i386/floppy.h
@@ -56,7 +56,6 @@
 	register unsigned char st;
 
 #undef TRACE_FLPY_INT
-#define NO_FLOPPY_ASSEMBLER
 
 #ifdef TRACE_FLPY_INT
 	static int calls=0;
@@ -71,38 +70,6 @@
 		bytes = virtual_dma_count;
 #endif
 
-#ifndef NO_FLOPPY_ASSEMBLER
-	__asm__ (
-       "testl %1,%1"
-	"je 3f"
-"1:	inb %w4,%b0"
-	"andb $160,%b0"
-	"cmpb $160,%b0"
-	"jne 2f"
-	"incw %w4"
-	"testl %3,%3"
-	"jne 4f"
-	"inb %w4,%b0"
-	"movb %0,(%2)"
-	"jmp 5f"
-"4:    	movb (%2),%0"
-	"outb %b0,%w4"
-"5:	decw %w4"
-	"outb %0,$0x80"
-	"decl %1"
-	"incl %2"
-	"testl %1,%1"
-	"jne 1b"
-"3:	inb %w4,%b0"
-"2:	"
-       : "=a" ((char) st), 
-       "=c" ((long) virtual_dma_count), 
-       "=S" ((long) virtual_dma_addr)
-       : "b" ((long) virtual_dma_mode),
-       "d" ((short) virtual_dma_port+4), 
-       "1" ((long) virtual_dma_count),
-       "2" ((long) virtual_dma_addr));
-#else	
 	{
 		register int lcount;
 		register char *lptr;
@@ -122,7 +89,6 @@
 		virtual_dma_addr = lptr;
 		st = inb(virtual_dma_port+4);
 	}
-#endif
 
 #ifdef TRACE_FLPY_INT
 	calls++;
diff --git a/include/asm-i386/futex.h b/include/asm-i386/futex.h
index 44b9db8..7b8ceef 100644
--- a/include/asm-i386/futex.h
+++ b/include/asm-i386/futex.h
@@ -104,5 +104,32 @@
 	return ret;
 }
 
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+		return -EFAULT;
+
+	__asm__ __volatile__(
+		"1:	" LOCK_PREFIX "cmpxchgl %3, %1		\n"
+
+		"2:	.section .fixup, \"ax\"			\n"
+		"3:	mov     %2, %0				\n"
+		"	jmp     2b				\n"
+		"	.previous				\n"
+
+		"	.section __ex_table, \"a\"		\n"
+		"	.align  8				\n"
+		"	.long   1b,3b				\n"
+		"	.previous				\n"
+
+		: "=a" (oldval), "=m" (*uaddr)
+		: "i" (-EFAULT), "r" (newval), "0" (oldval)
+		: "memory"
+	);
+
+	return oldval;
+}
+
 #endif
 #endif
diff --git a/include/asm-i386/kdebug.h b/include/asm-i386/kdebug.h
index 316138e..96d0828 100644
--- a/include/asm-i386/kdebug.h
+++ b/include/asm-i386/kdebug.h
@@ -17,11 +17,9 @@
 	int signr;
 };
 
-/* Note - you should never unregister because that can race with NMIs.
-   If you really want to do it first unregister - then synchronize_sched - then free.
-  */
-int register_die_notifier(struct notifier_block *nb);
-extern struct notifier_block *i386die_chain;
+extern int register_die_notifier(struct notifier_block *);
+extern int unregister_die_notifier(struct notifier_block *);
+extern struct atomic_notifier_head i386die_chain;
 
 
 /* Grossly misnamed. */
@@ -51,7 +49,7 @@
 		.trapnr = trap,
 		.signr = sig
 	};
-	return notifier_call_chain(&i386die_chain, val, &args);
+	return atomic_notifier_call_chain(&i386die_chain, val, &args);
 }
 
 #endif
diff --git a/include/asm-i386/kprobes.h b/include/asm-i386/kprobes.h
index a0d2d74..57d157c 100644
--- a/include/asm-i386/kprobes.h
+++ b/include/asm-i386/kprobes.h
@@ -34,6 +34,7 @@
 
 typedef u8 kprobe_opcode_t;
 #define BREAKPOINT_INSTRUCTION	0xcc
+#define RELATIVEJUMP_INSTRUCTION 0xe9
 #define MAX_INSN_SIZE 16
 #define MAX_STACK_SIZE 64
 #define MIN_STACK_SIZE(ADDR) (((MAX_STACK_SIZE) < \
@@ -51,6 +52,11 @@
 struct arch_specific_insn {
 	/* copy of the original instruction */
 	kprobe_opcode_t *insn;
+	/*
+	 * If this flag is not 0, this kprobe can be boost when its
+	 * post_handler and break_handler is not set.
+	 */
+	int boostable;
 };
 
 struct prev_kprobe {
diff --git a/include/asm-i386/local.h b/include/asm-i386/local.h
index 0177da8..e67fa08 100644
--- a/include/asm-i386/local.h
+++ b/include/asm-i386/local.h
@@ -5,7 +5,7 @@
 
 typedef struct
 {
-	volatile unsigned long counter;
+	volatile long counter;
 } local_t;
 
 #define LOCAL_INIT(i)	{ (i) }
@@ -29,7 +29,7 @@
 		:"m" (v->counter));
 }
 
-static __inline__ void local_add(unsigned long i, local_t *v)
+static __inline__ void local_add(long i, local_t *v)
 {
 	__asm__ __volatile__(
 		"addl %1,%0"
@@ -37,7 +37,7 @@
 		:"ir" (i), "m" (v->counter));
 }
 
-static __inline__ void local_sub(unsigned long i, local_t *v)
+static __inline__ void local_sub(long i, local_t *v)
 {
 	__asm__ __volatile__(
 		"subl %1,%0"
diff --git a/include/asm-i386/mach-default/mach_time.h b/include/asm-i386/mach-default/mach_time.h
index b749aa4..31eb5de 100644
--- a/include/asm-i386/mach-default/mach_time.h
+++ b/include/asm-i386/mach-default/mach_time.h
@@ -82,21 +82,8 @@
 static inline unsigned long mach_get_cmos_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
-	int i;
 
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-	/* read RTC exactly on falling edge of update flag */
-	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
-		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-			break;
-	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
-		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-			break;
-	do { /* Isn't this overkill ? UIP above should guarantee consistency */
+	do {
 		sec = CMOS_READ(RTC_SECONDS);
 		min = CMOS_READ(RTC_MINUTES);
 		hour = CMOS_READ(RTC_HOURS);
@@ -104,16 +91,18 @@
 		mon = CMOS_READ(RTC_MONTH);
 		year = CMOS_READ(RTC_YEAR);
 	} while (sec != CMOS_READ(RTC_SECONDS));
-	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-	  {
-	    BCD_TO_BIN(sec);
-	    BCD_TO_BIN(min);
-	    BCD_TO_BIN(hour);
-	    BCD_TO_BIN(day);
-	    BCD_TO_BIN(mon);
-	    BCD_TO_BIN(year);
-	  }
-	if ((year += 1900) < 1970)
+
+	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BCD_TO_BIN(sec);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(hour);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(mon);
+		BCD_TO_BIN(year);
+	}
+
+	year += 1900;
+	if (year < 1970)
 		year += 100;
 
 	return mktime(year, mon, day, hour, min, sec);
diff --git a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h
index 74f595d..e33e9f9 100644
--- a/include/asm-i386/mmzone.h
+++ b/include/asm-i386/mmzone.h
@@ -70,8 +70,6 @@
 #endif
 }
 
-#define node_localnr(pfn, nid)		((pfn) - node_data[nid]->node_start_pfn)
-
 /*
  * Following are macros that each numa implmentation must define.
  */
@@ -86,21 +84,6 @@
 /* XXX: FIXME -- wli */
 #define kern_addr_valid(kaddr)	(0)
 
-#define pfn_to_page(pfn)						\
-({									\
-	unsigned long __pfn = pfn;					\
-	int __node  = pfn_to_nid(__pfn);				\
-	&NODE_DATA(__node)->node_mem_map[node_localnr(__pfn,__node)];	\
-})
-
-#define page_to_pfn(pg)							\
-({									\
-	struct page *__page = pg;					\
-	struct zone *__zone = page_zone(__page);			\
-	(unsigned long)(__page - __zone->zone_mem_map)			\
-		+ __zone->zone_start_pfn;				\
-})
-
 #ifdef CONFIG_X86_NUMAQ            /* we have contiguous memory on NUMA-Q */
 #define pfn_valid(pfn)          ((pfn) < num_physpages)
 #else
diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h
index 997ca5d..30f52a2 100644
--- a/include/asm-i386/page.h
+++ b/include/asm-i386/page.h
@@ -126,8 +126,6 @@
 #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
 #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
 #ifdef CONFIG_FLATMEM
-#define pfn_to_page(pfn)	(mem_map + (pfn))
-#define page_to_pfn(page)	((unsigned long)((page) - mem_map))
 #define pfn_valid(pfn)		((pfn) < max_mapnr)
 #endif /* CONFIG_FLATMEM */
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
@@ -141,6 +139,7 @@
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* _I386_PAGE_H */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index feca5d9..805f0dc 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -20,6 +20,7 @@
 #include <linux/config.h>
 #include <linux/threads.h>
 #include <asm/percpu.h>
+#include <linux/cpumask.h>
 
 /* flag for disabling the tsc */
 extern int tsc_disable;
@@ -67,6 +68,9 @@
 	char	pad0;
 	int	x86_power;
 	unsigned long loops_per_jiffy;
+#ifdef CONFIG_SMP
+	cpumask_t llc_shared_map;	/* cpus sharing the last level cache */
+#endif
 	unsigned char x86_max_cores;	/* cpuid returned max cores value */
 	unsigned char booted_cores;	/* number of cores as seen by OS */
 	unsigned char apicid;
@@ -103,6 +107,7 @@
 
 extern	int phys_proc_id[NR_CPUS];
 extern	int cpu_core_id[NR_CPUS];
+extern	int cpu_llc_id[NR_CPUS];
 extern char ignore_fpu_irq;
 
 extern void identify_cpu(struct cpuinfo_x86 *);
@@ -616,8 +621,6 @@
 	unsigned int reserved[3];
 	struct extended_signature sigs[0];
 };
-/* '6' because it used to be for P6 only (but now covers Pentium 4 as well) */
-#define MICROCODE_IOCFREE	_IO('6',0)
 
 /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
 static inline void rep_nop(void)
diff --git a/include/asm-i386/setup.h b/include/asm-i386/setup.h
index 826a8ca..ee94145 100644
--- a/include/asm-i386/setup.h
+++ b/include/asm-i386/setup.h
@@ -6,9 +6,7 @@
 #ifndef _i386_SETUP_H
 #define _i386_SETUP_H
 
-#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
-#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
+#include <linux/pfn.h>
 
 /*
  * Reserved space for vmalloc and iomap - defined in asm/page.h
diff --git a/include/asm-i386/stat.h b/include/asm-i386/stat.h
index b464f80..67eae78 100644
--- a/include/asm-i386/stat.h
+++ b/include/asm-i386/stat.h
@@ -58,8 +58,7 @@
 	long long	st_size;
 	unsigned long	st_blksize;
 
-	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
-	unsigned long	__pad4;		/* future possible st_blocks high bits */
+	unsigned long long	st_blocks;	/* Number 512-byte blocks allocated. */
 
 	unsigned long	st_atime;
 	unsigned long	st_atime_nsec;
diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h
index aa958c6..b94e5ee 100644
--- a/include/asm-i386/topology.h
+++ b/include/asm-i386/topology.h
@@ -112,4 +112,6 @@
 
 #endif /* CONFIG_NUMA */
 
+extern cpumask_t cpu_coregroup_map(int cpu);
+
 #endif /* _ASM_I386_TOPOLOGY_H */
diff --git a/include/asm-i386/types.h b/include/asm-i386/types.h
index ced00fe..e50a08b 100644
--- a/include/asm-i386/types.h
+++ b/include/asm-i386/types.h
@@ -63,6 +63,11 @@
 #define HAVE_SECTOR_T
 #endif
 
+#ifdef CONFIG_LSF
+typedef u64 blkcnt_t;
+#define HAVE_BLKCNT_T
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index d8afd0e..2e7f3e2 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -316,8 +316,12 @@
 #define __NR_pselect6		308
 #define __NR_ppoll		309
 #define __NR_unshare		310
+#define __NR_set_robust_list	311
+#define __NR_get_robust_list	312
+#define __NR_sys_splice		313
+#define __NR_sys_sync_file_range 314
 
-#define NR_syscalls 311
+#define NR_syscalls 315
 
 /*
  * user-visible error numbers are in the range -1 - -128: see
diff --git a/include/asm-ia64/asmmacro.h b/include/asm-ia64/asmmacro.h
index d4cec32..edf2ceb 100644
--- a/include/asm-ia64/asmmacro.h
+++ b/include/asm-ia64/asmmacro.h
@@ -38,6 +38,10 @@
 
 /*
  * Helper macros for accessing user memory.
+ *
+ * When adding any new .section/.previous entries here, make sure to
+ * also add it to the DISCARD section in arch/ia64/kernel/gate.lds.S or
+ * unpleasant things will happen.
  */
 
 	.section "__ex_table", "a"		// declare section & section attributes
diff --git a/include/asm-ia64/bitops.h b/include/asm-ia64/bitops.h
index 36d0fb9..90921e1 100644
--- a/include/asm-ia64/bitops.h
+++ b/include/asm-ia64/bitops.h
@@ -5,8 +5,8 @@
  * Copyright (C) 1998-2003 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
- * 02/06/02 find_next_bit() and find_first_bit() added from Erich Focht's ia64 O(1)
- *	    scheduler patch
+ * 02/06/02 find_next_bit() and find_first_bit() added from Erich Focht's ia64
+ * O(1) scheduler patch
  */
 
 #include <linux/compiler.h>
@@ -25,9 +25,9 @@
  * restricted to acting on a single-word quantity.
  *
  * The address must be (at least) "long" aligned.
- * Note that there are driver (e.g., eepro100) which use these operations to operate on
- * hw-defined data-structures, so we can't easily change these operations to force a
- * bigger alignment.
+ * Note that there are driver (e.g., eepro100) which use these operations to
+ * operate on hw-defined data-structures, so we can't easily change these
+ * operations to force a bigger alignment.
  *
  * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
  */
@@ -284,8 +284,8 @@
  * ffz - find the first zero bit in a long word
  * @x: The long word to find the bit in
  *
- * Returns the bit-number (0..63) of the first (least significant) zero bit.  Undefined if
- * no zero exists, so code should check against ~0UL first...
+ * Returns the bit-number (0..63) of the first (least significant) zero bit.
+ * Undefined if no zero exists, so code should check against ~0UL first...
  */
 static inline unsigned long
 ffz (unsigned long x)
@@ -345,13 +345,14 @@
 	x |= x >> 16;
 	return ia64_popcnt(x);
 }
-#define fls64(x)   generic_fls64(x)
+
+#include <asm-generic/bitops/fls64.h>
 
 /*
- * ffs: find first bit set. This is defined the same way as the libc and compiler builtin
- * ffs routines, therefore differs in spirit from the above ffz (man ffs): it operates on
- * "int" values only and the result value is the bit number + 1.  ffs(0) is defined to
- * return zero.
+ * ffs: find first bit set. This is defined the same way as the libc and
+ * compiler builtin ffs routines, therefore differs in spirit from the above
+ * ffz (man ffs): it operates on "int" values only and the result value is the
+ * bit number + 1.  ffs(0) is defined to return zero.
  */
 #define ffs(x)	__builtin_ffs(x)
 
@@ -373,51 +374,17 @@
 
 #endif /* __KERNEL__ */
 
-extern int __find_next_zero_bit (const void *addr, unsigned long size,
-			unsigned long offset);
-extern int __find_next_bit(const void *addr, unsigned long size,
-			unsigned long offset);
-
-#define find_next_zero_bit(addr, size, offset) \
-			__find_next_zero_bit((addr), (size), (offset))
-#define find_next_bit(addr, size, offset) \
-			__find_next_bit((addr), (size), (offset))
-
-/*
- * The optimizer actually does good code for this case..
- */
-#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
-
-#define find_first_bit(addr, size) find_next_bit((addr), (size), 0)
+#include <asm-generic/bitops/find.h>
 
 #ifdef __KERNEL__
 
-#define __clear_bit(nr, addr)		clear_bit(nr, addr)
+#include <asm-generic/bitops/ext2-non-atomic.h>
 
-#define ext2_set_bit			test_and_set_bit
 #define ext2_set_bit_atomic(l,n,a)	test_and_set_bit(n,a)
-#define ext2_clear_bit			test_and_clear_bit
 #define ext2_clear_bit_atomic(l,n,a)	test_and_clear_bit(n,a)
-#define ext2_test_bit			test_bit
-#define ext2_find_first_zero_bit	find_first_zero_bit
-#define ext2_find_next_zero_bit		find_next_zero_bit
 
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit(nr,addr)		test_and_set_bit(nr,addr)
-#define minix_set_bit(nr,addr)			set_bit(nr,addr)
-#define minix_test_and_clear_bit(nr,addr)	test_and_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr)			test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size)	find_first_zero_bit(addr,size)
-
-static inline int
-sched_find_first_bit (unsigned long *b)
-{
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return 64 + __ffs(b[1]);
-	return __ffs(b[2]) + 128;
-}
+#include <asm-generic/bitops/minix.h>
+#include <asm-generic/bitops/sched.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-ia64/compat.h b/include/asm-ia64/compat.h
index c0b1910..40d01d8 100644
--- a/include/asm-ia64/compat.h
+++ b/include/asm-ia64/compat.h
@@ -189,6 +189,12 @@
 	return (void __user *) (unsigned long) uptr;
 }
 
+static inline compat_uptr_t
+ptr_to_compat(void __user *uptr)
+{
+	return (u32)(unsigned long)uptr;
+}
+
 static __inline__ void __user *
 compat_alloc_user_space (long len)
 {
diff --git a/include/asm-ia64/dmi.h b/include/asm-ia64/dmi.h
new file mode 100644
index 0000000..f3efaa2
--- /dev/null
+++ b/include/asm-ia64/dmi.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_DMI_H
+#define _ASM_DMI_H 1
+
+#include <asm/io.h>
+
+#endif
diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h
index b64fdb9..c2e3742 100644
--- a/include/asm-ia64/io.h
+++ b/include/asm-ia64/io.h
@@ -88,8 +88,8 @@
 }
 
 #define ARCH_HAS_VALID_PHYS_ADDR_RANGE
-extern int valid_phys_addr_range (unsigned long addr, size_t *count); /* efi.c */
-extern int valid_mmap_phys_addr_range (unsigned long addr, size_t *count);
+extern int valid_phys_addr_range (unsigned long addr, size_t count); /* efi.c */
+extern int valid_mmap_phys_addr_range (unsigned long addr, size_t count);
 
 /*
  * The following two macros are deprecated and scheduled for removal.
@@ -416,24 +416,18 @@
 # define outl_p		outl
 #endif
 
-/*
- * An "address" in IO memory space is not clearly either an integer or a pointer. We will
- * accept both, thus the casts.
- *
- * On ia-64, we access the physical I/O memory space through the uncached kernel region.
- */
-static inline void __iomem *
-ioremap (unsigned long offset, unsigned long size)
-{
-	return (void __iomem *) (__IA64_UNCACHED_OFFSET | (offset));
-}
+extern void __iomem * ioremap(unsigned long offset, unsigned long size);
+extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
 
 static inline void
 iounmap (volatile void __iomem *addr)
 {
 }
 
-#define ioremap_nocache(o,s)	ioremap(o,s)
+/* Use normal IO mappings for DMI */
+#define dmi_ioremap ioremap
+#define dmi_iounmap(x,l) iounmap(x)
+#define dmi_alloc(l) kmalloc(l, GFP_ATOMIC)
 
 # ifdef __KERNEL__
 
diff --git a/include/asm-ia64/kdebug.h b/include/asm-ia64/kdebug.h
index 8b01a08..218c458 100644
--- a/include/asm-ia64/kdebug.h
+++ b/include/asm-ia64/kdebug.h
@@ -40,7 +40,7 @@
 
 extern int register_die_notifier(struct notifier_block *);
 extern int unregister_die_notifier(struct notifier_block *);
-extern struct notifier_block *ia64die_chain;
+extern struct atomic_notifier_head ia64die_chain;
 
 enum die_val {
 	DIE_BREAK = 1,
@@ -81,7 +81,7 @@
 		.signr  = sig
 	};
 
-	return notifier_call_chain(&ia64die_chain, val, &args);
+	return atomic_notifier_call_chain(&ia64die_chain, val, &args);
 }
 
 #endif
diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h
index 6e9aa23..2087825 100644
--- a/include/asm-ia64/page.h
+++ b/include/asm-ia64/page.h
@@ -106,17 +106,25 @@
 # define ia64_pfn_valid(pfn) 1
 #endif
 
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+extern struct page *vmem_map;
+#ifdef CONFIG_DISCONTIGMEM
+# define page_to_pfn(page)	((unsigned long) (page - vmem_map))
+# define pfn_to_page(pfn)	(vmem_map + (pfn))
+#endif
+#endif
+
+#if defined(CONFIG_FLATMEM) || defined(CONFIG_SPARSEMEM)
+/* FLATMEM always configures mem_map (mem_map = vmem_map if necessary) */
+#include <asm-generic/memory_model.h>
+#endif
+
 #ifdef CONFIG_FLATMEM
 # define pfn_valid(pfn)		(((pfn) < max_mapnr) && ia64_pfn_valid(pfn))
-# define page_to_pfn(page)	((unsigned long) (page - mem_map))
-# define pfn_to_page(pfn)	(mem_map + (pfn))
 #elif defined(CONFIG_DISCONTIGMEM)
-extern struct page *vmem_map;
 extern unsigned long min_low_pfn;
 extern unsigned long max_low_pfn;
 # define pfn_valid(pfn)		(((pfn) >= min_low_pfn) && ((pfn) < max_low_pfn) && ia64_pfn_valid(pfn))
-# define page_to_pfn(page)	((unsigned long) (page - vmem_map))
-# define pfn_to_page(pfn)	(vmem_map + (pfn))
 #endif
 
 #define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
diff --git a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h
index 4e7e6f2..37e52a2 100644
--- a/include/asm-ia64/pal.h
+++ b/include/asm-ia64/pal.h
@@ -68,6 +68,7 @@
 #define PAL_SHUTDOWN		40	/* enter processor shutdown state */
 #define PAL_PREFETCH_VISIBILITY	41	/* Make Processor Prefetches Visible */
 #define PAL_LOGICAL_TO_PHYSICAL 42	/* returns information on logical to physical processor mapping */
+#define PAL_CACHE_SHARED_INFO	43	/* returns information on caches shared by logical processor */
 
 #define PAL_COPY_PAL		256	/* relocate PAL procedures and PAL PMI */
 #define PAL_HALT_INFO		257	/* return the low power capabilities of processor */
@@ -130,7 +131,7 @@
 #define PAL_CACHE_LINE_STATE_MODIFIED	3	/* Modified */
 
 typedef struct pal_freq_ratio {
-	u64 den : 32, num : 32;	/* numerator & denominator */
+	u32 den, num;		/* numerator & denominator */
 } itc_ratio, proc_ratio;
 
 typedef	union  pal_cache_config_info_1_s {
@@ -151,10 +152,10 @@
 
 typedef	union  pal_cache_config_info_2_s {
 	struct {
-		u64		cache_size	: 32,	/*cache size in bytes*/
+		u32		cache_size;		/*cache size in bytes*/
 
 
-				alias_boundary	: 8,	/* 39-32 aliased addr
+		u32		alias_boundary	: 8,	/* 39-32 aliased addr
 							 * separation for max
 							 * performance.
 							 */
@@ -1647,6 +1648,33 @@
 
 	return iprv.status;
 }
+
+typedef struct pal_cache_shared_info_s
+{
+	u64 num_shared;
+	pal_proc_n_log_info1_t ppli1;
+	pal_proc_n_log_info2_t ppli2;
+} pal_cache_shared_info_t;
+
+/* Get information on logical to physical processor mappings. */
+static inline s64
+ia64_pal_cache_shared_info(u64 level,
+		u64 type,
+		u64 proc_number,
+		pal_cache_shared_info_t *info)
+{
+	struct ia64_pal_retval iprv;
+
+	PAL_CALL(iprv, PAL_CACHE_SHARED_INFO, level, type, proc_number);
+
+	if (iprv.status == PAL_STATUS_SUCCESS) {
+		info->num_shared = iprv.v0;
+		info->ppli1.ppli1_data = iprv.v1;
+		info->ppli2.ppli2_data = iprv.v2;
+	}
+
+	return iprv.status;
+}
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_IA64_PAL_H */
diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h
index 244449d..bf4cc86 100644
--- a/include/asm-ia64/sn/sn_sal.h
+++ b/include/asm-ia64/sn/sn_sal.h
@@ -159,7 +159,7 @@
 static inline u32
 sn_sal_rev(void)
 {
-	struct ia64_sal_systab *systab = efi.sal_systab;
+	struct ia64_sal_systab *systab = __va(efi.sal_systab);
 
 	return (u32)(systab->sal_b_rev_major << 8 | systab->sal_b_rev_minor);
 }
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
index 019956c..36070c1 100644
--- a/include/asm-ia64/unistd.h
+++ b/include/asm-ia64/unistd.h
@@ -285,12 +285,13 @@
 #define __NR_faccessat			1293
 /* 1294, 1295 reserved for pselect/ppoll */
 #define __NR_unshare			1296
+#define __NR_splice			1297
 
 #ifdef __KERNEL__
 
 #include <linux/config.h>
 
-#define NR_syscalls			273 /* length of syscall table */
+#define NR_syscalls			274 /* length of syscall table */
 
 #define __ARCH_WANT_SYS_RT_SIGACTION
 
diff --git a/include/asm-m32r/bitops.h b/include/asm-m32r/bitops.h
index abea2fd..902a366 100644
--- a/include/asm-m32r/bitops.h
+++ b/include/asm-m32r/bitops.h
@@ -63,25 +63,6 @@
 }
 
 /**
- * __set_bit - Set a bit in memory
- * @nr: the bit to set
- * @addr: the address to start counting from
- *
- * Unlike set_bit(), this function is non-atomic and may be reordered.
- * If it's called on the same region of memory simultaneously, the effect
- * may be that only one operation succeeds.
- */
-static __inline__ void __set_bit(int nr, volatile void * addr)
-{
-	__u32 mask;
-	volatile __u32 *a = addr;
-
-	a += (nr >> 5);
-	mask = (1 << (nr & 0x1F));
-	*a |= mask;
-}
-
-/**
  * clear_bit - Clears a bit in memory
  * @nr: Bit to clear
  * @addr: Address to start counting from
@@ -118,39 +99,10 @@
 	local_irq_restore(flags);
 }
 
-static __inline__ void __clear_bit(int nr, volatile unsigned long * addr)
-{
-	unsigned long mask;
-	volatile unsigned long *a = addr;
-
-	a += (nr >> 5);
-	mask = (1 << (nr & 0x1F));
-	*a &= ~mask;
-}
-
 #define smp_mb__before_clear_bit()	barrier()
 #define smp_mb__after_clear_bit()	barrier()
 
 /**
- * __change_bit - Toggle a bit in memory
- * @nr: the bit to set
- * @addr: the address to start counting from
- *
- * Unlike change_bit(), this function is non-atomic and may be reordered.
- * If it's called on the same region of memory simultaneously, the effect
- * may be that only one operation succeeds.
- */
-static __inline__ void __change_bit(int nr, volatile void * addr)
-{
-	__u32 mask;
-	volatile __u32 *a = addr;
-
-	a += (nr >> 5);
-	mask = (1 << (nr & 0x1F));
-	*a ^= mask;
-}
-
-/**
  * change_bit - Toggle a bit in memory
  * @nr: Bit to clear
  * @addr: Address to start counting from
@@ -221,28 +173,6 @@
 }
 
 /**
- * __test_and_set_bit - Set a bit and return its old value
- * @nr: Bit to set
- * @addr: Address to count from
- *
- * This operation is non-atomic and can be reordered.
- * If two examples of this operation race, one can appear to succeed
- * but actually fail.  You must protect multiple accesses with a lock.
- */
-static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
-{
-	__u32 mask, oldbit;
-	volatile __u32 *a = addr;
-
-	a += (nr >> 5);
-	mask = (1 << (nr & 0x1F));
-	oldbit = (*a & mask);
-	*a |= mask;
-
-	return (oldbit != 0);
-}
-
-/**
  * test_and_clear_bit - Clear a bit and return its old value
  * @nr: Bit to set
  * @addr: Address to count from
@@ -280,42 +210,6 @@
 }
 
 /**
- * __test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to set
- * @addr: Address to count from
- *
- * This operation is non-atomic and can be reordered.
- * If two examples of this operation race, one can appear to succeed
- * but actually fail.  You must protect multiple accesses with a lock.
- */
-static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
-{
-	__u32 mask, oldbit;
-	volatile __u32 *a = addr;
-
-	a += (nr >> 5);
-	mask = (1 << (nr & 0x1F));
-	oldbit = (*a & mask);
-	*a &= ~mask;
-
-	return (oldbit != 0);
-}
-
-/* WARNING: non atomic and it can be reordered! */
-static __inline__ int __test_and_change_bit(int nr, volatile void * addr)
-{
-	__u32 mask, oldbit;
-	volatile __u32 *a = addr;
-
-	a += (nr >> 5);
-	mask = (1 << (nr & 0x1F));
-	oldbit = (*a & mask);
-	*a ^= mask;
-
-	return (oldbit != 0);
-}
-
-/**
  * test_and_change_bit - Change a bit and return its old value
  * @nr: Bit to set
  * @addr: Address to count from
@@ -350,353 +244,26 @@
 	return (oldbit != 0);
 }
 
-/**
- * test_bit - Determine whether a bit is set
- * @nr: bit number to test
- * @addr: Address to start counting from
- */
-static __inline__ int test_bit(int nr, const volatile void * addr)
-{
-	__u32 mask;
-	const volatile __u32 *a = addr;
-
-	a += (nr >> 5);
-	mask = (1 << (nr & 0x1F));
-
-	return ((*a & mask) != 0);
-}
-
-/**
- * ffz - find first zero in word.
- * @word: The word to search
- *
- * Undefined if no zero exists, so code should check against ~0UL first.
- */
-static __inline__ unsigned long ffz(unsigned long word)
-{
-	int k;
-
-	word = ~word;
-	k = 0;
-	if (!(word & 0x0000ffff)) { k += 16; word >>= 16; }
-	if (!(word & 0x000000ff)) { k += 8; word >>= 8; }
-	if (!(word & 0x0000000f)) { k += 4; word >>= 4; }
-	if (!(word & 0x00000003)) { k += 2; word >>= 2; }
-	if (!(word & 0x00000001)) { k += 1; }
-
-	return k;
-}
-
-/**
- * find_first_zero_bit - find the first zero bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first zero bit, not the number of the byte
- * containing a bit.
- */
-
-#define find_first_zero_bit(addr, size) \
-	find_next_zero_bit((addr), (size), 0)
-
-/**
- * find_next_zero_bit - find the first zero bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-static __inline__ int find_next_zero_bit(const unsigned long *addr,
-					 int size, int offset)
-{
-	const unsigned long *p = addr + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (32-offset);
-		if (size < 32)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size & ~31UL) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp |= ~0UL << size;
-found_middle:
-	return result + ffz(tmp);
-}
-
-/**
- * __ffs - find first bit in word.
- * @word: The word to search
- *
- * Undefined if no bit exists, so code should check against 0 first.
- */
-static __inline__ unsigned long __ffs(unsigned long word)
-{
-	int k = 0;
-
-	if (!(word & 0x0000ffff)) { k += 16; word >>= 16; }
-	if (!(word & 0x000000ff)) { k += 8; word >>= 8; }
-	if (!(word & 0x0000000f)) { k += 4; word >>= 4; }
-	if (!(word & 0x00000003)) { k += 2; word >>= 2; }
-	if (!(word & 0x00000001)) { k += 1;}
-
-	return k;
-}
-
-/*
- * fls: find last bit set.
- */
-#define fls(x) generic_fls(x)
-#define fls64(x)   generic_fls64(x)
+#include <asm-generic/bitops/non-atomic.h>
+#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
 
 #ifdef __KERNEL__
 
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-static inline int sched_find_first_bit(unsigned long *b)
-{
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-}
-
-/**
- * find_next_bit - find the first set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-static inline unsigned long find_next_bit(const unsigned long *addr,
-	unsigned long size, unsigned long offset)
-{
-	unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
-	unsigned int result = offset & ~31UL;
-	unsigned int tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *p++;
-		tmp &= ~0UL << offset;
-		if (size < 32)
-			goto found_first;
-		if (tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size >= 32) {
-		if ((tmp = *p++) != 0)
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp &= ~0UL >> (32 - size);
-	if (tmp == 0UL)        /* Are any bits set? */
-		return result + size; /* Nope. */
-found_middle:
-	return result + __ffs(tmp);
-}
-
-/**
- * find_first_bit - find the first set bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first set bit, not the number of the byte
- * containing a bit.
- */
-#define find_first_bit(addr, size) \
-	find_next_bit((addr), (size), 0)
-
-/**
- * ffs - find first bit set
- * @x: the word to search
- *
- * This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
- */
-#define ffs(x)	generic_ffs(x)
-
-/**
- * hweightN - returns the hamming weight of a N-bit word
- * @x: the word to weigh
- *
- * The Hamming Weight of a number is the total number of bits set in it.
- */
-
-#define hweight32(x)	generic_hweight32(x)
-#define hweight16(x)	generic_hweight16(x)
-#define hweight8(x)	generic_hweight8(x)
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/find.h>
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/hweight.h>
 
 #endif /* __KERNEL__ */
 
 #ifdef __KERNEL__
 
-/*
- * ext2_XXXX function
- * orig: include/asm-sh/bitops.h
- */
-
-#ifdef __LITTLE_ENDIAN__
-#define ext2_set_bit			test_and_set_bit
-#define ext2_clear_bit			__test_and_clear_bit
-#define ext2_test_bit			test_bit
-#define ext2_find_first_zero_bit	find_first_zero_bit
-#define ext2_find_next_zero_bit		find_next_zero_bit
-#else
-static inline int ext2_set_bit(int nr, volatile void * addr)
-{
-	__u8 mask, oldbit;
-	volatile __u8 *a = addr;
-
-	a += (nr >> 3);
-	mask = (1 << (nr & 0x07));
-	oldbit = (*a & mask);
-	*a |= mask;
-
-	return (oldbit != 0);
-}
-
-static inline int ext2_clear_bit(int nr, volatile void * addr)
-{
-	__u8 mask, oldbit;
-	volatile __u8 *a = addr;
-
-	a += (nr >> 3);
-	mask = (1 << (nr & 0x07));
-	oldbit = (*a & mask);
-	*a &= ~mask;
-
-	return (oldbit != 0);
-}
-
-static inline int ext2_test_bit(int nr, const volatile void * addr)
-{
-	__u32 mask;
-	const volatile __u8 *a = addr;
-
-	a += (nr >> 3);
-	mask = (1 << (nr & 0x07));
-
-	return ((mask & *a) != 0);
-}
-
-#define ext2_find_first_zero_bit(addr, size) \
-	ext2_find_next_zero_bit((addr), (size), 0)
-
-static inline unsigned long ext2_find_next_zero_bit(void *addr,
-	unsigned long size, unsigned long offset)
-{
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if(offset) {
-		/* We hold the little endian value in tmp, but then the
-		 * shift is illegal. So we could keep a big endian value
-		 * in tmp, like this:
-		 *
-		 * tmp = __swab32(*(p++));
-		 * tmp |= ~0UL >> (32-offset);
-		 *
-		 * but this would decrease preformance, so we change the
-		 * shift:
-		 */
-		tmp = *(p++);
-		tmp |= __swab32(~0UL >> (32-offset));
-		if(size < 32)
-			goto found_first;
-		if(~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while(size & ~31UL) {
-		if(~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if(!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	/* tmp is little endian, so we would have to swab the shift,
-	 * see above. But then we have to swab tmp below for ffz, so
-	 * we might as well do this here.
-	 */
-	return result + ffz(__swab32(tmp) | (~0UL << size));
-found_middle:
-	return result + ffz(__swab32(tmp));
-}
-#endif
-
-#define ext2_set_bit_atomic(lock, nr, addr)		\
-	({						\
-		int ret;				\
-		spin_lock(lock);			\
-		ret = ext2_set_bit((nr), (addr));	\
-		spin_unlock(lock);			\
-		ret;					\
-	})
-
-#define ext2_clear_bit_atomic(lock, nr, addr)		\
-	({						\
-		int ret;				\
-		spin_lock(lock);			\
-		ret = ext2_clear_bit((nr), (addr));	\
-		spin_unlock(lock);			\
-		ret;					\
-	})
-
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit(nr,addr)		__test_and_set_bit(nr,addr)
-#define minix_set_bit(nr,addr)			__set_bit(nr,addr)
-#define minix_test_and_clear_bit(nr,addr)	__test_and_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr) test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size)	find_first_zero_bit(addr,size)
+#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/ext2-atomic.h>
+#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-m32r/mmzone.h b/include/asm-m32r/mmzone.h
index adc7970..9f3b5ac 100644
--- a/include/asm-m32r/mmzone.h
+++ b/include/asm-m32r/mmzone.h
@@ -21,20 +21,6 @@
 	__pgdat->node_start_pfn + __pgdat->node_spanned_pages - 1;	\
 })
 
-#define pfn_to_page(pfn)						\
-({									\
-	unsigned long __pfn = pfn;					\
-	int __node  = pfn_to_nid(__pfn);				\
-	&NODE_DATA(__node)->node_mem_map[node_localnr(__pfn,__node)];	\
-})
-
-#define page_to_pfn(pg)							\
-({									\
-	struct page *__page = pg;					\
-	struct zone *__zone = page_zone(__page);			\
-	(unsigned long)(__page - __zone->zone_mem_map)			\
-		+ __zone->zone_start_pfn;				\
-})
 #define pmd_page(pmd)		(pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
 /*
  * pfn_valid should be made as fast as possible, and the current definition
diff --git a/include/asm-m32r/page.h b/include/asm-m32r/page.h
index 4ab5788..9ddbc08 100644
--- a/include/asm-m32r/page.h
+++ b/include/asm-m32r/page.h
@@ -76,9 +76,7 @@
 
 #ifndef CONFIG_DISCONTIGMEM
 #define PFN_BASE		(CONFIG_MEMORY_START >> PAGE_SHIFT)
-#define pfn_to_page(pfn)	(mem_map + ((pfn) - PFN_BASE))
-#define page_to_pfn(page)	\
-	((unsigned long)((page) - mem_map) + PFN_BASE)
+#define ARCH_PFN_OFFSET		PFN_BASE
 #define pfn_valid(pfn)		(((pfn) - PFN_BASE) < max_mapnr)
 #endif  /* !CONFIG_DISCONTIGMEM */
 
@@ -92,6 +90,7 @@
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* _ASM_M32R_PAGE_H */
diff --git a/include/asm-m32r/setup.h b/include/asm-m32r/setup.h
index 5f028dc..52f4fa2 100644
--- a/include/asm-m32r/setup.h
+++ b/include/asm-m32r/setup.h
@@ -24,10 +24,6 @@
 #define RAMDISK_PROMPT_FLAG		(0x8000)
 #define RAMDISK_LOAD_FLAG		(0x4000)
 
-#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
-#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
-
 extern unsigned long memory_start;
 extern unsigned long memory_end;
 
diff --git a/include/asm-m68k/bitops.h b/include/asm-m68k/bitops.h
index 13f4c00..1a61fdb 100644
--- a/include/asm-m68k/bitops.h
+++ b/include/asm-m68k/bitops.h
@@ -310,36 +310,10 @@
 
 	return 32 - cnt;
 }
-#define fls64(x)   generic_fls64(x)
 
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-static inline int sched_find_first_bit(const unsigned long *b)
-{
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-}
-
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/hweight.h>
 
 /* Bitmap functions for the minix filesystem */
 
@@ -365,9 +339,9 @@
 	return ((p - addr) << 4) + (res ^ 31);
 }
 
-#define minix_test_and_set_bit(nr, addr)	test_and_set_bit((nr) ^ 16, (unsigned long *)(addr))
-#define minix_set_bit(nr,addr)			set_bit((nr) ^ 16, (unsigned long *)(addr))
-#define minix_test_and_clear_bit(nr, addr)	test_and_clear_bit((nr) ^ 16, (unsigned long *)(addr))
+#define minix_test_and_set_bit(nr, addr)	__test_and_set_bit((nr) ^ 16, (unsigned long *)(addr))
+#define minix_set_bit(nr,addr)			__set_bit((nr) ^ 16, (unsigned long *)(addr))
+#define minix_test_and_clear_bit(nr, addr)	__test_and_clear_bit((nr) ^ 16, (unsigned long *)(addr))
 
 static inline int minix_test_bit(int nr, const void *vaddr)
 {
@@ -377,9 +351,9 @@
 
 /* Bitmap functions for the ext2 filesystem. */
 
-#define ext2_set_bit(nr, addr)			test_and_set_bit((nr) ^ 24, (unsigned long *)(addr))
+#define ext2_set_bit(nr, addr)			__test_and_set_bit((nr) ^ 24, (unsigned long *)(addr))
 #define ext2_set_bit_atomic(lock, nr, addr)	test_and_set_bit((nr) ^ 24, (unsigned long *)(addr))
-#define ext2_clear_bit(nr, addr)		test_and_clear_bit((nr) ^ 24, (unsigned long *)(addr))
+#define ext2_clear_bit(nr, addr)		__test_and_clear_bit((nr) ^ 24, (unsigned long *)(addr))
 #define ext2_clear_bit_atomic(lock, nr, addr)	test_and_clear_bit((nr) ^ 24, (unsigned long *)(addr))
 
 static inline int ext2_test_bit(int nr, const void *vaddr)
diff --git a/include/asm-m68k/stat.h b/include/asm-m68k/stat.h
index c4c402a..dd38bc2 100644
--- a/include/asm-m68k/stat.h
+++ b/include/asm-m68k/stat.h
@@ -60,8 +60,7 @@
 	long long	st_size;
 	unsigned long	st_blksize;
 
-	unsigned long	__pad4;		/* future possible st_blocks high bits */
-	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
+	unsigned long long	st_blocks;	/* Number 512-byte blocks allocated. */
 
 	unsigned long	st_atime;
 	unsigned long	st_atime_nsec;
diff --git a/include/asm-m68knommu/bitops.h b/include/asm-m68knommu/bitops.h
index 25d8a3c..0b68ccd 100644
--- a/include/asm-m68knommu/bitops.h
+++ b/include/asm-m68knommu/bitops.h
@@ -12,104 +12,10 @@
 
 #ifdef __KERNEL__
 
-/*
- *	Generic ffs().
- */
-static inline int ffs(int x)
-{
-	int r = 1;
-
-	if (!x)
-		return 0;
-	if (!(x & 0xffff)) {
-		x >>= 16;
-		r += 16;
-	}
-	if (!(x & 0xff)) {
-		x >>= 8;
-		r += 8;
-	}
-	if (!(x & 0xf)) {
-		x >>= 4;
-		r += 4;
-	}
-	if (!(x & 3)) {
-		x >>= 2;
-		r += 2;
-	}
-	if (!(x & 1)) {
-		x >>= 1;
-		r += 1;
-	}
-	return r;
-}
-
-/*
- *	Generic __ffs().
- */
-static inline int __ffs(int x)
-{
-	int r = 0;
-
-	if (!x)
-		return 0;
-	if (!(x & 0xffff)) {
-		x >>= 16;
-		r += 16;
-	}
-	if (!(x & 0xff)) {
-		x >>= 8;
-		r += 8;
-	}
-	if (!(x & 0xf)) {
-		x >>= 4;
-		r += 4;
-	}
-	if (!(x & 3)) {
-		x >>= 2;
-		r += 2;
-	}
-	if (!(x & 1)) {
-		x >>= 1;
-		r += 1;
-	}
-	return r;
-}
-
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-static inline int sched_find_first_bit(unsigned long *b)
-{
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-}
-
-/*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
- */
-static __inline__ unsigned long ffz(unsigned long word)
-{
-	unsigned long result = 0;
-
-	while(word & 1) {
-		result++;
-		word >>= 1;
-	}
-	return result;
-}
-
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/ffz.h>
 
 static __inline__ void set_bit(int nr, volatile unsigned long * addr)
 {
@@ -254,98 +160,8 @@
  __constant_test_bit((nr),(addr)) : \
  __test_bit((nr),(addr)))
 
-#define find_first_zero_bit(addr, size) \
-        find_next_zero_bit((addr), (size), 0)
-#define find_first_bit(addr, size) \
-        find_next_bit((addr), (size), 0)
-
-static __inline__ int find_next_zero_bit (const void * addr, int size, int offset)
-{
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (32-offset);
-		if (size < 32)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size & ~31UL) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp |= ~0UL << size;
-found_middle:
-	return result + ffz(tmp);
-}
-
-/*
- * Find next one bit in a bitmap reasonably efficiently.
- */
-static __inline__ unsigned long find_next_bit(const unsigned long *addr,
-	unsigned long size, unsigned long offset)
-{
-	unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
-	unsigned int result = offset & ~31UL;
-	unsigned int tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *p++;
-		tmp &= ~0UL << offset;
-		if (size < 32)
-			goto found_first;
-		if (tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size >= 32) {
-		if ((tmp = *p++) != 0)
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp &= ~0UL >> (32 - size);
-	if (tmp == 0UL)        /* Are any bits set? */
-		return result + size; /* Nope. */
-found_middle:
-	return result + __ffs(tmp);
-}
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
-
+#include <asm-generic/bitops/find.h>
+#include <asm-generic/bitops/hweight.h>
 
 static __inline__ int ext2_set_bit(int nr, volatile void * addr)
 {
@@ -475,30 +291,11 @@
 	return result + ffz(__swab32(tmp));
 }
 
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr) test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
-
-/**
- * hweightN - returns the hamming weight of a N-bit word
- * @x: the word to weigh
- *
- * The Hamming Weight of a number is the total number of bits set in it.
- */
-
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
+#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
-/*
- * fls: find last bit set.
- */
-#define fls(x) generic_fls(x)
-#define fls64(x)   generic_fls64(x)
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
 
 #endif /* _M68KNOMMU_BITOPS_H */
diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h
index 8e80205..a1728f8 100644
--- a/include/asm-mips/bitops.h
+++ b/include/asm-mips/bitops.h
@@ -105,22 +105,6 @@
 }
 
 /*
- * __set_bit - Set a bit in memory
- * @nr: the bit to set
- * @addr: the address to start counting from
- *
- * Unlike set_bit(), this function is non-atomic and may be reordered.
- * If it's called on the same region of memory simultaneously, the effect
- * may be that only one operation succeeds.
- */
-static inline void __set_bit(unsigned long nr, volatile unsigned long * addr)
-{
-	unsigned long * m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
-
-	*m |= 1UL << (nr & SZLONG_MASK);
-}
-
-/*
  * clear_bit - Clears a bit in memory
  * @nr: Bit to clear
  * @addr: Address to start counting from
@@ -169,22 +153,6 @@
 }
 
 /*
- * __clear_bit - Clears a bit in memory
- * @nr: Bit to clear
- * @addr: Address to start counting from
- *
- * Unlike clear_bit(), this function is non-atomic and may be reordered.
- * If it's called on the same region of memory simultaneously, the effect
- * may be that only one operation succeeds.
- */
-static inline void __clear_bit(unsigned long nr, volatile unsigned long * addr)
-{
-	unsigned long * m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
-
-	*m &= ~(1UL << (nr & SZLONG_MASK));
-}
-
-/*
  * change_bit - Toggle a bit in memory
  * @nr: Bit to change
  * @addr: Address to start counting from
@@ -235,22 +203,6 @@
 }
 
 /*
- * __change_bit - Toggle a bit in memory
- * @nr: the bit to change
- * @addr: the address to start counting from
- *
- * Unlike change_bit(), this function is non-atomic and may be reordered.
- * If it's called on the same region of memory simultaneously, the effect
- * may be that only one operation succeeds.
- */
-static inline void __change_bit(unsigned long nr, volatile unsigned long * addr)
-{
-	unsigned long * m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
-
-	*m ^= 1UL << (nr & SZLONG_MASK);
-}
-
-/*
  * test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
  * @addr: Address to count from
@@ -321,30 +273,6 @@
 }
 
 /*
- * __test_and_set_bit - Set a bit and return its old value
- * @nr: Bit to set
- * @addr: Address to count from
- *
- * This operation is non-atomic and can be reordered.
- * If two examples of this operation race, one can appear to succeed
- * but actually fail.  You must protect multiple accesses with a lock.
- */
-static inline int __test_and_set_bit(unsigned long nr,
-	volatile unsigned long *addr)
-{
-	volatile unsigned long *a = addr;
-	unsigned long mask;
-	int retval;
-
-	a += nr >> SZLONG_LOG;
-	mask = 1UL << (nr & SZLONG_MASK);
-	retval = (mask & *a) != 0;
-	*a |= mask;
-
-	return retval;
-}
-
-/*
  * test_and_clear_bit - Clear a bit and return its old value
  * @nr: Bit to clear
  * @addr: Address to count from
@@ -417,30 +345,6 @@
 }
 
 /*
- * __test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to clear
- * @addr: Address to count from
- *
- * This operation is non-atomic and can be reordered.
- * If two examples of this operation race, one can appear to succeed
- * but actually fail.  You must protect multiple accesses with a lock.
- */
-static inline int __test_and_clear_bit(unsigned long nr,
-	volatile unsigned long * addr)
-{
-	volatile unsigned long *a = addr;
-	unsigned long mask;
-	int retval;
-
-	a += (nr >> SZLONG_LOG);
-	mask = 1UL << (nr & SZLONG_MASK);
-	retval = ((mask & *a) != 0);
-	*a &= ~mask;
-
-	return retval;
-}
-
-/*
  * test_and_change_bit - Change a bit and return its old value
  * @nr: Bit to change
  * @addr: Address to count from
@@ -509,43 +413,11 @@
 	}
 }
 
-/*
- * __test_and_change_bit - Change a bit and return its old value
- * @nr: Bit to change
- * @addr: Address to count from
- *
- * This operation is non-atomic and can be reordered.
- * If two examples of this operation race, one can appear to succeed
- * but actually fail.  You must protect multiple accesses with a lock.
- */
-static inline int __test_and_change_bit(unsigned long nr,
-	volatile unsigned long *addr)
-{
-	volatile unsigned long *a = addr;
-	unsigned long mask;
-	int retval;
-
-	a += (nr >> SZLONG_LOG);
-	mask = 1UL << (nr & SZLONG_MASK);
-	retval = ((mask & *a) != 0);
-	*a ^= mask;
-
-	return retval;
-}
-
 #undef __bi_flags
 #undef __bi_local_irq_save
 #undef __bi_local_irq_restore
 
-/*
- * test_bit - Determine whether a bit is set
- * @nr: bit number to test
- * @addr: Address to start counting from
- */
-static inline int test_bit(unsigned long nr, const volatile unsigned long *addr)
-{
-	return 1UL & (addr[nr >> SZLONG_LOG] >> (nr & SZLONG_MASK));
-}
+#include <asm-generic/bitops/non-atomic.h>
 
 /*
  * Return the bit position (0..63) of the most significant 1 bit in a word
@@ -580,6 +452,8 @@
 	return 63 - lz;
 }
 
+#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
+
 /*
  * __ffs - find first bit in word.
  * @word: The word to search
@@ -589,31 +463,7 @@
  */
 static inline unsigned long __ffs(unsigned long word)
 {
-#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
 	return __ilog2(word & -word);
-#else
-	int b = 0, s;
-
-#ifdef CONFIG_32BIT
-	s = 16; if (word << 16 != 0) s = 0; b += s; word >>= s;
-	s =  8; if (word << 24 != 0) s = 0; b += s; word >>= s;
-	s =  4; if (word << 28 != 0) s = 0; b += s; word >>= s;
-	s =  2; if (word << 30 != 0) s = 0; b += s; word >>= s;
-	s =  1; if (word << 31 != 0) s = 0; b += s;
-
-	return b;
-#endif
-#ifdef CONFIG_64BIT
-	s = 32; if (word << 32 != 0) s = 0; b += s; word >>= s;
-	s = 16; if (word << 48 != 0) s = 0; b += s; word >>= s;
-	s =  8; if (word << 56 != 0) s = 0; b += s; word >>= s;
-	s =  4; if (word << 60 != 0) s = 0; b += s; word >>= s;
-	s =  2; if (word << 62 != 0) s = 0; b += s; word >>= s;
-	s =  1; if (word << 63 != 0) s = 0; b += s;
-
-	return b;
-#endif
-#endif
 }
 
 /*
@@ -652,321 +502,38 @@
  */
 static inline unsigned long fls(unsigned long word)
 {
-#ifdef CONFIG_32BIT
 #ifdef CONFIG_CPU_MIPS32
 	__asm__ ("clz %0, %1" : "=r" (word) : "r" (word));
 
 	return 32 - word;
-#else
-	{
-	int r = 32, s;
-
-	if (word == 0)
-		return 0;
-
-	s = 16; if ((word & 0xffff0000)) s = 0; r -= s; word <<= s;
-	s = 8;  if ((word & 0xff000000)) s = 0; r -= s; word <<= s;
-	s = 4;  if ((word & 0xf0000000)) s = 0; r -= s; word <<= s;
-	s = 2;  if ((word & 0xc0000000)) s = 0; r -= s; word <<= s;
-	s = 1;  if ((word & 0x80000000)) s = 0; r -= s;
-
-	return r;
-	}
 #endif
-#endif /* CONFIG_32BIT */
 
-#ifdef CONFIG_64BIT
 #ifdef CONFIG_CPU_MIPS64
-
 	__asm__ ("dclz %0, %1" : "=r" (word) : "r" (word));
 
 	return 64 - word;
-#else
-	{
-	int r = 64, s;
-
-	if (word == 0)
-		return 0;
-
-	s = 32; if ((word & 0xffffffff00000000UL)) s = 0; r -= s; word <<= s;
-	s = 16; if ((word & 0xffff000000000000UL)) s = 0; r -= s; word <<= s;
-	s = 8;  if ((word & 0xff00000000000000UL)) s = 0; r -= s; word <<= s;
-	s = 4;  if ((word & 0xf000000000000000UL)) s = 0; r -= s; word <<= s;
-	s = 2;  if ((word & 0xc000000000000000UL)) s = 0; r -= s; word <<= s;
-	s = 1;  if ((word & 0x8000000000000000UL)) s = 0; r -= s;
-
-	return r;
-	}
 #endif
-#endif /* CONFIG_64BIT */
 }
 
-#define fls64(x)   generic_fls64(x)
+#else
 
-/*
- * find_next_zero_bit - find the first zero bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-static inline unsigned long find_next_zero_bit(const unsigned long *addr,
-	unsigned long size, unsigned long offset)
-{
-	const unsigned long *p = addr + (offset >> SZLONG_LOG);
-	unsigned long result = offset & ~SZLONG_MASK;
-	unsigned long tmp;
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/fls.h>
 
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= SZLONG_MASK;
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (_MIPS_SZLONG-offset);
-		if (size < _MIPS_SZLONG)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= _MIPS_SZLONG;
-		result += _MIPS_SZLONG;
-	}
-	while (size & ~SZLONG_MASK) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += _MIPS_SZLONG;
-		size -= _MIPS_SZLONG;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
+#endif /*defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) */
 
-found_first:
-	tmp |= ~0UL << size;
-	if (tmp == ~0UL)		/* Are any bits zero? */
-		return result + size;	/* Nope. */
-found_middle:
-	return result + ffz(tmp);
-}
-
-#define find_first_zero_bit(addr, size) \
-	find_next_zero_bit((addr), (size), 0)
-
-/*
- * find_next_bit - find the next set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-static inline unsigned long find_next_bit(const unsigned long *addr,
-	unsigned long size, unsigned long offset)
-{
-	const unsigned long *p = addr + (offset >> SZLONG_LOG);
-	unsigned long result = offset & ~SZLONG_MASK;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= SZLONG_MASK;
-	if (offset) {
-		tmp = *(p++);
-		tmp &= ~0UL << offset;
-		if (size < _MIPS_SZLONG)
-			goto found_first;
-		if (tmp)
-			goto found_middle;
-		size -= _MIPS_SZLONG;
-		result += _MIPS_SZLONG;
-	}
-	while (size & ~SZLONG_MASK) {
-		if ((tmp = *(p++)))
-			goto found_middle;
-		result += _MIPS_SZLONG;
-		size -= _MIPS_SZLONG;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp &= ~0UL >> (_MIPS_SZLONG - size);
-	if (tmp == 0UL)			/* Are any bits set? */
-		return result + size;	/* Nope. */
-found_middle:
-	return result + __ffs(tmp);
-}
-
-/*
- * find_first_bit - find the first set bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first set bit, not the number of the byte
- * containing a bit.
- */
-#define find_first_bit(addr, size) \
-	find_next_bit((addr), (size), 0)
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/find.h>
 
 #ifdef __KERNEL__
 
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-static inline int sched_find_first_bit(const unsigned long *b)
-{
-#ifdef CONFIG_32BIT
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-#endif
-#ifdef CONFIG_64BIT
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 64;
-	return __ffs(b[2]) + 128;
-#endif
-}
-
-/*
- * hweightN - returns the hamming weight of a N-bit word
- * @x: the word to weigh
- *
- * The Hamming Weight of a number is the total number of bits set in it.
- */
-
-#define hweight64(x)	generic_hweight64(x)
-#define hweight32(x)	generic_hweight32(x)
-#define hweight16(x)	generic_hweight16(x)
-#define hweight8(x)	generic_hweight8(x)
-
-static inline int __test_and_set_le_bit(unsigned long nr, unsigned long *addr)
-{
-	unsigned char	*ADDR = (unsigned char *) addr;
-	int		mask, retval;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	retval = (mask & *ADDR) != 0;
-	*ADDR |= mask;
-
-	return retval;
-}
-
-static inline int __test_and_clear_le_bit(unsigned long nr, unsigned long *addr)
-{
-	unsigned char	*ADDR = (unsigned char *) addr;
-	int		mask, retval;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	retval = (mask & *ADDR) != 0;
-	*ADDR &= ~mask;
-
-	return retval;
-}
-
-static inline int test_le_bit(unsigned long nr, const unsigned long * addr)
-{
-	const unsigned char	*ADDR = (const unsigned char *) addr;
-	int			mask;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-
-	return ((mask & *ADDR) != 0);
-}
-
-static inline unsigned long find_next_zero_le_bit(unsigned long *addr,
-	unsigned long size, unsigned long offset)
-{
-	unsigned long *p = ((unsigned long *) addr) + (offset >> SZLONG_LOG);
-	unsigned long result = offset & ~SZLONG_MASK;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= SZLONG_MASK;
-	if (offset) {
-		tmp = cpu_to_lelongp(p++);
-		tmp |= ~0UL >> (_MIPS_SZLONG-offset); /* bug or feature ? */
-		if (size < _MIPS_SZLONG)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= _MIPS_SZLONG;
-		result += _MIPS_SZLONG;
-	}
-	while (size & ~SZLONG_MASK) {
-		if (~(tmp = cpu_to_lelongp(p++)))
-			goto found_middle;
-		result += _MIPS_SZLONG;
-		size -= _MIPS_SZLONG;
-	}
-	if (!size)
-		return result;
-	tmp = cpu_to_lelongp(p);
-
-found_first:
-	tmp |= ~0UL << size;
-	if (tmp == ~0UL)		/* Are any bits zero? */
-		return result + size;	/* Nope. */
-
-found_middle:
-	return result + ffz(tmp);
-}
-
-#define find_first_zero_le_bit(addr, size) \
-	find_next_zero_le_bit((addr), (size), 0)
-
-#define ext2_set_bit(nr,addr) \
-	__test_and_set_le_bit((nr),(unsigned long*)addr)
-#define ext2_clear_bit(nr, addr) \
-	__test_and_clear_le_bit((nr),(unsigned long*)addr)
- #define ext2_set_bit_atomic(lock, nr, addr)		\
-({							\
-	int ret;					\
-	spin_lock(lock);				\
-	ret = ext2_set_bit((nr), (addr));		\
-	spin_unlock(lock);				\
-	ret;						\
-})
-
-#define ext2_clear_bit_atomic(lock, nr, addr)		\
-({							\
-	int ret;					\
-	spin_lock(lock);				\
-	ret = ext2_clear_bit((nr), (addr));		\
-	spin_unlock(lock);				\
-	ret;						\
-})
-#define ext2_test_bit(nr, addr)	test_le_bit((nr),(unsigned long*)addr)
-#define ext2_find_first_zero_bit(addr, size) \
-	find_first_zero_le_bit((unsigned long*)addr, size)
-#define ext2_find_next_zero_bit(addr, size, off) \
-	find_next_zero_le_bit((unsigned long*)addr, size, off)
-
-/*
- * Bitmap functions for the minix filesystem.
- *
- * FIXME: These assume that Minix uses the native byte/bitorder.
- * This limits the Minix filesystem's value for data exchange very much.
- */
-#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr) test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/ext2-atomic.h>
+#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-mips/compat.h b/include/asm-mips/compat.h
index 0012bd8..986511d 100644
--- a/include/asm-mips/compat.h
+++ b/include/asm-mips/compat.h
@@ -133,6 +133,11 @@
 	return (void __user *)(long)uptr;
 }
 
+static inline compat_uptr_t ptr_to_compat(void __user *uptr)
+{
+	return (u32)(unsigned long)uptr;
+}
+
 static inline void __user *compat_alloc_user_space(long len)
 {
 	struct pt_regs *regs = (struct pt_regs *)
diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h
index 2454c44..a554089 100644
--- a/include/asm-mips/futex.h
+++ b/include/asm-mips/futex.h
@@ -99,5 +99,11 @@
 	return ret;
 }
 
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+	return -ENOSYS;
+}
+
 #endif
 #endif
diff --git a/include/asm-mips/mc146818-time.h b/include/asm-mips/mc146818-time.h
index 4721486..41ac8d3 100644
--- a/include/asm-mips/mc146818-time.h
+++ b/include/asm-mips/mc146818-time.h
@@ -86,43 +86,14 @@
 	return retval;
 }
 
-/*
- * Returns true if a clock update is in progress
- */
-static inline unsigned char rtc_is_updating(void)
-{
-	unsigned char uip;
-	unsigned long flags;
-
-	spin_lock_irqsave(&rtc_lock, flags);
-	uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
-	spin_unlock_irqrestore(&rtc_lock, flags);
-	return uip;
-}
-
 static inline unsigned long mc146818_get_cmos_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
-	int i;
 	unsigned long flags;
 
-	/*
-	 * The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-
-	/* read RTC exactly on falling edge of update flag */
-	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
-		if (rtc_is_updating())
-			break;
-	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
-		if (!rtc_is_updating())
-			break;
-
 	spin_lock_irqsave(&rtc_lock, flags);
-	do { /* Isn't this overkill ? UIP above should guarantee consistency */
+
+	do {
 		sec = CMOS_READ(RTC_SECONDS);
 		min = CMOS_READ(RTC_MINUTES);
 		hour = CMOS_READ(RTC_HOURS);
diff --git a/include/asm-mips/mmzone.h b/include/asm-mips/mmzone.h
index 011caeb..7bde443 100644
--- a/include/asm-mips/mmzone.h
+++ b/include/asm-mips/mmzone.h
@@ -22,20 +22,6 @@
 		       NODE_DATA(__n)->node_spanned_pages) : 0);\
 })
 
-#define pfn_to_page(pfn)					\
-({								\
- 	unsigned long __pfn = (pfn);				\
-	pg_data_t *__pg = NODE_DATA(pfn_to_nid(__pfn));		\
-	__pg->node_mem_map + (__pfn - __pg->node_start_pfn);	\
-})
-
-#define page_to_pfn(p)						\
-({								\
-	struct page *__p = (p);					\
-	struct zone *__z = page_zone(__p);			\
-	((__p - __z->zone_mem_map) + __z->zone_start_pfn);	\
-})
-
 /* XXX: FIXME -- wli */
 #define kern_addr_valid(addr)	(0)
 
diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h
index ee25a77..a1eab13 100644
--- a/include/asm-mips/page.h
+++ b/include/asm-mips/page.h
@@ -140,8 +140,6 @@
 #define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
 
 #ifndef CONFIG_NEED_MULTIPLE_NODES
-#define pfn_to_page(pfn)	(mem_map + (pfn))
-#define page_to_pfn(page)	((unsigned long)((page) - mem_map))
 #define pfn_valid(pfn)		((pfn) < max_mapnr)
 #endif
 
@@ -160,6 +158,7 @@
 #define WANT_PAGE_VIRTUAL
 #endif
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* _ASM_PAGE_H */
diff --git a/include/asm-mips/serial.h b/include/asm-mips/serial.h
index e796d75..7b23664 100644
--- a/include/asm-mips/serial.h
+++ b/include/asm-mips/serial.h
@@ -103,88 +103,6 @@
 #define IVR_SERIAL_PORT_DEFNS
 #endif
 
-#ifdef CONFIG_SERIAL_AU1X00
-#include <asm/mach-au1x00/au1000.h>
-#ifdef CONFIG_SOC_AU1000
-#define AU1000_SERIAL_PORT_DEFNS                       \
-    { .baud_base = 0, .port = UART0_ADDR,              \
-      .iomem_base = (unsigned char *)UART0_ADDR,       \
-      .irq = AU1000_UART0_INT, .flags = STD_COM_FLAGS, \
-      .iomem_reg_shift = 2 },                          \
-    { .baud_base = 0, .port = UART1_ADDR,              \
-      .iomem_base = (unsigned char *)UART1_ADDR,       \
-      .irq = AU1000_UART1_INT, .flags = STD_COM_FLAGS, \
-      .iomem_reg_shift = 2 },                          \
-    { .baud_base = 0, .port = UART2_ADDR,              \
-      .iomem_base = (unsigned char *)UART2_ADDR,       \
-      .irq = AU1000_UART2_INT, .flags = STD_COM_FLAGS, \
-      .iomem_reg_shift = 2 },                          \
-    { .baud_base = 0, .port = UART3_ADDR,              \
-      .iomem_base = (unsigned char *)UART3_ADDR,       \
-      .irq = AU1000_UART3_INT, .flags = STD_COM_FLAGS, \
-      .iomem_reg_shift = 2 },
-#endif
-
-#ifdef CONFIG_SOC_AU1500
-#define AU1000_SERIAL_PORT_DEFNS                       \
-    { .baud_base = 0, .port = UART0_ADDR,              \
-      .iomem_base = (unsigned char *)UART0_ADDR,       \
-      .irq = AU1500_UART0_INT, .flags = STD_COM_FLAGS, \
-      .iomem_reg_shift = 2 },                          \
-    { .baud_base = 0, .port = UART3_ADDR,              \
-      .iomem_base = (unsigned char *)UART3_ADDR,       \
-      .irq = AU1500_UART3_INT, .flags = STD_COM_FLAGS, \
-      .iomem_reg_shift = 2 },
-#endif
-
-#ifdef CONFIG_SOC_AU1100
-#define AU1000_SERIAL_PORT_DEFNS                       \
-    { .baud_base = 0, .port = UART0_ADDR,              \
-      .iomem_base = (unsigned char *)UART0_ADDR,       \
-      .irq = AU1100_UART0_INT, .flags = STD_COM_FLAGS, \
-      .iomem_reg_shift = 2 },                          \
-    { .baud_base = 0, .port = UART1_ADDR,              \
-      .iomem_base = (unsigned char *)UART1_ADDR,       \
-      .irq = AU1100_UART1_INT, .flags = STD_COM_FLAGS, \
-      .iomem_reg_shift = 2 },                          \
-    { .baud_base = 0, .port = UART3_ADDR,              \
-      .iomem_base = (unsigned char *)UART3_ADDR,       \
-      .irq = AU1100_UART3_INT, .flags = STD_COM_FLAGS, \
-      .iomem_reg_shift = 2 },
-#endif
-
-#ifdef CONFIG_SOC_AU1550
-#define AU1000_SERIAL_PORT_DEFNS                       \
-    { .baud_base = 0, .port = UART0_ADDR,              \
-      .iomem_base = (unsigned char *)UART0_ADDR,       \
-      .irq = AU1550_UART0_INT, .flags = STD_COM_FLAGS, \
-      .iomem_reg_shift = 2 },                          \
-    { .baud_base = 0, .port = UART1_ADDR,              \
-      .iomem_base = (unsigned char *)UART1_ADDR,       \
-      .irq = AU1550_UART1_INT, .flags = STD_COM_FLAGS, \
-      .iomem_reg_shift = 2 },                          \
-    { .baud_base = 0, .port = UART3_ADDR,              \
-      .iomem_base = (unsigned char *)UART3_ADDR,       \
-      .irq = AU1550_UART3_INT,  .flags = STD_COM_FLAGS,\
-      .iomem_reg_shift = 2 },
-#endif
-
-#ifdef CONFIG_SOC_AU1200
-#define AU1000_SERIAL_PORT_DEFNS                       \
-    { .baud_base = 0, .port = UART0_ADDR,              \
-      .iomem_base = (unsigned char *)UART0_ADDR,       \
-      .irq = AU1200_UART0_INT, .flags = STD_COM_FLAGS, \
-      .iomem_reg_shift = 2 },                          \
-    { .baud_base = 0, .port = UART1_ADDR,              \
-      .iomem_base = (unsigned char *)UART1_ADDR,       \
-      .irq = AU1200_UART1_INT, .flags = STD_COM_FLAGS, \
-      .iomem_reg_shift = 2 },
-#endif
-
-#else
-#define AU1000_SERIAL_PORT_DEFNS
-#endif
-
 #ifdef CONFIG_HAVE_STD_PC_SERIAL_PORT
 #define STD_SERIAL_PORT_DEFNS			\
 	/* UART CLK   PORT IRQ     FLAGS        */			\
@@ -331,7 +249,6 @@
 	MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS		\
 	MOMENCO_OCELOT_C_SERIAL_PORT_DEFNS		\
 	MOMENCO_OCELOT_SERIAL_PORT_DEFNS		\
-	MOMENCO_OCELOT_3_SERIAL_PORT_DEFNS		\
-	AU1000_SERIAL_PORT_DEFNS
+	MOMENCO_OCELOT_3_SERIAL_PORT_DEFNS
 
 #endif /* _ASM_SERIAL_H */
diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h
index 9cc3564..d897c8b 100644
--- a/include/asm-mips/time.h
+++ b/include/asm-mips/time.h
@@ -26,14 +26,14 @@
 
 /*
  * RTC ops.  By default, they point to no-RTC functions.
- *	rtc_get_time - mktime(year, mon, day, hour, min, sec) in seconds.
- *	rtc_set_time - reverse the above translation and set time to RTC.
- *	rtc_set_mmss - similar to rtc_set_time, but only min and sec need
+ *	rtc_mips_get_time - mktime(year, mon, day, hour, min, sec) in seconds.
+ *	rtc_mips_set_time - reverse the above translation and set time to RTC.
+ *	rtc_mips_set_mmss - similar to rtc_set_time, but only min and sec need
  *			to be set.  Used by RTC sync-up.
  */
-extern unsigned long (*rtc_get_time)(void);
-extern int (*rtc_set_time)(unsigned long);
-extern int (*rtc_set_mmss)(unsigned long);
+extern unsigned long (*rtc_mips_get_time)(void);
+extern int (*rtc_mips_set_time)(unsigned long);
+extern int (*rtc_mips_set_mmss)(unsigned long);
 
 /*
  * Timer interrupt functions.
diff --git a/include/asm-mips/types.h b/include/asm-mips/types.h
index 421b3ae..cd2813d 100644
--- a/include/asm-mips/types.h
+++ b/include/asm-mips/types.h
@@ -99,6 +99,11 @@
 #define HAVE_SECTOR_T
 #endif
 
+#ifdef CONFIG_LSF
+typedef u64 blkcnt_t;
+#define HAVE_BLKCNT_T
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-parisc/atomic.h b/include/asm-parisc/atomic.h
index 4dc7253..403ea97 100644
--- a/include/asm-parisc/atomic.h
+++ b/include/asm-parisc/atomic.h
@@ -210,6 +210,8 @@
 
 #define atomic_dec_and_test(v)	(atomic_dec_return(v) == 0)
 
+#define atomic_sub_and_test(i,v)	(atomic_sub_return((i),(v)) == 0)
+
 #define ATOMIC_INIT(i)	((atomic_t) { (i) })
 
 #define smp_mb__before_atomic_dec()	smp_mb()
@@ -267,6 +269,7 @@
 
 #define atomic64_inc_and_test(v) 	(atomic64_inc_return(v) == 0)
 #define atomic64_dec_and_test(v)	(atomic64_dec_return(v) == 0)
+#define atomic64_sub_and_test(i,v)	(atomic64_sub_return((i),(v)) == 0)
 
 #endif /* __LP64__ */
 
diff --git a/include/asm-parisc/bitops.h b/include/asm-parisc/bitops.h
index 15d8c2b..9005619 100644
--- a/include/asm-parisc/bitops.h
+++ b/include/asm-parisc/bitops.h
@@ -35,13 +35,6 @@
 	_atomic_spin_unlock_irqrestore(addr, flags);
 }
 
-static __inline__ void __set_bit(unsigned long nr, volatile unsigned long * addr)
-{
-	unsigned long *m = (unsigned long *) addr + (nr >> SHIFT_PER_LONG);
-
-	*m |= 1UL << CHOP_SHIFTCOUNT(nr);
-}
-
 static __inline__ void clear_bit(int nr, volatile unsigned long * addr)
 {
 	unsigned long mask = ~(1UL << CHOP_SHIFTCOUNT(nr));
@@ -53,13 +46,6 @@
 	_atomic_spin_unlock_irqrestore(addr, flags);
 }
 
-static __inline__ void __clear_bit(unsigned long nr, volatile unsigned long * addr)
-{
-	unsigned long *m = (unsigned long *) addr + (nr >> SHIFT_PER_LONG);
-
-	*m &= ~(1UL << CHOP_SHIFTCOUNT(nr));
-}
-
 static __inline__ void change_bit(int nr, volatile unsigned long * addr)
 {
 	unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
@@ -71,13 +57,6 @@
 	_atomic_spin_unlock_irqrestore(addr, flags);
 }
 
-static __inline__ void __change_bit(unsigned long nr, volatile unsigned long * addr)
-{
-	unsigned long *m = (unsigned long *) addr + (nr >> SHIFT_PER_LONG);
-
-	*m ^= 1UL << CHOP_SHIFTCOUNT(nr);
-}
-
 static __inline__ int test_and_set_bit(int nr, volatile unsigned long * addr)
 {
 	unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
@@ -93,18 +72,6 @@
 	return (oldbit & mask) ? 1 : 0;
 }
 
-static __inline__ int __test_and_set_bit(int nr, volatile unsigned long * address)
-{
-	unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
-	unsigned long oldbit;
-	unsigned long *addr = (unsigned long *)address + (nr >> SHIFT_PER_LONG);
-
-	oldbit = *addr;
-	*addr = oldbit | mask;
-
-	return (oldbit & mask) ? 1 : 0;
-}
-
 static __inline__ int test_and_clear_bit(int nr, volatile unsigned long * addr)
 {
 	unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
@@ -120,18 +87,6 @@
 	return (oldbit & mask) ? 1 : 0;
 }
 
-static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long * address)
-{
-	unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
-	unsigned long *addr = (unsigned long *)address + (nr >> SHIFT_PER_LONG);
-	unsigned long oldbit;
-
-	oldbit = *addr;
-	*addr = oldbit & ~mask;
-
-	return (oldbit & mask) ? 1 : 0;
-}
-
 static __inline__ int test_and_change_bit(int nr, volatile unsigned long * addr)
 {
 	unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
@@ -147,25 +102,7 @@
 	return (oldbit & mask) ? 1 : 0;
 }
 
-static __inline__ int __test_and_change_bit(int nr, volatile unsigned long * address)
-{
-	unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
-	unsigned long *addr = (unsigned long *)address + (nr >> SHIFT_PER_LONG);
-	unsigned long oldbit;
-
-	oldbit = *addr;
-	*addr = oldbit ^ mask;
-
-	return (oldbit & mask) ? 1 : 0;
-}
-
-static __inline__ int test_bit(int nr, const volatile unsigned long *address)
-{
-	unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
-	const unsigned long *addr = (const unsigned long *)address + (nr >> SHIFT_PER_LONG);
-	
-	return !!(*addr & mask);
-}
+#include <asm-generic/bitops/non-atomic.h>
 
 #ifdef __KERNEL__
 
@@ -219,8 +156,7 @@
 	return ret;
 }
 
-/* Undefined if no bit is zero. */
-#define ffz(x)	__ffs(~x)
+#include <asm-generic/bitops/ffz.h>
 
 /*
  * ffs: find first bit set. returns 1 to BITS_PER_LONG or 0 (if none set)
@@ -263,155 +199,22 @@
 
 	return ret;
 }
-#define fls64(x)   generic_fls64(x)
 
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-#define hweight64(x) generic_hweight64(x)
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
-
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-static inline int sched_find_first_bit(const unsigned long *b)
-{
-#ifdef __LP64__
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 64;
-	return __ffs(b[2]) + 128;
-#else
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-#endif
-}
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/sched.h>
 
 #endif /* __KERNEL__ */
 
-/*
- * This implementation of find_{first,next}_zero_bit was stolen from
- * Linus' asm-alpha/bitops.h.
- */
-#define find_first_zero_bit(addr, size) \
-	find_next_zero_bit((addr), (size), 0)
-
-static __inline__ unsigned long find_next_zero_bit(const void * addr, unsigned long size, unsigned long offset)
-{
-	const unsigned long * p = ((unsigned long *) addr) + (offset >> SHIFT_PER_LONG);
-	unsigned long result = offset & ~(BITS_PER_LONG-1);
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= (BITS_PER_LONG-1);
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (BITS_PER_LONG-offset);
-		if (size < BITS_PER_LONG)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= BITS_PER_LONG;
-		result += BITS_PER_LONG;
-	}
-	while (size & ~(BITS_PER_LONG -1)) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += BITS_PER_LONG;
-		size -= BITS_PER_LONG;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-found_first:
-	tmp |= ~0UL << size;
-found_middle:
-	return result + ffz(tmp);
-}
-
-static __inline__ unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset)
-{
-	const unsigned long *p = addr + (offset >> SHIFT_PER_LONG);
-	unsigned long result = offset & ~(BITS_PER_LONG-1);
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= (BITS_PER_LONG-1);
-	if (offset) {
-		tmp = *(p++);
-		tmp &= (~0UL << offset);
-		if (size < BITS_PER_LONG)
-			goto found_first;
-		if (tmp)
-			goto found_middle;
-		size -= BITS_PER_LONG;
-		result += BITS_PER_LONG;
-	}
-	while (size & ~(BITS_PER_LONG-1)) {
-		if ((tmp = *(p++)))
-			goto found_middle;
-		result += BITS_PER_LONG;
-		size -= BITS_PER_LONG;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp &= (~0UL >> (BITS_PER_LONG - size));
-	if (tmp == 0UL)        /* Are any bits set? */
-		return result + size; /* Nope. */
-found_middle:
-	return result + __ffs(tmp);
-}
-
-/**
- * find_first_bit - find the first set bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first set bit, not the number of the byte
- * containing a bit.
- */
-#define find_first_bit(addr, size) \
-        find_next_bit((addr), (size), 0)
-
-#define _EXT2_HAVE_ASM_BITOPS_
+#include <asm-generic/bitops/find.h>
 
 #ifdef __KERNEL__
-/*
- * test_and_{set,clear}_bit guarantee atomicity without
- * disabling interrupts.
- */
+
+#include <asm-generic/bitops/ext2-non-atomic.h>
 
 /* '3' is bits per byte */
 #define LE_BYTE_ADDR ((sizeof(unsigned long) - 1) << 3)
 
-#define ext2_test_bit(nr, addr) \
-			test_bit((nr)	^ LE_BYTE_ADDR, (unsigned long *)addr)
-#define ext2_set_bit(nr, addr)	\
-		__test_and_set_bit((nr) ^ LE_BYTE_ADDR, (unsigned long *)addr)
-#define ext2_clear_bit(nr, addr) \
-		__test_and_clear_bit((nr) ^ LE_BYTE_ADDR, (unsigned long *)addr)
-
 #define ext2_set_bit_atomic(l,nr,addr) \
 		test_and_set_bit((nr)   ^ LE_BYTE_ADDR, (unsigned long *)addr)
 #define ext2_clear_bit_atomic(l,nr,addr) \
@@ -419,77 +222,6 @@
 
 #endif	/* __KERNEL__ */
 
-
-#define ext2_find_first_zero_bit(addr, size) \
-	ext2_find_next_zero_bit((addr), (size), 0)
-
-/* include/linux/byteorder does not support "unsigned long" type */
-static inline unsigned long ext2_swabp(unsigned long * x)
-{
-#ifdef __LP64__
-	return (unsigned long) __swab64p((u64 *) x);
-#else
-	return (unsigned long) __swab32p((u32 *) x);
-#endif
-}
-
-/* include/linux/byteorder doesn't support "unsigned long" type */
-static inline unsigned long ext2_swab(unsigned long y)
-{
-#ifdef __LP64__
-	return (unsigned long) __swab64((u64) y);
-#else
-	return (unsigned long) __swab32((u32) y);
-#endif
-}
-
-static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
-{
-	unsigned long *p = (unsigned long *) addr + (offset >> SHIFT_PER_LONG);
-	unsigned long result = offset & ~(BITS_PER_LONG - 1);
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= (BITS_PER_LONG - 1UL);
-	if (offset) {
-		tmp = ext2_swabp(p++);
-		tmp |= (~0UL >> (BITS_PER_LONG - offset));
-		if (size < BITS_PER_LONG)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= BITS_PER_LONG;
-		result += BITS_PER_LONG;
-	}
-
-	while (size & ~(BITS_PER_LONG - 1)) {
-		if (~(tmp = *(p++)))
-			goto found_middle_swap;
-		result += BITS_PER_LONG;
-		size -= BITS_PER_LONG;
-	}
-	if (!size)
-		return result;
-	tmp = ext2_swabp(p);
-found_first:
-	tmp |= ~0UL << size;
-	if (tmp == ~0UL)	/* Are any bits zero? */
-		return result + size; /* Nope. Skip ffz */
-found_middle:
-	return result + ffz(tmp);
-
-found_middle_swap:
-	return result + ffz(ext2_swab(tmp));
-}
-
-
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit(nr,addr) ext2_set_bit(nr,addr)
-#define minix_set_bit(nr,addr) ((void)ext2_set_bit(nr,addr))
-#define minix_test_and_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr) ext2_test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size)
+#include <asm-generic/bitops/minix-le.h>
 
 #endif /* _PARISC_BITOPS_H */
diff --git a/include/asm-parisc/cache.h b/include/asm-parisc/cache.h
index ae50f8e..c831665 100644
--- a/include/asm-parisc/cache.h
+++ b/include/asm-parisc/cache.h
@@ -48,7 +48,7 @@
 extern void flush_kernel_icache_range_asm(unsigned long, unsigned long);
 extern void flush_user_dcache_range_asm(unsigned long, unsigned long);
 extern void flush_kernel_dcache_range_asm(unsigned long, unsigned long);
-extern void flush_kernel_dcache_page(void *);
+extern void flush_kernel_dcache_page_asm(void *);
 extern void flush_kernel_icache_page(void *);
 extern void disable_sr_hashing(void);   /* turns off space register hashing */
 extern void disable_sr_hashing_asm(int); /* low level support for above */
diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h
index c53af9f..76b6b7d 100644
--- a/include/asm-parisc/cacheflush.h
+++ b/include/asm-parisc/cacheflush.h
@@ -62,7 +62,7 @@
 #define flush_dcache_mmap_unlock(mapping) \
 	write_unlock_irq(&(mapping)->tree_lock)
 
-#define flush_icache_page(vma,page)	do { flush_kernel_dcache_page(page_address(page)); flush_kernel_icache_page(page_address(page)); } while (0)
+#define flush_icache_page(vma,page)	do { flush_kernel_dcache_page(page); flush_kernel_icache_page(page_address(page)); } while (0)
 
 #define flush_icache_range(s,e)		do { flush_kernel_dcache_range_asm(s,e); flush_kernel_icache_range_asm(s,e); } while (0)
 
@@ -184,6 +184,21 @@
 
 }
 
+static inline void
+flush_anon_page(struct page *page, unsigned long vmaddr)
+{
+	if (PageAnon(page))
+		flush_user_dcache_page(vmaddr);
+}
+#define ARCH_HAS_FLUSH_ANON_PAGE
+
+static inline void
+flush_kernel_dcache_page(struct page *page)
+{
+	flush_kernel_dcache_page_asm(page_address(page));
+}
+#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+
 #ifdef CONFIG_DEBUG_RODATA
 void mark_rodata_ro(void);
 #endif
diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
index 38b918f..289624d 100644
--- a/include/asm-parisc/compat.h
+++ b/include/asm-parisc/compat.h
@@ -138,6 +138,11 @@
 	return (void __user *)(unsigned long)uptr;
 }
 
+static inline compat_uptr_t ptr_to_compat(void __user *uptr)
+{
+	return (u32)(unsigned long)uptr;
+}
+
 static __inline__ void __user *compat_alloc_user_space(long len)
 {
 	struct pt_regs *regs = &current->thread.regs;
diff --git a/include/asm-parisc/io.h b/include/asm-parisc/io.h
index be0c723..29da311 100644
--- a/include/asm-parisc/io.h
+++ b/include/asm-parisc/io.h
@@ -25,35 +25,11 @@
  *   eg dev->hpa or 0xfee00000.
  */
 
-#ifdef CONFIG_DEBUG_IOREMAP
-#ifdef CONFIG_64BIT
-#define NYBBLE_SHIFT 60
-#else
-#define NYBBLE_SHIFT 28
-#endif
-extern void gsc_bad_addr(unsigned long addr);
-extern void __raw_bad_addr(const volatile void __iomem *addr);
-#define gsc_check_addr(addr)					\
-	if ((addr >> NYBBLE_SHIFT) != 0xf) {			\
-		gsc_bad_addr(addr);				\
-		addr |= 0xfUL << NYBBLE_SHIFT;			\
-	}
-#define __raw_check_addr(addr)					\
-	if (((unsigned long)addr >> NYBBLE_SHIFT) != 0xe)	\
-		__raw_bad_addr(addr);			\
-	addr = (void __iomem *)((unsigned long)addr | (0xfUL << NYBBLE_SHIFT));
-#else
-#define gsc_check_addr(addr)
-#define __raw_check_addr(addr)
-#endif
-
 static inline unsigned char gsc_readb(unsigned long addr)
 {
 	long flags;
 	unsigned char ret;
 
-	gsc_check_addr(addr);
-
 	__asm__ __volatile__(
 	"	rsm	2,%0\n"
 	"	ldbx	0(%2),%1\n"
@@ -68,8 +44,6 @@
 	long flags;
 	unsigned short ret;
 
-	gsc_check_addr(addr);
-
 	__asm__ __volatile__(
 	"	rsm	2,%0\n"
 	"	ldhx	0(%2),%1\n"
@@ -83,8 +57,6 @@
 {
 	u32 ret;
 
-	gsc_check_addr(addr);
-
 	__asm__ __volatile__(
 	"	ldwax	0(%1),%0\n"
 	: "=r" (ret) : "r" (addr) );
@@ -95,7 +67,6 @@
 static inline unsigned long long gsc_readq(unsigned long addr)
 {
 	unsigned long long ret;
-	gsc_check_addr(addr);
 
 #ifdef __LP64__
 	__asm__ __volatile__(
@@ -112,8 +83,6 @@
 static inline void gsc_writeb(unsigned char val, unsigned long addr)
 {
 	long flags;
-	gsc_check_addr(addr);
-
 	__asm__ __volatile__(
 	"	rsm	2,%0\n"
 	"	stbs	%1,0(%2)\n"
@@ -124,8 +93,6 @@
 static inline void gsc_writew(unsigned short val, unsigned long addr)
 {
 	long flags;
-	gsc_check_addr(addr);
-
 	__asm__ __volatile__(
 	"	rsm	2,%0\n"
 	"	sths	%1,0(%2)\n"
@@ -135,8 +102,6 @@
 
 static inline void gsc_writel(unsigned int val, unsigned long addr)
 {
-	gsc_check_addr(addr);
-
 	__asm__ __volatile__(
 	"	stwas	%0,0(%1)\n"
 	: :  "r" (val), "r" (addr) );
@@ -144,8 +109,6 @@
 
 static inline void gsc_writeq(unsigned long long val, unsigned long addr)
 {
-	gsc_check_addr(addr);
-
 #ifdef __LP64__
 	__asm__ __volatile__(
 	"	stda	%0,0(%1)\n"
@@ -180,14 +143,7 @@
 
 extern void iounmap(void __iomem *addr);
 
-/*
- * USE_HPPA_IOREMAP is the magic flag to enable or disable real ioremap()
- * functionality.  It's currently disabled because it may not work on some
- * machines.
- */
-#define USE_HPPA_IOREMAP 0
 
-#if USE_HPPA_IOREMAP
 static inline unsigned char __raw_readb(const volatile void __iomem *addr)
 {
 	return (*(volatile unsigned char __force *) (addr));
@@ -221,57 +177,6 @@
 {
 	*(volatile unsigned long long __force *) addr = b;
 }
-#else /* !USE_HPPA_IOREMAP */
-static inline unsigned char __raw_readb(const volatile void __iomem *addr)
-{
-	__raw_check_addr(addr);
-
-	return gsc_readb((unsigned long) addr);
-}
-static inline unsigned short __raw_readw(const volatile void __iomem *addr)
-{
-	__raw_check_addr(addr);
-
-	return gsc_readw((unsigned long) addr);
-}
-static inline unsigned int __raw_readl(const volatile void __iomem *addr)
-{
-	__raw_check_addr(addr);
-
-	return gsc_readl((unsigned long) addr);
-}
-static inline unsigned long long __raw_readq(const volatile void __iomem *addr)
-{
-	__raw_check_addr(addr);
-
-	return gsc_readq((unsigned long) addr);
-}
-
-static inline void __raw_writeb(unsigned char b, volatile void __iomem *addr)
-{
-	__raw_check_addr(addr);
-
-	gsc_writeb(b, (unsigned long) addr);
-}
-static inline void __raw_writew(unsigned short b, volatile void __iomem *addr)
-{
-	__raw_check_addr(addr);
-
-	gsc_writew(b, (unsigned long) addr);
-}
-static inline void __raw_writel(unsigned int b, volatile void __iomem *addr)
-{
-	__raw_check_addr(addr);
-
-	gsc_writel(b, (unsigned long) addr);
-}
-static inline void __raw_writeq(unsigned long long b, volatile void __iomem *addr)
-{
-	__raw_check_addr(addr);
-
-	gsc_writeq(b, (unsigned long) addr);
-}
-#endif /* !USE_HPPA_IOREMAP */
 
 /* readb can never be const, so use __fswab instead of le*_to_cpu */
 #define readb(addr) __raw_readb(addr)
diff --git a/include/asm-parisc/local.h b/include/asm-parisc/local.h
index 892b3b2..d0f5509 100644
--- a/include/asm-parisc/local.h
+++ b/include/asm-parisc/local.h
@@ -4,16 +4,16 @@
 #include <linux/percpu.h>
 #include <asm/atomic.h>
 
-typedef atomic_t local_t;
+typedef atomic_long_t local_t;
 
-#define LOCAL_INIT(i)	ATOMIC_INIT(i)
-#define local_read(v)	atomic_read(v)
-#define local_set(v,i)	atomic_set(v,i)
+#define LOCAL_INIT(i)	ATOMIC_LONG_INIT(i)
+#define local_read(v)	atomic_long_read(v)
+#define local_set(v,i)	atomic_long_set(v,i)
 
-#define local_inc(v)	atomic_inc(v)
-#define local_dec(v)	atomic_dec(v)
-#define local_add(i, v)	atomic_add(i, v)
-#define local_sub(i, v)	atomic_sub(i, v)
+#define local_inc(v)	atomic_long_inc(v)
+#define local_dec(v)	atomic_long_dec(v)
+#define local_add(i, v)	atomic_long_add(i, v)
+#define local_sub(i, v)	atomic_long_sub(i, v)
 
 #define __local_inc(v)		((v)->counter++)
 #define __local_dec(v)		((v)->counter--)
diff --git a/include/asm-parisc/mmzone.h b/include/asm-parisc/mmzone.h
index ae039f4..ceb9b73 100644
--- a/include/asm-parisc/mmzone.h
+++ b/include/asm-parisc/mmzone.h
@@ -25,23 +25,6 @@
 	pg_data_t *__pgdat = NODE_DATA(nid);				\
 	__pgdat->node_start_pfn + __pgdat->node_spanned_pages;		\
 })
-#define node_localnr(pfn, nid)		((pfn) - node_start_pfn(nid))
-
-#define pfn_to_page(pfn)						\
-({									\
-	unsigned long __pfn = (pfn);					\
-	int __node  = pfn_to_nid(__pfn);				\
-	&NODE_DATA(__node)->node_mem_map[node_localnr(__pfn,__node)];	\
-})
-
-#define page_to_pfn(pg)							\
-({									\
-	struct page *__page = pg;					\
-	struct zone *__zone = page_zone(__page);			\
-	BUG_ON(__zone == NULL);						\
-	(unsigned long)(__page - __zone->zone_mem_map)			\
-		+ __zone->zone_start_pfn;				\
-})
 
 /* We have these possible memory map layouts:
  * Astro: 0-3.75, 67.75-68, 4-64
diff --git a/include/asm-parisc/page.h b/include/asm-parisc/page.h
index 4a6752b..45e02aa 100644
--- a/include/asm-parisc/page.h
+++ b/include/asm-parisc/page.h
@@ -26,7 +26,7 @@
 copy_user_page(void *vto, void *vfrom, unsigned long vaddr, struct page *pg)
 {
 	copy_user_page_asm(vto, vfrom);
-	flush_kernel_dcache_page(vto);
+	flush_kernel_dcache_page_asm(vto);
 	/* XXX: ppc flushes icache too, should we? */
 }
 
@@ -40,14 +40,19 @@
 /*
  * These are used to make use of C type-checking..
  */
-#ifdef __LP64__
-typedef struct { unsigned long pte; } pte_t;
-#else
-typedef struct {
-	unsigned long pte;
-	unsigned long flags;
-} pte_t;
+#define STRICT_MM_TYPECHECKS
+#ifdef STRICT_MM_TYPECHECKS
+typedef struct { unsigned long pte;
+#if !defined(CONFIG_64BIT)
+                 unsigned long future_flags;
+ /* XXX: it's possible to remove future_flags and change BITS_PER_PTE_ENTRY
+	 to 2, but then strangely the identical 32bit kernel boots on a
+	 c3000(pa20), but not any longer on a 715(pa11).
+	 Still investigating... HelgeD.
+  */
 #endif
+} pte_t; /* either 32 or 64bit */
+
 /* NOTE: even on 64 bits, these entries are __u32 because we allocate
  * the pmd and pgd in ZONE_DMA (i.e. under 4GB) */
 typedef struct { __u32 pmd; } pmd_t;
@@ -55,25 +60,44 @@
 typedef struct { unsigned long pgprot; } pgprot_t;
 
 #define pte_val(x)	((x).pte)
-#ifdef __LP64__
-#define pte_flags(x)	(*(__u32 *)&((x).pte))
-#else
-#define pte_flags(x)	((x).flags)
-#endif
-
 /* These do not work lvalues, so make sure we don't use them as such. */
 #define pmd_val(x)	((x).pmd + 0)
 #define pgd_val(x)	((x).pgd + 0)
 #define pgprot_val(x)	((x).pgprot)
 
-#define __pmd_val_set(x,n) (x).pmd = (n)
-#define __pgd_val_set(x,n) (x).pgd = (n)
-
 #define __pte(x)	((pte_t) { (x) } )
 #define __pmd(x)	((pmd_t) { (x) } )
 #define __pgd(x)	((pgd_t) { (x) } )
 #define __pgprot(x)	((pgprot_t) { (x) } )
 
+#define __pmd_val_set(x,n) (x).pmd = (n)
+#define __pgd_val_set(x,n) (x).pgd = (n)
+
+#else
+/*
+ * .. while these make it easier on the compiler
+ */
+typedef unsigned long pte_t;
+typedef         __u32 pmd_t;
+typedef         __u32 pgd_t;
+typedef unsigned long pgprot_t;
+
+#define pte_val(x)      (x)
+#define pmd_val(x)      (x)
+#define pgd_val(x)      (x)
+#define pgprot_val(x)   (x)
+
+#define __pte(x)        (x)
+#define __pmd(x)	(x)
+#define __pgd(x)        (x)
+#define __pgprot(x)     (x)
+
+#define __pmd_val_set(x,n) (x) = (n)
+#define __pgd_val_set(x,n) (x) = (n)
+
+#endif /* STRICT_MM_TYPECHECKS */
+
+
 typedef struct __physmem_range {
 	unsigned long start_pfn;
 	unsigned long pages;       /* PAGE_SIZE pages */
@@ -130,8 +154,6 @@
 #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
 
 #ifndef CONFIG_DISCONTIGMEM
-#define pfn_to_page(pfn)	(mem_map + (pfn))
-#define page_to_pfn(page)	((unsigned long)((page) - mem_map))
 #define pfn_valid(pfn)		((pfn) < max_mapnr)
 #endif /* CONFIG_DISCONTIGMEM */
 
@@ -152,6 +174,7 @@
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* _PARISC_PAGE_H */
diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h
index fe7f6a2..77bbafb 100644
--- a/include/asm-parisc/pci.h
+++ b/include/asm-parisc/pci.h
@@ -289,4 +289,9 @@
 {
 }
 
+static inline void pcibios_penalize_isa_irq(int irq, int active)
+{
+	/* We don't need to penalize isa irq's */
+}
+
 #endif /* __ASM_PARISC_PCI_H */
diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h
index 8e23e4c..0a3face 100644
--- a/include/asm-parisc/pdc.h
+++ b/include/asm-parisc/pdc.h
@@ -333,7 +333,7 @@
 	unsigned long curr_key;
 };
 
-/* Values for PDC_MODEL_CAPABILITES non-equivalent virtual aliasing support */
+/* Values for PDC_MODEL_CAPABILITIES non-equivalent virtual aliasing support */
 
 #define PDC_MODEL_IOPDIR_FDC            (1 << 2)        /* see sba_iommu.c */
 #define PDC_MODEL_NVA_MASK		(3 << 4)
diff --git a/include/asm-parisc/pdc_chassis.h b/include/asm-parisc/pdc_chassis.h
index adac9ac..a609273 100644
--- a/include/asm-parisc/pdc_chassis.h
+++ b/include/asm-parisc/pdc_chassis.h
@@ -6,9 +6,8 @@
  *
  *
  *      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.
+ *      it under the terms of the GNU General Public License, version 2, as
+ *      published by the Free Software Foundation.
  *      
  *      This program is distributed in the hope that it will be useful,
  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h
index 16c2ac0..a93960e 100644
--- a/include/asm-parisc/spinlock.h
+++ b/include/asm-parisc/spinlock.h
@@ -134,14 +134,22 @@
 	return 1;
 }
 
-static __inline__ int __raw_is_read_locked(raw_rwlock_t *rw)
+/*
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+static __inline__ int __raw_read_can_lock(raw_rwlock_t *rw)
 {
-	return rw->counter > 0;
+	return rw->counter >= 0;
 }
 
-static __inline__ int __raw_is_write_locked(raw_rwlock_t *rw)
+/*
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+static __inline__ int __raw_write_can_lock(raw_rwlock_t *rw)
 {
-	return rw->counter < 0;
+	return !rw->counter;
 }
 
 #endif /* __ASM_SPINLOCK_H */
diff --git a/include/asm-parisc/thread_info.h b/include/asm-parisc/thread_info.h
index ac32f14..f2f83b0 100644
--- a/include/asm-parisc/thread_info.h
+++ b/include/asm-parisc/thread_info.h
@@ -49,7 +49,8 @@
 
 #endif /* !__ASSEMBLY */
 
-#define PREEMPT_ACTIVE          0x10000000
+#define PREEMPT_ACTIVE_BIT	28
+#define PREEMPT_ACTIVE		(1 << PREEMPT_ACTIVE_BIT)
 
 /*
  * thread information flags
diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h
index bf6941a..d1c2a44 100644
--- a/include/asm-powerpc/bitops.h
+++ b/include/asm-powerpc/bitops.h
@@ -184,72 +184,7 @@
 	: "cc");
 }
 
-/* Non-atomic versions */
-static __inline__ int test_bit(unsigned long nr,
-			       __const__ volatile unsigned long *addr)
-{
-	return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
-}
-
-static __inline__ void __set_bit(unsigned long nr,
-				 volatile unsigned long *addr)
-{
-	unsigned long mask = BITOP_MASK(nr);
-	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-	*p  |= mask;
-}
-
-static __inline__ void __clear_bit(unsigned long nr,
-				   volatile unsigned long *addr)
-{
-	unsigned long mask = BITOP_MASK(nr);
-	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-	*p &= ~mask;
-}
-
-static __inline__ void __change_bit(unsigned long nr,
-				    volatile unsigned long *addr)
-{
-	unsigned long mask = BITOP_MASK(nr);
-	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-	*p ^= mask;
-}
-
-static __inline__ int __test_and_set_bit(unsigned long nr,
-					 volatile unsigned long *addr)
-{
-	unsigned long mask = BITOP_MASK(nr);
-	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-	unsigned long old = *p;
-
-	*p = old | mask;
-	return (old & mask) != 0;
-}
-
-static __inline__ int __test_and_clear_bit(unsigned long nr,
-					   volatile unsigned long *addr)
-{
-	unsigned long mask = BITOP_MASK(nr);
-	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-	unsigned long old = *p;
-
-	*p = old & ~mask;
-	return (old & mask) != 0;
-}
-
-static __inline__ int __test_and_change_bit(unsigned long nr,
-					    volatile unsigned long *addr)
-{
-	unsigned long mask = BITOP_MASK(nr);
-	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-	unsigned long old = *p;
-
-	*p = old ^ mask;
-	return (old & mask) != 0;
-}
+#include <asm-generic/bitops/non-atomic.h>
 
 /*
  * Return the zero-based bit position (LE, not IBM bit numbering) of
@@ -310,16 +245,9 @@
 	asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x));
 	return 32 - lz;
 }
-#define fls64(x)   generic_fls64(x)
+#include <asm-generic/bitops/fls64.h>
 
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-#define hweight64(x) generic_hweight64(x)
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
+#include <asm-generic/bitops/hweight.h>
 
 #define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
 unsigned long find_next_zero_bit(const unsigned long *addr,
@@ -397,32 +325,7 @@
 #define minix_find_first_zero_bit(addr,size) \
 	find_first_zero_le_bit((unsigned long *)addr, size)
 
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-static inline int sched_find_first_bit(const unsigned long *b)
-{
-#ifdef CONFIG_PPC64
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 64;
-	return __ffs(b[2]) + 128;
-#else
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-#endif
-}
+#include <asm-generic/bitops/sched.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-powerpc/bug.h b/include/asm-powerpc/bug.h
index 99817a8..f44b529 100644
--- a/include/asm-powerpc/bug.h
+++ b/include/asm-powerpc/bug.h
@@ -30,34 +30,60 @@
 
 #ifdef CONFIG_BUG
 
+/*
+ * BUG_ON() and WARN_ON() do their best to cooperate with compile-time
+ * optimisations. However depending on the complexity of the condition
+ * some compiler versions may not produce optimal results.
+ */
+
 #define BUG() do {							 \
 	__asm__ __volatile__(						 \
 		"1:	twi 31,0,0\n"					 \
 		".section __bug_table,\"a\"\n"				 \
-		"\t"PPC_LONG"	1b,%0,%1,%2\n"			 \
+		"\t"PPC_LONG"	1b,%0,%1,%2\n"				 \
 		".previous"						 \
 		: : "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__)); \
 } while (0)
 
 #define BUG_ON(x) do {						\
-	__asm__ __volatile__(					\
+	if (__builtin_constant_p(x)) {				\
+		if (x)						\
+			BUG();					\
+	} else {						\
+		__asm__ __volatile__(				\
 		"1:	"PPC_TLNEI"	%0,0\n"			\
 		".section __bug_table,\"a\"\n"			\
-		"\t"PPC_LONG"	1b,%1,%2,%3\n"		\
+		"\t"PPC_LONG"	1b,%1,%2,%3\n"			\
 		".previous"					\
 		: : "r" ((long)(x)), "i" (__LINE__),		\
 		    "i" (__FILE__), "i" (__FUNCTION__));	\
+	}							\
+} while (0)
+
+#define __WARN() do {						\
+	__asm__ __volatile__(					\
+		"1:	twi 31,0,0\n"				\
+		".section __bug_table,\"a\"\n"			\
+		"\t"PPC_LONG"	1b,%0,%1,%2\n"			\
+		".previous"					\
+		: : "i" (__LINE__ + BUG_WARNING_TRAP),		\
+		    "i" (__FILE__), "i" (__FUNCTION__));	\
 } while (0)
 
 #define WARN_ON(x) do {						\
-	__asm__ __volatile__(					\
+	if (__builtin_constant_p(x)) {				\
+		if (x)						\
+			__WARN();				\
+	} else {						\
+		__asm__ __volatile__(				\
 		"1:	"PPC_TLNEI"	%0,0\n"			\
 		".section __bug_table,\"a\"\n"			\
-		"\t"PPC_LONG"	1b,%1,%2,%3\n"		\
+		"\t"PPC_LONG"	1b,%1,%2,%3\n"			\
 		".previous"					\
 		: : "r" ((long)(x)),				\
 		    "i" (__LINE__ + BUG_WARNING_TRAP),		\
 		    "i" (__FILE__), "i" (__FUNCTION__));	\
+	}							\
 } while (0)
 
 #define HAVE_ARCH_BUG
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index fe45f6f..4321483 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -188,153 +188,154 @@
 		     !defined(CONFIG_POWER3) && !defined(CONFIG_POWER4) && \
 		     !defined(CONFIG_BOOKE))
 
-enum {
-	CPU_FTRS_PPC601 = CPU_FTR_COMMON | CPU_FTR_601 | CPU_FTR_HPTE_TABLE,
-	CPU_FTRS_603 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB |
-	    CPU_FTR_MAYBE_CAN_NAP,
-	CPU_FTRS_604 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE,
-	CPU_FTRS_740_NOTAU = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR |
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP,
-	CPU_FTRS_740 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR |
-	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP,
-	CPU_FTRS_750 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR |
-	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP,
-	CPU_FTRS_750FX1 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR |
-	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP |
-	    CPU_FTR_DUAL_PLL_750FX | CPU_FTR_NO_DPM,
-	CPU_FTRS_750FX2 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR |
-	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP |
-	    CPU_FTR_NO_DPM,
-	CPU_FTRS_750FX = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR |
-	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP |
-	    CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS,
-	CPU_FTRS_750GX = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
-	    CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU |
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP |
-	    CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS,
-	CPU_FTRS_7400_NOTAU = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR |
-	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE |
-	    CPU_FTR_MAYBE_CAN_NAP,
-	CPU_FTRS_7400 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR |
-	    CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE |
-	    CPU_FTR_MAYBE_CAN_NAP,
-	CPU_FTRS_7450_20 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP |
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 |
-	    CPU_FTR_NEED_COHERENT,
-	CPU_FTRS_7450_21 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB |
-	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP |
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 |
-	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP |
-	    CPU_FTR_NEED_COHERENT,
-	CPU_FTRS_7450_23 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB |
-	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP |
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 |
-	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_NEED_COHERENT,
-	CPU_FTRS_7455_1 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB |
-	    CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_HAS_HIGH_BATS |
-	    CPU_FTR_NEED_COHERENT,
-	CPU_FTRS_7455_20 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB |
-	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP |
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 |
-	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP |
-	    CPU_FTR_NEED_COHERENT | CPU_FTR_HAS_HIGH_BATS,
-	CPU_FTRS_7455 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB |
-	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP |
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 |
-	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS |
-	    CPU_FTR_NEED_COHERENT,
-	CPU_FTRS_7447_10 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB |
-	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP |
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 |
-	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS |
-	    CPU_FTR_NEED_COHERENT | CPU_FTR_NO_BTIC,
-	CPU_FTRS_7447 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB |
-	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP |
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 |
-	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS |
-	    CPU_FTR_NEED_COHERENT,
-	CPU_FTRS_7447A = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB |
-	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP |
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 |
-	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS |
-	    CPU_FTR_NEED_COHERENT,
-	CPU_FTRS_82XX = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB,
-	CPU_FTRS_G2_LE = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
-	    CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS,
-	CPU_FTRS_E300 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
-	    CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS |
-	    CPU_FTR_COMMON,
-	CPU_FTRS_CLASSIC32 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE,
-	CPU_FTRS_POWER3_32 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE,
-	CPU_FTRS_POWER4_32 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_NODSISRALIGN,
-	CPU_FTRS_970_32 = CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE |
-	    CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_ALTIVEC_COMP |
-	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN,
-	CPU_FTRS_8XX = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
-	CPU_FTRS_40X = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	    CPU_FTR_NODSISRALIGN,
-	CPU_FTRS_44X = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	    CPU_FTR_NODSISRALIGN,
-	CPU_FTRS_E200 = CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN,
-	CPU_FTRS_E500 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	    CPU_FTR_NODSISRALIGN,
-	CPU_FTRS_E500_2 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	    CPU_FTR_BIG_PHYS | CPU_FTR_NODSISRALIGN,
-	CPU_FTRS_GENERIC_32 = CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN,
+#define CPU_FTRS_PPC601	(CPU_FTR_COMMON | CPU_FTR_601 | CPU_FTR_HPTE_TABLE)
+#define CPU_FTRS_603	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
+	    CPU_FTR_MAYBE_CAN_NAP)
+#define CPU_FTRS_604	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE)
+#define CPU_FTRS_740_NOTAU	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+	    CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP)
+#define CPU_FTRS_740	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP)
+#define CPU_FTRS_750	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP)
+#define CPU_FTRS_750FX1	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+	    CPU_FTR_DUAL_PLL_750FX | CPU_FTR_NO_DPM)
+#define CPU_FTRS_750FX2	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+	    CPU_FTR_NO_DPM)
+#define CPU_FTRS_750FX	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+	    CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS)
+#define CPU_FTRS_750GX	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
+	    CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | \
+	    CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+	    CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS)
+#define CPU_FTRS_7400_NOTAU	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | \
+	    CPU_FTR_MAYBE_CAN_NAP)
+#define CPU_FTRS_7400	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+	    CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | \
+	    CPU_FTR_MAYBE_CAN_NAP)
+#define CPU_FTRS_7450_20	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
+	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
+	    CPU_FTR_NEED_COHERENT)
+#define CPU_FTRS_7450_21	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | \
+	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
+	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
+	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | \
+	    CPU_FTR_NEED_COHERENT)
+#define CPU_FTRS_7450_23	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | \
+	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
+	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
+	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_NEED_COHERENT)
+#define CPU_FTRS_7455_1	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | \
+	    CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | \
+	    CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_HAS_HIGH_BATS | \
+	    CPU_FTR_NEED_COHERENT)
+#define CPU_FTRS_7455_20	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | \
+	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
+	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
+	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | \
+	    CPU_FTR_NEED_COHERENT | CPU_FTR_HAS_HIGH_BATS)
+#define CPU_FTRS_7455	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | \
+	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
+	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
+	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
+	    CPU_FTR_NEED_COHERENT)
+#define CPU_FTRS_7447_10	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | \
+	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
+	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
+	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
+	    CPU_FTR_NEED_COHERENT | CPU_FTR_NO_BTIC)
+#define CPU_FTRS_7447	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | \
+	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
+	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
+	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
+	    CPU_FTR_NEED_COHERENT)
+#define CPU_FTRS_7447A	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | \
+	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
+	    CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
+	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
+	    CPU_FTR_NEED_COHERENT)
+#define CPU_FTRS_82XX	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB)
+#define CPU_FTRS_G2_LE	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
+	    CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS)
+#define CPU_FTRS_E300	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
+	    CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \
+	    CPU_FTR_COMMON)
+#define CPU_FTRS_CLASSIC32	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE)
+#define CPU_FTRS_POWER3_32	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE)
+#define CPU_FTRS_POWER4_32	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_NODSISRALIGN)
+#define CPU_FTRS_970_32	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_ALTIVEC_COMP | \
+	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN)
+#define CPU_FTRS_8XX	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB)
+#define CPU_FTRS_40X	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+	    CPU_FTR_NODSISRALIGN)
+#define CPU_FTRS_44X	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+	    CPU_FTR_NODSISRALIGN)
+#define CPU_FTRS_E200	(CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN)
+#define CPU_FTRS_E500	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+	    CPU_FTR_NODSISRALIGN)
+#define CPU_FTRS_E500_2	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+	    CPU_FTR_BIG_PHYS | CPU_FTR_NODSISRALIGN)
+#define CPU_FTRS_GENERIC_32	(CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
 #ifdef __powerpc64__
-	CPU_FTRS_POWER3 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_IABR,
-	CPU_FTRS_RS64 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
-	    CPU_FTR_MMCRA | CPU_FTR_CTRL,
-	CPU_FTRS_POWER4 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA,
-	CPU_FTRS_PPC970 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 |
-	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA,
-	CPU_FTRS_POWER5 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 |
-	    CPU_FTR_MMCRA | CPU_FTR_SMT |
-	    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
-	    CPU_FTR_MMCRA_SIHV | CPU_FTR_PURR,
-	CPU_FTRS_CELL = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 |
-	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT |
-	    CPU_FTR_CTRL | CPU_FTR_PAUSE_ZERO,
-	CPU_FTRS_COMPATIBLE = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2,
+#define CPU_FTRS_POWER3	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+	    CPU_FTR_HPTE_TABLE | CPU_FTR_IABR)
+#define CPU_FTRS_RS64	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+	    CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | \
+	    CPU_FTR_MMCRA | CPU_FTR_CTRL)
+#define CPU_FTRS_POWER4	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA)
+#define CPU_FTRS_PPC970	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
+	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA)
+#define CPU_FTRS_POWER5	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
+	    CPU_FTR_MMCRA | CPU_FTR_SMT | \
+	    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
+	    CPU_FTR_MMCRA_SIHV | CPU_FTR_PURR)
+#define CPU_FTRS_CELL	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
+	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
+	    CPU_FTR_CTRL | CPU_FTR_PAUSE_ZERO)
+#define CPU_FTRS_COMPATIBLE	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2)
 #endif
 
-	CPU_FTRS_POSSIBLE =
 #ifdef __powerpc64__
-	    CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |
-	    CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_CELL |
-            CPU_FTR_CI_LARGE_PAGE |
+#define CPU_FTRS_POSSIBLE	\
+	    (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |	\
+	    CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_CELL |	\
+            CPU_FTR_CI_LARGE_PAGE)
 #else
+enum {
+	CPU_FTRS_POSSIBLE =
 #if CLASSIC_PPC
 	    CPU_FTRS_PPC601 | CPU_FTRS_603 | CPU_FTRS_604 | CPU_FTRS_740_NOTAU |
 	    CPU_FTRS_740 | CPU_FTRS_750 | CPU_FTRS_750FX1 |
@@ -368,14 +369,18 @@
 #ifdef CONFIG_E500
 	    CPU_FTRS_E500 | CPU_FTRS_E500_2 |
 #endif
-#endif /* __powerpc64__ */
 	    0,
+};
+#endif /* __powerpc64__ */
 
-	CPU_FTRS_ALWAYS =
 #ifdef __powerpc64__
-	    CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 &
-	    CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_CELL &
+#define CPU_FTRS_ALWAYS		\
+	    (CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 &	\
+	    CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_CELL &	\
+	    CPU_FTRS_POSSIBLE)
 #else
+enum {
+	CPU_FTRS_ALWAYS =
 #if CLASSIC_PPC
 	    CPU_FTRS_PPC601 & CPU_FTRS_603 & CPU_FTRS_604 & CPU_FTRS_740_NOTAU &
 	    CPU_FTRS_740 & CPU_FTRS_750 & CPU_FTRS_750FX1 &
@@ -409,9 +414,9 @@
 #ifdef CONFIG_E500
 	    CPU_FTRS_E500 & CPU_FTRS_E500_2 &
 #endif
-#endif /* __powerpc64__ */
 	    CPU_FTRS_POSSIBLE,
 };
+#endif /* __powerpc64__ */
 
 static inline int cpu_has_feature(unsigned long feature)
 {
diff --git a/include/asm-powerpc/firmware.h b/include/asm-powerpc/firmware.h
index ce37882..77069df 100644
--- a/include/asm-powerpc/firmware.h
+++ b/include/asm-powerpc/firmware.h
@@ -82,13 +82,11 @@
 /* This is used to identify firmware features which are available
  * to the kernel.
  */
-extern unsigned long	ppc64_firmware_features;
+extern unsigned long	powerpc_firmware_features;
 
-static inline unsigned long firmware_has_feature(unsigned long feature)
-{
-	return (FW_FEATURE_ALWAYS & feature) ||
-		(FW_FEATURE_POSSIBLE & ppc64_firmware_features & feature);
-}
+#define firmware_has_feature(feature)					\
+	((FW_FEATURE_ALWAYS & (feature)) ||				\
+		(FW_FEATURE_POSSIBLE & powerpc_firmware_features & (feature)))
 
 extern void system_reset_fwnmi(void);
 extern void machine_check_fwnmi(void);
diff --git a/include/asm-powerpc/floppy.h b/include/asm-powerpc/floppy.h
index e258778..608164c 100644
--- a/include/asm-powerpc/floppy.h
+++ b/include/asm-powerpc/floppy.h
@@ -35,6 +35,7 @@
 #ifdef CONFIG_PCI
 
 #include <linux/pci.h>
+#include <asm/ppc-pci.h>	/* for ppc64_isabridge_dev */
 
 #define fd_dma_setup(addr,size,mode,io) powerpc_fd_dma_setup(addr,size,mode,io)
 
@@ -52,12 +53,12 @@
 	if (bus_addr 
 	    && (addr != prev_addr || size != prev_size || dir != prev_dir)) {
 		/* different from last time -- unmap prev */
-		pci_unmap_single(NULL, bus_addr, prev_size, prev_dir);
+		pci_unmap_single(ppc64_isabridge_dev, bus_addr, prev_size, prev_dir);
 		bus_addr = 0;
 	}
 
 	if (!bus_addr)	/* need to map it */
-		bus_addr = pci_map_single(NULL, addr, size, dir);
+		bus_addr = pci_map_single(ppc64_isabridge_dev, addr, size, dir);
 
 	/* remember this one as prev */
 	prev_addr = addr;
diff --git a/include/asm-powerpc/futex.h b/include/asm-powerpc/futex.h
index 39e85f3..f1b3c00 100644
--- a/include/asm-powerpc/futex.h
+++ b/include/asm-powerpc/futex.h
@@ -81,5 +81,11 @@
 	return ret;
 }
 
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+	return -ENOSYS;
+}
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_FUTEX_H */
diff --git a/include/asm-powerpc/hvcall.h b/include/asm-powerpc/hvcall.h
index 38ca9ad..b72c04f 100644
--- a/include/asm-powerpc/hvcall.h
+++ b/include/asm-powerpc/hvcall.h
@@ -9,6 +9,7 @@
 #define H_Closed	2	/* Resource closed */
 #define H_Constrained	4	/* Resource request constrained to max allowed */
 #define H_InProgress   14	/* Kind of like busy */
+#define H_Pending      17	/* returned from H_POLL_PENDING */
 #define H_Continue     18	/* Returned from H_Join on success */
 #define H_LongBusyStartRange   9900  /* Start of long busy range */
 #define H_LongBusyOrder1msec   9900  /* Long busy, hint that 1msec is a good time to retry */
diff --git a/include/asm-powerpc/hvconsole.h b/include/asm-powerpc/hvconsole.h
index 34daf7b..35ea69e 100644
--- a/include/asm-powerpc/hvconsole.h
+++ b/include/asm-powerpc/hvconsole.h
@@ -24,28 +24,18 @@
 #ifdef __KERNEL__
 
 /*
- * This is the max number of console adapters that can/will be found as
- * console devices on first stage console init.  Any number beyond this range
- * can't be used as a console device but is still a valid tty device.
+ * PSeries firmware will only send/recv up to 16 bytes of character data per
+ * hcall.
  */
-#define MAX_NR_HVC_CONSOLES	16
+#define MAX_VIO_PUT_CHARS	16
+#define SIZE_VIO_GET_CHARS	16
 
-/* implemented by a low level driver */
-struct hv_ops {
-	int (*get_chars)(uint32_t vtermno, char *buf, int count);
-	int (*put_chars)(uint32_t vtermno, const char *buf, int count);
-};
+/*
+ * Vio firmware always attempts to fetch MAX_VIO_GET_CHARS chars.  The 'count'
+ * parm is included to conform to put_chars() function pointer template
+ */
 extern int hvc_get_chars(uint32_t vtermno, char *buf, int count);
 extern int hvc_put_chars(uint32_t vtermno, const char *buf, int count);
 
-struct hvc_struct;
-
-/* Register a vterm and a slot index for use as a console (console_init) */
-extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops);
-/* register a vterm for hvc tty operation (module_init or hotplug add) */
-extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq,
-						 struct hv_ops *ops);
-/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */
-extern int __devexit hvc_remove(struct hvc_struct *hp);
 #endif /* __KERNEL__ */
 #endif /* _PPC64_HVCONSOLE_H */
diff --git a/include/asm-powerpc/kdebug.h b/include/asm-powerpc/kdebug.h
index 7c16265..c01786a 100644
--- a/include/asm-powerpc/kdebug.h
+++ b/include/asm-powerpc/kdebug.h
@@ -16,13 +16,9 @@
 	int signr;
 };
 
-/*
-   Note - you should never unregister because that can race with NMIs.
-   If you really want to do it first unregister - then synchronize_sched -
-   then free.
- */
-int register_die_notifier(struct notifier_block *nb);
-extern struct notifier_block *powerpc_die_chain;
+extern int register_die_notifier(struct notifier_block *);
+extern int unregister_die_notifier(struct notifier_block *);
+extern struct atomic_notifier_head powerpc_die_chain;
 
 /* Grossly misnamed. */
 enum die_val {
@@ -37,7 +33,7 @@
 static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap, int sig)
 {
 	struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig };
-	return notifier_call_chain(&powerpc_die_chain, val, &args);
+	return atomic_notifier_call_chain(&powerpc_die_chain, val, &args);
 }
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index 5348b82..5ed8476 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -47,6 +47,7 @@
 #endif
 
 struct machdep_calls {
+	char		*name;
 #ifdef CONFIG_PPC64
 	void            (*hpte_invalidate)(unsigned long slot,
 					   unsigned long va,
@@ -85,9 +86,9 @@
 	void		(*iommu_dev_setup)(struct pci_dev *dev);
 	void		(*iommu_bus_setup)(struct pci_bus *bus);
 	void		(*irq_bus_setup)(struct pci_bus *bus);
-#endif
+#endif /* CONFIG_PPC64 */
 
-	int		(*probe)(int platform);
+	int		(*probe)(void);
 	void		(*setup_arch)(void);
 	void		(*init_early)(void);
 	/* Optional, may be NULL. */
@@ -158,6 +159,12 @@
 	/* Idle loop for this platform, leave empty for default idle loop */
 	void		(*idle_loop)(void);
 
+	/*
+	 * Function for waiting for work with reduced power in idle loop;
+	 * called with interrupts disabled.
+	 */
+	void		(*power_save)(void);
+
 	/* Function to enable performance monitor counters for this
 	   platform, called once per cpu. */
 	void		(*enable_pmcs)(void);
@@ -170,13 +177,6 @@
 	   May be NULL. */
 	void		(*init)(void);
 
-	void		(*idle)(void);
-	void		(*power_save)(void);
-
-	void		(*heartbeat)(void);
-	unsigned long	heartbeat_reset;
-	unsigned long	heartbeat_count;
-
 	void		(*setup_io_mappings)(void);
 
 	void		(*early_serial_map)(void);
@@ -208,8 +208,6 @@
 	/* Called at then very end of pcibios_init() */
 	void (*pcibios_after_init)(void);
 
-	/* this is for modules, since _machine can be a define -- Cort */
-	int ppc_machine;
 #endif /* CONFIG_PPC32 */
 
 	/* Called to shutdown machine specific hardware not already controlled
@@ -242,10 +240,29 @@
 #endif /* CONFIG_KEXEC */
 };
 
-extern void default_idle(void);
-extern void native_idle(void);
+extern void power4_idle(void);
+extern void ppc6xx_idle(void);
 
+/*
+ * ppc_md contains a copy of the machine description structure for the
+ * current platform. machine_id contains the initial address where the
+ * description was found during boot.
+ */
 extern struct machdep_calls ppc_md;
+extern struct machdep_calls *machine_id;
+
+#define __machine_desc __attribute__ ((__section__ (".machine.desc")))
+
+#define define_machine(name) struct machdep_calls mach_##name __machine_desc =
+#define machine_is(name) \
+	({ \
+		extern struct machdep_calls mach_##name \
+			__attribute__((weak));		 \
+		machine_id == &mach_##name; \
+	})
+
+extern void probe_machine(void);
+
 extern char cmd_line[COMMAND_LINE_SIZE];
 
 #ifdef CONFIG_PPC_PMAC
diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h
index 338e6a7..5b33994 100644
--- a/include/asm-powerpc/oprofile_impl.h
+++ b/include/asm-powerpc/oprofile_impl.h
@@ -17,9 +17,6 @@
 
 /* Per-counter configuration as set via oprofilefs.  */
 struct op_counter_config {
-#ifdef __powerpc64__
-	unsigned long valid;
-#endif
 	unsigned long enabled;
 	unsigned long event;
 	unsigned long count;
@@ -38,9 +35,6 @@
 #endif
 	unsigned long enable_kernel;
 	unsigned long enable_user;
-#ifdef CONFIG_PPC64
-	unsigned long backtrace_spinlocks;
-#endif
 };
 
 /* Per-arch configuration */
@@ -56,17 +50,12 @@
 	int num_counters;
 };
 
-#ifdef CONFIG_FSL_BOOKE
 extern struct op_powerpc_model op_model_fsl_booke;
-#else /* Otherwise, it's classic */
-
-#ifdef CONFIG_PPC64
 extern struct op_powerpc_model op_model_rs64;
 extern struct op_powerpc_model op_model_power4;
-
-#else /* Otherwise, CONFIG_PPC32 */
 extern struct op_powerpc_model op_model_7450;
-#endif
+
+#ifndef CONFIG_FSL_BOOKE
 
 /* All the classic PPC parts use these */
 static inline unsigned int ctr_read(unsigned int i)
@@ -134,5 +123,7 @@
 }
 #endif /* !CONFIG_FSL_BOOKE */
 
+extern void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth);
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_OPROFILE_IMPL_H */
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
index 4465b95..706325f 100644
--- a/include/asm-powerpc/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -105,5 +105,7 @@
 
 extern struct paca_struct paca[];
 
+void setup_boot_paca(void);
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PACA_H */
diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h
index 0b82df4..2fbeceb 100644
--- a/include/asm-powerpc/page.h
+++ b/include/asm-powerpc/page.h
@@ -69,8 +69,6 @@
 #endif
 
 #ifdef CONFIG_FLATMEM
-#define pfn_to_page(pfn)	(mem_map + (pfn))
-#define page_to_pfn(page)	((unsigned long)((page) - mem_map))
 #define pfn_valid(pfn)		((pfn) < max_mapnr)
 #endif
 
@@ -200,6 +198,7 @@
 		struct page *p);
 extern int page_is_ram(unsigned long pfn);
 
+#include <asm-generic/memory_model.h>
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/percpu.h b/include/asm-powerpc/percpu.h
index 464301c..184a7a4 100644
--- a/include/asm-powerpc/percpu.h
+++ b/include/asm-powerpc/percpu.h
@@ -27,7 +27,7 @@
 #define percpu_modcopy(pcpudst, src, size)			\
 do {								\
 	unsigned int __i;					\
-	for_each_cpu(__i)					\
+	for_each_possible_cpu(__i)				\
 		memcpy((pcpudst)+__per_cpu_offset(__i),		\
 		       (src), (size));				\
 } while (0)
diff --git a/include/asm-powerpc/pmac_feature.h b/include/asm-powerpc/pmac_feature.h
index 3221628..d3599cc 100644
--- a/include/asm-powerpc/pmac_feature.h
+++ b/include/asm-powerpc/pmac_feature.h
@@ -305,7 +305,7 @@
 extern void pmac_set_early_video_resume(void (*proc)(void *data), void *data);
 extern void pmac_call_early_video_resume(void);
 
-#define PMAC_FTR_DEF(x) ((_MACH_Pmac << 16) | (x))
+#define PMAC_FTR_DEF(x) ((0x6660000) | (x))
 
 /* The AGP driver registers itself here */
 extern void pmac_register_agp_pm(struct pci_dev *bridge,
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
index 1c64a21..93f83ef 100644
--- a/include/asm-powerpc/processor.h
+++ b/include/asm-powerpc/processor.h
@@ -22,22 +22,6 @@
  * -- BenH.
  */
 
-/* Platforms codes (to be obsoleted) */
-#define PLATFORM_PSERIES	0x0100
-#define PLATFORM_PSERIES_LPAR	0x0101
-#define PLATFORM_ISERIES_LPAR	0x0201
-#define PLATFORM_LPAR		0x0001
-#define PLATFORM_POWERMAC	0x0400
-#define PLATFORM_MAPLE		0x0500
-#define PLATFORM_PREP		0x0600
-#define PLATFORM_CHRP		0x0700
-#define PLATFORM_CELL		0x1000
-
-/* Compat platform codes for 32 bits */
-#define _MACH_prep	PLATFORM_PREP
-#define _MACH_Pmac	PLATFORM_POWERMAC
-#define _MACH_chrp	PLATFORM_CHRP
-
 /* PREP sub-platform types see residual.h for these */
 #define _PREP_Motorola	0x01	/* motorola prep */
 #define _PREP_Firm	0x02	/* firmworks prep */
@@ -49,18 +33,14 @@
 #define _CHRP_IBM	0x05	/* IBM chrp, the longtrail and longtrail 2 */
 #define _CHRP_Pegasos	0x06	/* Genesi/bplan's Pegasos and Pegasos2 */
 
-#ifdef __KERNEL__
-#define platform_is_pseries()	(_machine == PLATFORM_PSERIES || \
-				 _machine == PLATFORM_PSERIES_LPAR)
+#if defined(__KERNEL__) && defined(CONFIG_PPC32)
 
-#if defined(CONFIG_PPC_MULTIPLATFORM)
-extern int _machine;
+extern int _chrp_type;
 
-#ifdef CONFIG_PPC32
+#ifdef CONFIG_PPC_PREP
 
 /* what kind of prep workstation we are */
 extern int _prep_type;
-extern int _chrp_type;
 
 /*
  * This is used to identify the board type from a given PReP board
@@ -70,17 +50,14 @@
 extern unsigned char ucBoardRev;
 extern unsigned char ucBoardRevMaj, ucBoardRevMin;
 
-#endif /* CONFIG_PPC32 */
+#endif /* CONFIG_PPC_PREP */
 
-#elif defined(CONFIG_PPC_ISERIES)
-/*
- * iSeries is soon to become MULTIPLATFORM hopefully ...
- */
-#define _machine PLATFORM_ISERIES_LPAR
-#else
+#ifndef CONFIG_PPC_MULTIPLATFORM
 #define _machine 0
 #endif /* CONFIG_PPC_MULTIPLATFORM */
-#endif /* __KERNEL__ */
+
+#endif /* defined(__KERNEL__) && defined(CONFIG_PPC32) */
+
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
@@ -251,6 +228,10 @@
 #define cpu_relax()	barrier()
 #endif
 
+/* Check that a certain kernel stack pointer is valid in task_struct p */
+int validate_sp(unsigned long sp, struct task_struct *p,
+                       unsigned long nbytes);
+
 /*
  * Prefetch macros.
  */
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index 782e13a..97ef1cd 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -149,12 +149,14 @@
 extern void of_node_put(struct device_node *node);
 
 /* For scanning the flat device-tree at boot time */
-int __init of_scan_flat_dt(int (*it)(unsigned long node,
-				     const char *uname, int depth,
-				     void *data),
-			   void *data);
-void* __init of_get_flat_dt_prop(unsigned long node, const char *name,
-				 unsigned long *size);
+extern int __init of_scan_flat_dt(int (*it)(unsigned long node,
+					    const char *uname, int depth,
+					    void *data),
+				  void *data);
+extern void* __init of_get_flat_dt_prop(unsigned long node, const char *name,
+					unsigned long *size);
+extern int __init of_flat_dt_is_compatible(unsigned long node, const char *name);
+extern unsigned long __init of_get_flat_dt_root(void);
 
 /* For updating the device tree at runtime */
 extern void of_attach_node(struct device_node *);
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index 72bfe3a..bd467bf 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -622,6 +622,10 @@
 extern unsigned long scom970_read(unsigned int address);
 extern void scom970_write(unsigned int address, unsigned long value);
 
+#else
+#define ppc64_runlatch_on()
+#define ppc64_runlatch_off()
+
 #endif /* CONFIG_PPC64 */
 
 #define __get_SP()	({unsigned long sp; \
diff --git a/include/asm-powerpc/smp.h b/include/asm-powerpc/smp.h
index 98581e5..4a716f7 100644
--- a/include/asm-powerpc/smp.h
+++ b/include/asm-powerpc/smp.h
@@ -29,7 +29,6 @@
 #endif
 
 extern int boot_cpuid;
-extern int boot_cpuid_phys;
 
 extern void cpu_die(void);
 
@@ -99,6 +98,7 @@
 #else
 /* 32-bit */
 #ifndef CONFIG_SMP
+extern int boot_cpuid_phys;
 #define get_hard_smp_processor_id(cpu) 	boot_cpuid_phys
 #define set_hard_smp_processor_id(cpu, phys)
 #endif
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index 38bacf2..f431d8b0 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -110,6 +110,7 @@
 	char *name;
 	unsigned long local_store_phys;
 	u8 *local_store;
+	unsigned long problem_phys;
 	struct spu_problem __iomem *problem;
 	struct spu_priv1 __iomem *priv1;
 	struct spu_priv2 __iomem *priv2;
@@ -137,6 +138,7 @@
 	void (* wbox_callback)(struct spu *spu);
 	void (* ibox_callback)(struct spu *spu);
 	void (* stop_callback)(struct spu *spu);
+	void (* mfc_callback)(struct spu *spu);
 
 	char irq_c0[8];
 	char irq_c1[8];
@@ -149,6 +151,14 @@
 int spu_irq_class_1_bottom(struct spu *spu);
 void spu_irq_setaffinity(struct spu *spu, int cpu);
 
+/* system callbacks from the SPU */
+struct spu_syscall_block {
+	u64 nr_ret;
+	u64 parm[6];
+};
+extern long spu_sys_callback(struct spu_syscall_block *s);
+
+/* syscalls implemented in spufs */
 extern struct spufs_calls {
 	asmlinkage long (*create_thread)(const char __user *name,
 					unsigned int flags, mode_t mode);
@@ -399,7 +409,6 @@
 #define SPU_GET_REVISION_BITS(vr)	(vr & SPU_REVISION_BITS)
 	u8  pad_0x28_0x100[0x100 - 0x28];			/* 0x28 */
 
-
 	/* Interrupt Area */
 	u64 int_mask_RW[3];					/* 0x100 */
 #define CLASS0_ENABLE_DMA_ALIGNMENT_INTR		0x1L
diff --git a/include/asm-powerpc/syscalls.h b/include/asm-powerpc/syscalls.h
new file mode 100644
index 0000000..c2fe79d
--- /dev/null
+++ b/include/asm-powerpc/syscalls.h
@@ -0,0 +1,58 @@
+#ifndef __ASM_POWERPC_SYSCALLS_H
+#define __ASM_POWERPC_SYSCALLS_H
+#ifdef __KERNEL__
+
+#include <linux/compiler.h>
+#include <linux/linkage.h>
+#include <linux/types.h>
+#include <asm/signal.h>
+
+struct new_utsname;
+struct pt_regs;
+struct rtas_args;
+struct sigaction;
+
+asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
+		unsigned long prot, unsigned long flags,
+		unsigned long fd, off_t offset);
+asmlinkage unsigned long sys_mmap2(unsigned long addr, size_t len,
+		unsigned long prot, unsigned long flags,
+		unsigned long fd, unsigned long pgoff);
+asmlinkage int sys_execve(unsigned long a0, unsigned long a1,
+		unsigned long a2, unsigned long a3, unsigned long a4,
+		unsigned long a5, struct pt_regs *regs);
+asmlinkage int sys_clone(unsigned long clone_flags, unsigned long usp,
+		int __user *parent_tidp, void __user *child_threadptr,
+		int __user *child_tidp, int p6, struct pt_regs *regs);
+asmlinkage int sys_fork(unsigned long p1, unsigned long p2,
+		unsigned long p3, unsigned long p4, unsigned long p5,
+		unsigned long p6, struct pt_regs *regs);
+asmlinkage int sys_vfork(unsigned long p1, unsigned long p2,
+		unsigned long p3, unsigned long p4, unsigned long p5,
+		unsigned long p6, struct pt_regs *regs);
+asmlinkage int sys_pipe(int __user *fildes);
+asmlinkage long sys_rt_sigaction(int sig,
+		const struct sigaction __user *act,
+		struct sigaction __user *oact, size_t sigsetsize);
+asmlinkage int sys_ipc(uint call, int first, unsigned long second,
+		long third, void __user *ptr, long fifth);
+asmlinkage long ppc64_personality(unsigned long personality);
+asmlinkage int ppc_rtas(struct rtas_args __user *uargs);
+asmlinkage time_t sys64_time(time_t __user * tloc);
+asmlinkage long ppc_newuname(struct new_utsname __user * name);
+
+asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset,
+		size_t sigsetsize);
+
+#ifndef __powerpc64__
+asmlinkage long sys_sigaltstack(const stack_t __user *uss,
+		stack_t __user *uoss, int r5, int r6, int r7, int r8,
+		struct pt_regs *regs);
+#else /* __powerpc64__ */
+asmlinkage long sys_sigaltstack(const stack_t __user *uss,
+		stack_t __user *uoss, unsigned long r5, unsigned long r6,
+		unsigned long r7, unsigned long r8, struct pt_regs *regs);
+#endif /* __powerpc64__ */
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_POWERPC_SYSCALLS_H */
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index 65f5a7b..d075725 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -365,8 +365,11 @@
  * powers of 2 writes until it reaches sufficient alignment).
  *
  * Based on this we disable the IP header alignment in network drivers.
+ * We also modify NET_SKB_PAD to be a cacheline in size, thus maintaining
+ * cacheline alignment of buffers.
  */
-#define NET_IP_ALIGN   0
+#define NET_IP_ALIGN	0
+#define NET_SKB_PAD	L1_CACHE_BYTES
 #endif
 
 #define arch_align_stack(x) (x)
diff --git a/include/asm-powerpc/types.h b/include/asm-powerpc/types.h
index ec3c2ee..baabba9 100644
--- a/include/asm-powerpc/types.h
+++ b/include/asm-powerpc/types.h
@@ -103,6 +103,11 @@
 #define HAVE_SECTOR_T
 #endif
 
+#ifdef CONFIG_LSF
+typedef u64 blkcnt_t;
+#define HAVE_BLKCNT_T
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index 3555699..536ba08 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -301,8 +301,9 @@
 #define __NR_pselect6		280
 #define __NR_ppoll		281
 #define __NR_unshare		282
+#define __NR_splice		283
 
-#define __NR_syscalls		283
+#define __NR_syscalls		284
 
 #ifdef __KERNEL__
 #define __NR__exit __NR_exit
@@ -425,6 +426,7 @@
 #include <linux/types.h>
 #include <linux/compiler.h>
 #include <linux/linkage.h>
+#include <asm/syscalls.h>
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
@@ -460,44 +462,10 @@
  * System call prototypes.
  */
 #ifdef __KERNEL_SYSCALLS__
-extern pid_t setsid(void);
-extern int write(int fd, const char *buf, off_t count);
-extern int read(int fd, char *buf, off_t count);
-extern off_t lseek(int fd, off_t offset, int count);
-extern int dup(int fd);
 extern int execve(const char *file, char **argv, char **envp);
-extern int open(const char *file, int flag, int mode);
-extern int close(int fd);
-extern pid_t waitpid(pid_t pid, int *wait_stat, int options);
 #endif /* __KERNEL_SYSCALLS__ */
 
 /*
- * Functions that implement syscalls.
- */
-unsigned long sys_mmap(unsigned long addr, size_t len, unsigned long prot,
-		       unsigned long flags, unsigned long fd, off_t offset);
-unsigned long sys_mmap2(unsigned long addr, size_t len,
-			unsigned long prot, unsigned long flags,
-			unsigned long fd, unsigned long pgoff);
-struct pt_regs;
-int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
-		unsigned long a3, unsigned long a4, unsigned long a5,
-		struct pt_regs *regs);
-int sys_clone(unsigned long clone_flags, unsigned long usp,
-		int __user *parent_tidp, void __user *child_threadptr,
-		int __user *child_tidp, int p6, struct pt_regs *regs);
-int sys_fork(unsigned long p1, unsigned long p2, unsigned long p3,
-		unsigned long p4, unsigned long p5, unsigned long p6,
-		struct pt_regs *regs);
-int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3,
-		unsigned long p4, unsigned long p5, unsigned long p6,
-		struct pt_regs *regs);
-int sys_pipe(int __user *fildes);
-struct sigaction;
-long sys_rt_sigaction(int sig, const struct sigaction __user *act,
-		      struct sigaction __user *oact, size_t sigsetsize);
-
-/*
  * "Conditional" syscalls
  *
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
diff --git a/include/asm-powerpc/vdso_datapage.h b/include/asm-powerpc/vdso_datapage.h
index 7aa9208..8a94f0e 100644
--- a/include/asm-powerpc/vdso_datapage.h
+++ b/include/asm-powerpc/vdso_datapage.h
@@ -55,6 +55,9 @@
 		__u32 minor;		/* Minor number			0x14 */
 	} version;
 
+	/* Note about the platform flags: it now only contains the lpar
+	 * bit. The actual platform number is dead and burried
+	 */
 	__u32 platform;			/* Platform flags		0x18 */
 	__u32 processor;		/* Processor type		0x1C */
 	__u64 processorCount;		/* # of physical processors	0x20 */
diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
index a3e8a45..e1a0a7b 100644
--- a/include/asm-ppc/machdep.h
+++ b/include/asm-ppc/machdep.h
@@ -19,6 +19,18 @@
 struct seq_file;
 struct file;
 
+/*
+ * This is for compatibility with ARCH=powerpc.
+ */
+#define machine_is(x)	__MACHINE_IS_##x
+#define __MACHINE_IS_powermac	0
+#define __MACHINE_IS_chrp	0
+#ifdef CONFIG_PPC_PREP
+#define __MACHINE_IS_prep	1
+#else
+#define __MACHINE_IS_prep	0
+#endif
+
 /* We export this macro for external modules like Alsa to know if
  * ppc_md.feature_call is implemented or not
  */
@@ -44,7 +56,7 @@
 	void		(*power_off)(void);
 	void		(*halt)(void);
 
-	void		(*idle)(void);
+	void		(*idle_loop)(void);
 	void		(*power_save)(void);
 
 	long		(*time_init)(void); /* Optional, may be NULL */
@@ -104,9 +116,6 @@
 						unsigned long size,
 						pgprot_t vma_prot);
 
-	/* this is for modules, since _machine can be a define -- Cort */
-	int ppc_machine;
-
 	/* Motherboard/chipset features. This is a kind of general purpose
 	 * hook used to control some machine specific features (like reset
 	 * lines, chip power control, etc...).
diff --git a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h
index 6167f74..7e98428 100644
--- a/include/asm-ppc/mpc52xx.h
+++ b/include/asm-ppc/mpc52xx.h
@@ -355,6 +355,7 @@
 	u32	snoop_window;		/* XLB + 0x70 */
 };
 
+#define MPC52xx_XLB_CFG_PLDIS		(1 << 31)
 #define MPC52xx_XLB_CFG_SNOOP		(1 << 15)
 
 /* Clock Distribution control */
@@ -427,6 +428,9 @@
 
 extern void mpc52xx_find_bridges(void);
 
+extern void mpc52xx_setup_cpu(void);
+
+
 
 	/* Matching of PSC function */
 struct mpc52xx_psc_func {
diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h
index 538e0c8..a70ba2e 100644
--- a/include/asm-ppc/page.h
+++ b/include/asm-ppc/page.h
@@ -149,8 +149,7 @@
 #define __pa(x) ___pa((unsigned long)(x))
 #define __va(x) ((void *)(___va((unsigned long)(x))))
 
-#define pfn_to_page(pfn)	(mem_map + ((pfn) - PPC_PGSTART))
-#define page_to_pfn(page)	((unsigned long)((page) - mem_map) + PPC_PGSTART)
+#define ARCH_PFN_OFFSET		(PPC_PGSTART)
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 #define page_to_virt(page)	__va(page_to_pfn(page) << PAGE_SHIFT)
 
@@ -175,5 +174,6 @@
 /* We do define AT_SYSINFO_EHDR but don't use the gate mecanism */
 #define __HAVE_ARCH_GATE_AREA		1
 
+#include <asm-generic/memory_model.h>
 #endif /* __KERNEL__ */
 #endif /* _PPC_PAGE_H */
diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
index e1c62da..570b355 100644
--- a/include/asm-ppc/pgtable.h
+++ b/include/asm-ppc/pgtable.h
@@ -837,7 +837,8 @@
  */
 #define pgtable_cache_init()	do { } while (0)
 
-extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep);
+extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep,
+		      pmd_t **pmdp);
 
 #include <asm-generic/pgtable.h>
 
diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
index 6d431d6..adc5ae7 100644
--- a/include/asm-ppc/prom.h
+++ b/include/asm-ppc/prom.h
@@ -8,126 +8,19 @@
 #ifndef _PPC_PROM_H
 #define _PPC_PROM_H
 
-#include <linux/config.h>
-#include <linux/types.h>
-
-typedef u32 phandle;
-typedef u32 ihandle;
-
-struct address_range {
-	unsigned int space;
-	unsigned int address;
-	unsigned int size;
-};
-
-struct interrupt_info {
-	int	line;
-	int	sense;		/* +ve/-ve logic, edge or level, etc. */
-};
-
+/* This is used in arch/ppc/mm/mem_pieces.h */
 struct reg_property {
 	unsigned int address;
 	unsigned int size;
 };
 
-struct property {
-	char	*name;
-	int	length;
-	unsigned char *value;
-	struct property *next;
-};
-
 /*
- * Note: don't change this structure for now or you'll break BootX !
- */
-struct device_node {
-	char	*name;
-	char	*type;
-	phandle	node;
-	int	n_addrs;
-	struct	address_range *addrs;
-	int	n_intrs;
-	struct	interrupt_info *intrs;
-	char	*full_name;
-	struct	property *properties;
-	struct	device_node *parent;
-	struct	device_node *child;
-	struct	device_node *sibling;
-	struct	device_node *next;	/* next device of same type */
-	struct	device_node *allnext;	/* next in list of all nodes */
-};
-
-struct prom_args;
-typedef void (*prom_entry)(struct prom_args *);
-
-/* OBSOLETE: Old style node lookup */
-extern struct device_node *find_devices(const char *name);
-extern struct device_node *find_type_devices(const char *type);
-extern struct device_node *find_path_device(const char *path);
-extern struct device_node *find_compatible_devices(const char *type,
-						   const char *compat);
-extern struct device_node *find_all_nodes(void);
-
-/* New style node lookup */
-extern struct device_node *of_find_node_by_name(struct device_node *from,
-	const char *name);
-extern struct device_node *of_find_node_by_type(struct device_node *from,
-	const char *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_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 device_node *of_node_get(struct device_node *node);
-extern void of_node_put(struct device_node *node);
-
-/* Other Prototypes */
-extern void abort(void);
-extern unsigned long prom_init(int, int, prom_entry);
-extern void prom_print(const char *msg);
-extern void relocate_nodes(void);
-extern void finish_device_tree(void);
-extern int device_is_compatible(struct device_node *device, const char *);
-extern int machine_is_compatible(const char *compat);
-extern unsigned char *get_property(struct device_node *node, const char *name,
-				   int *lenp);
-extern int prom_add_property(struct device_node* np, struct property* prop);
-extern void prom_get_irq_senses(unsigned char *, int, int);
-extern int prom_n_addr_cells(struct device_node* np);
-extern int prom_n_size_cells(struct device_node* np);
-
-extern struct resource*
-request_OF_resource(struct device_node* node, int index, const char* name_postfix);
-extern int release_OF_resource(struct device_node* node, int index);
-
-extern void print_properties(struct device_node *node);
-extern int call_rtas(const char *service, int nargs, int nret,
-		     unsigned long *outputs, ...);
-
-/*
- * PCI <-> OF matching functions
- */
-struct pci_bus;
-struct pci_dev;
-extern int pci_device_from_OF_node(struct device_node *node,
-				   u8* bus, u8* devfn);
-extern struct device_node* pci_busdev_to_OF_node(struct pci_bus *, int);
-extern struct device_node* pci_device_to_OF_node(struct pci_dev *);
-extern void pci_create_OF_bus_map(void);
-
-/*
- * When we call back to the Open Firmware client interface, we usually
- * have to do that before the kernel is relocated to its final location
- * (this is because we can't use OF after we have overwritten the
- * exception vectors with our exception handlers).  These macros assist
- * in performing the address calculations that we need to do to access
- * data when the kernel is running at an address that is different from
- * the address that the kernel is linked at.  The reloc_offset() function
- * returns the difference between these two addresses and the macros
- * simplify the process of adding or subtracting this offset to/from
- * pointer values.  See arch/ppc/kernel/prom.c for how these are used.
+ * These macros assist in performing the address calculations that we
+ * need to do to access data when the kernel is running at an address
+ * that is different from the address that the kernel is linked at.
+ * The reloc_offset() function returns the difference between these
+ * two addresses and the macros simplify the process of adding or
+ * subtracting this offset to/from pointer values.
  */
 extern unsigned long reloc_offset(void);
 extern unsigned long add_reloc_offset(unsigned long);
@@ -136,45 +29,12 @@
 #define PTRRELOC(x)	((typeof(x))add_reloc_offset((unsigned long)(x)))
 #define PTRUNRELOC(x)	((typeof(x))sub_reloc_offset((unsigned long)(x)))
 
-
 /*
- * OF address retreival & translation
- */
-
-
-/* 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, u32 *addr);
-
-/* Extract an address from a device, returns the region size and
- * the address space flags too. The PCI version uses a BAR number
- * instead of an absolute index
- */
-extern u32 *of_get_address(struct device_node *dev, int index,
-			   u64 *size, unsigned int *flags);
-extern u32 *of_get_pci_address(struct device_node *dev, int bar_no,
-			       u64 *size, unsigned int *flags);
-
-/* Get an address as a resource. Note that if your address is
- * a PIO address, the conversion will fail if the physical address
- * can't be internally converted to an IO token with
- * pci_address_to_pio(), that is because it's either called to early
- * or it can't be matched to any host bridge IO space
- */
-extern int of_address_to_resource(struct device_node *dev, int index,
-				  struct resource *r);
-extern int of_pci_address_to_resource(struct device_node *dev, int bar,
-				      struct resource *r);
-
-#ifndef CONFIG_PPC_OF
-/*
- * Fallback definitions for builds where we don't have prom.c included.
+ * Fallback definitions since we don't support OF in arch/ppc any more.
  */
 #define machine_is_compatible(x)		0
 #define of_find_compatible_node(f, t, c)	NULL
 #define get_property(p, n, l)			NULL
-#endif
 
 #endif /* _PPC_PROM_H */
 #endif /* __KERNEL__ */
diff --git a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h
index 485a924..b74af54 100644
--- a/include/asm-ppc/serial.h
+++ b/include/asm-ppc/serial.h
@@ -41,15 +41,10 @@
 #else
 
 /*
- * XXX Assume for now it has PC-style ISA serial ports.
- * This is true for PReP and CHRP at least.
+ * XXX Assume it has PC-style ISA serial ports - true for PReP at least.
  */
 #include <asm/pc_serial.h>
 
-#if defined(CONFIG_MAC_SERIAL)
-#define SERIAL_DEV_OFFSET	((_machine == _MACH_prep || _machine == _MACH_chrp) ? 0 : 2)
-#endif
-
 #endif /* !CONFIG_GEMINI and others */
 #endif /* __ASM_SERIAL_H__ */
 #endif /* __KERNEL__ */
diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h
index 3628899..ca092ff 100644
--- a/include/asm-s390/bitops.h
+++ b/include/asm-s390/bitops.h
@@ -828,35 +828,12 @@
 	return find_first_bit(b, 140);
 }
 
-/*
- * ffs: find first bit set. This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
- */
-#define ffs(x) generic_ffs(x)
+#include <asm-generic/bitops/ffs.h>
 
-/*
- * fls: find last bit set.
- */
-#define fls(x) generic_fls(x)
-#define fls64(x)   generic_fls64(x)
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
 
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-#define hweight64(x)						\
-({								\
-	unsigned long __x = (x);				\
-	unsigned int __w;					\
-	__w = generic_hweight32((unsigned int) __x);		\
-	__w += generic_hweight32((unsigned int) (__x>>32));	\
-	__w;							\
-})
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
-
+#include <asm-generic/bitops/hweight.h>
 
 #ifdef __KERNEL__
 
@@ -871,11 +848,11 @@
  */
 
 #define ext2_set_bit(nr, addr)       \
-	test_and_set_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
+	__test_and_set_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
 #define ext2_set_bit_atomic(lock, nr, addr)       \
 	test_and_set_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
 #define ext2_clear_bit(nr, addr)     \
-	test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
+	__test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
 #define ext2_clear_bit_atomic(lock, nr, addr)     \
 	test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
 #define ext2_test_bit(nr, addr)      \
@@ -1011,18 +988,7 @@
 	return offset + ext2_find_first_zero_bit(p, size);
 }
 
-/* Bitmap functions for the minix filesystem.  */
-/* FIXME !!! */
-#define minix_test_and_set_bit(nr,addr) \
-	test_and_set_bit(nr,(unsigned long *)addr)
-#define minix_set_bit(nr,addr) \
-	set_bit(nr,(unsigned long *)addr)
-#define minix_test_and_clear_bit(nr,addr) \
-	test_and_clear_bit(nr,(unsigned long *)addr)
-#define minix_test_bit(nr,addr) \
-	test_bit(nr,(unsigned long *)addr)
-#define minix_find_first_zero_bit(addr,size) \
-	find_first_zero_bit(addr,size)
+#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-s390/compat.h b/include/asm-s390/compat.h
index a007715..356a0b1 100644
--- a/include/asm-s390/compat.h
+++ b/include/asm-s390/compat.h
@@ -128,6 +128,11 @@
 	return (void __user *)(unsigned long)(uptr & 0x7fffffffUL);
 }
 
+static inline compat_uptr_t ptr_to_compat(void __user *uptr)
+{
+	return (u32)(unsigned long)uptr;
+}
+
 static inline void __user *compat_alloc_user_space(long len)
 {
 	unsigned long stack;
diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h
index 2430c56..3b1138a 100644
--- a/include/asm-s390/page.h
+++ b/include/asm-s390/page.h
@@ -181,8 +181,6 @@
 #define PAGE_OFFSET             0x0UL
 #define __pa(x)                 (unsigned long)(x)
 #define __va(x)                 (void *)(unsigned long)(x)
-#define pfn_to_page(pfn)	(mem_map + (pfn))
-#define page_to_pfn(page)	((unsigned long)((page) - mem_map))
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 
 #define pfn_valid(pfn)		((pfn) < max_mapnr)
@@ -193,6 +191,7 @@
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* _S390_PAGE_H */
diff --git a/include/asm-s390/percpu.h b/include/asm-s390/percpu.h
index e10ed87..436d216 100644
--- a/include/asm-s390/percpu.h
+++ b/include/asm-s390/percpu.h
@@ -46,7 +46,7 @@
 #define percpu_modcopy(pcpudst, src, size)			\
 do {								\
 	unsigned int __i;					\
-	for_each_cpu(__i)					\
+	for_each_possible_cpu(__i)				\
 		memcpy((pcpudst)+__per_cpu_offset[__i],		\
 		       (src), (size));				\
 } while (0)
diff --git a/include/asm-s390/types.h b/include/asm-s390/types.h
index d0be3e4..5738ad63 100644
--- a/include/asm-s390/types.h
+++ b/include/asm-s390/types.h
@@ -93,6 +93,11 @@
 #define HAVE_SECTOR_T
 #endif
 
+#ifdef CONFIG_LSF
+typedef u64 blkcnt_t;
+#define HAVE_BLKCNT_T
+#endif
+
 #endif /* ! __s390x__   */
 #endif /* __ASSEMBLY__  */
 #endif /* __KERNEL__    */
diff --git a/include/asm-sh/addrspace.h b/include/asm-sh/addrspace.h
index dbb05d1..720afc1 100644
--- a/include/asm-sh/addrspace.h
+++ b/include/asm-sh/addrspace.h
@@ -13,7 +13,7 @@
 
 #include <asm/cpu/addrspace.h>
 
-/* Memory segments (32bit Priviledged mode addresses)  */
+/* Memory segments (32bit Privileged mode addresses)  */
 #define P0SEG		0x00000000
 #define P1SEG		0x80000000
 #define P2SEG		0xa0000000
diff --git a/include/asm-sh/bitops.h b/include/asm-sh/bitops.h
index 1c52608..e34f825 100644
--- a/include/asm-sh/bitops.h
+++ b/include/asm-sh/bitops.h
@@ -19,16 +19,6 @@
 	local_irq_restore(flags);
 }
 
-static __inline__ void __set_bit(int nr, volatile void * addr)
-{
-	int	mask;
-	volatile unsigned int *a = addr;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	*a |= mask;
-}
-
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
  */
@@ -47,16 +37,6 @@
 	local_irq_restore(flags);
 }
 
-static __inline__ void __clear_bit(int nr, volatile void * addr)
-{
-	int	mask;
-	volatile unsigned int *a = addr;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	*a &= ~mask;
-}
-
 static __inline__ void change_bit(int nr, volatile void * addr)
 {
 	int	mask;
@@ -70,16 +50,6 @@
 	local_irq_restore(flags);
 }
 
-static __inline__ void __change_bit(int nr, volatile void * addr)
-{
-	int	mask;
-	volatile unsigned int *a = addr;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	*a ^= mask;
-}
-
 static __inline__ int test_and_set_bit(int nr, volatile void * addr)
 {
 	int	mask, retval;
@@ -96,19 +66,6 @@
 	return retval;
 }
 
-static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
-{
-	int	mask, retval;
-	volatile unsigned int *a = addr;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	retval = (mask & *a) != 0;
-	*a |= mask;
-
-	return retval;
-}
-
 static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
 {
 	int	mask, retval;
@@ -125,19 +82,6 @@
 	return retval;
 }
 
-static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
-{
-	int	mask, retval;
-	volatile unsigned int *a = addr;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	retval = (mask & *a) != 0;
-	*a &= ~mask;
-
-	return retval;
-}
-
 static __inline__ int test_and_change_bit(int nr, volatile void * addr)
 {
 	int	mask, retval;
@@ -154,23 +98,7 @@
 	return retval;
 }
 
-static __inline__ int __test_and_change_bit(int nr, volatile void * addr)
-{
-	int	mask, retval;
-	volatile unsigned int *a = addr;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	retval = (mask & *a) != 0;
-	*a ^= mask;
-
-	return retval;
-}
-
-static __inline__ int test_bit(int nr, const volatile void *addr)
-{
-	return 1UL & (((const volatile unsigned int *) addr)[nr >> 5] >> (nr & 31));
-}
+#include <asm-generic/bitops/non-atomic.h>
 
 static __inline__ unsigned long ffz(unsigned long word)
 {
@@ -206,271 +134,15 @@
 	return result;
 }
 
-/**
- * find_next_bit - find the next set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-static __inline__ unsigned long find_next_bit(const unsigned long *addr,
-	unsigned long size, unsigned long offset)
-{
-	unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
-	unsigned int result = offset & ~31UL;
-	unsigned int tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *p++;
-		tmp &= ~0UL << offset;
-		if (size < 32)
-			goto found_first;
-		if (tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size >= 32) {
-		if ((tmp = *p++) != 0)
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp &= ~0UL >> (32 - size);
-	if (tmp == 0UL)        /* Are any bits set? */
-		return result + size; /* Nope. */
-found_middle:
-	return result + __ffs(tmp);
-}
-
-/**
- * find_first_bit - find the first set bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first set bit, not the number of the byte
- * containing a bit.
- */
-#define find_first_bit(addr, size) \
-	find_next_bit((addr), (size), 0)
-
-static __inline__ int find_next_zero_bit(const unsigned long *addr, int size, int offset)
-{
-	const unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (32-offset);
-		if (size < 32)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size & ~31UL) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp |= ~0UL << size;
-found_middle:
-	return result + ffz(tmp);
-}
-
-#define find_first_zero_bit(addr, size) \
-        find_next_zero_bit((addr), (size), 0)
-
-/*
- * ffs: find first bit set. This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
- */
-
-#define ffs(x) generic_ffs(x)
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
-
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-
-static inline int sched_find_first_bit(const unsigned long *b)
-{
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-}
-
-#ifdef __LITTLE_ENDIAN__
-#define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr))
-#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr), (addr))
-#define ext2_test_bit(nr, addr) test_bit((nr), (addr))
-#define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size))
-#define ext2_find_next_zero_bit(addr, size, offset) \
-                find_next_zero_bit((unsigned long *)(addr), (size), (offset))
-#else
-static __inline__ int ext2_set_bit(int nr, volatile void * addr)
-{
-	int		mask, retval;
-	unsigned long	flags;
-	volatile unsigned char	*ADDR = (unsigned char *) addr;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	local_irq_save(flags);
-	retval = (mask & *ADDR) != 0;
-	*ADDR |= mask;
-	local_irq_restore(flags);
-	return retval;
-}
-
-static __inline__ int ext2_clear_bit(int nr, volatile void * addr)
-{
-	int		mask, retval;
-	unsigned long	flags;
-	volatile unsigned char	*ADDR = (unsigned char *) addr;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	local_irq_save(flags);
-	retval = (mask & *ADDR) != 0;
-	*ADDR &= ~mask;
-	local_irq_restore(flags);
-	return retval;
-}
-
-static __inline__ int ext2_test_bit(int nr, const volatile void * addr)
-{
-	int			mask;
-	const volatile unsigned char	*ADDR = (const unsigned char *) addr;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	return ((mask & *ADDR) != 0);
-}
-
-#define ext2_find_first_zero_bit(addr, size) \
-        ext2_find_next_zero_bit((addr), (size), 0)
-
-static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
-{
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if(offset) {
-		/* We hold the little endian value in tmp, but then the
-		 * shift is illegal. So we could keep a big endian value
-		 * in tmp, like this:
-		 *
-		 * tmp = __swab32(*(p++));
-		 * tmp |= ~0UL >> (32-offset);
-		 *
-		 * but this would decrease preformance, so we change the
-		 * shift:
-		 */
-		tmp = *(p++);
-		tmp |= __swab32(~0UL >> (32-offset));
-		if(size < 32)
-			goto found_first;
-		if(~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while(size & ~31UL) {
-		if(~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if(!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	/* tmp is little endian, so we would have to swab the shift,
-	 * see above. But then we have to swab tmp below for ffz, so
-	 * we might as well do this here.
-	 */
-	return result + ffz(__swab32(tmp) | (~0UL << size));
-found_middle:
-	return result + ffz(__swab32(tmp));
-}
-#endif
-
-#define ext2_set_bit_atomic(lock, nr, addr)		\
-	({						\
-		int ret;				\
-		spin_lock(lock);			\
-		ret = ext2_set_bit((nr), (addr));	\
-		spin_unlock(lock);			\
-		ret;					\
-	})
-
-#define ext2_clear_bit_atomic(lock, nr, addr)		\
-	({						\
-		int ret;				\
-		spin_lock(lock);			\
-		ret = ext2_clear_bit((nr), (addr));	\
-		spin_unlock(lock);			\
-		ret;					\
-	})
-
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr) test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
-
-/*
- * fls: find last bit set.
- */
-
-#define fls(x) generic_fls(x)
-#define fls64(x)   generic_fls64(x)
+#include <asm-generic/bitops/find.h>
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/ext2-atomic.h>
+#include <asm-generic/bitops/minix.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h
index 972c3f6..9c89287 100644
--- a/include/asm-sh/page.h
+++ b/include/asm-sh/page.h
@@ -105,9 +105,7 @@
 
 /* PFN start number, because of __MEMORY_START */
 #define PFN_START		(__MEMORY_START >> PAGE_SHIFT)
-
-#define pfn_to_page(pfn)	(mem_map + (pfn) - PFN_START)
-#define page_to_pfn(page)	((unsigned long)((page) - mem_map) + PFN_START)
+#define ARCH_PFN_OFFSET		(FPN_START)
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 #define pfn_valid(pfn)		(((pfn) - PFN_START) < max_mapnr)
 #define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
@@ -117,6 +115,7 @@
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* __ASM_SH_PAGE_H */
diff --git a/include/asm-sh/stat.h b/include/asm-sh/stat.h
index 914e3fc..6c41a60 100644
--- a/include/asm-sh/stat.h
+++ b/include/asm-sh/stat.h
@@ -60,13 +60,7 @@
 	long long	st_size;
 	unsigned long	st_blksize;
 
-#if defined(__BIG_ENDIAN__)
-	unsigned long	__pad4;		/* Future possible st_blocks hi bits */
-	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
-#else /* Must be little */
-	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
-	unsigned long	__pad4;		/* Future possible st_blocks hi bits */
-#endif
+	unsigned long long	st_blocks;	/* Number 512-byte blocks allocated. */
 
 	unsigned long	st_atime;
 	unsigned long	st_atime_nsec;
diff --git a/include/asm-sh/thread_info.h b/include/asm-sh/thread_info.h
index 85f0c11..7345350 100644
--- a/include/asm-sh/thread_info.h
+++ b/include/asm-sh/thread_info.h
@@ -18,7 +18,7 @@
 struct thread_info {
 	struct task_struct	*task;		/* main task structure */
 	struct exec_domain	*exec_domain;	/* execution domain */
-	__u32			flags;		/* low level flags */
+	unsigned long		flags;		/* low level flags */
 	__u32			cpu;
 	int			preempt_count; /* 0 => preemptable, <0 => BUG */
 	struct restart_block	restart_block;
diff --git a/include/asm-sh/types.h b/include/asm-sh/types.h
index cb7e183..488552f 100644
--- a/include/asm-sh/types.h
+++ b/include/asm-sh/types.h
@@ -58,6 +58,11 @@
 #define HAVE_SECTOR_T
 #endif
 
+#ifdef CONFIG_LSF
+typedef u64 blkcnt_t;
+#define HAVE_BLKCNT_T
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-sh64/bitops.h b/include/asm-sh64/bitops.h
index ce9c3ad..f3bdcdb 100644
--- a/include/asm-sh64/bitops.h
+++ b/include/asm-sh64/bitops.h
@@ -31,16 +31,6 @@
 	local_irq_restore(flags);
 }
 
-static inline void __set_bit(int nr, void *addr)
-{
-	int	mask;
-	unsigned int *a = addr;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	*a |= mask;
-}
-
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
  */
@@ -58,15 +48,6 @@
 	local_irq_restore(flags);
 }
 
-static inline void __clear_bit(int nr, volatile unsigned long *a)
-{
-	int	mask;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	*a &= ~mask;
-}
-
 static __inline__ void change_bit(int nr, volatile void * addr)
 {
 	int	mask;
@@ -80,16 +61,6 @@
 	local_irq_restore(flags);
 }
 
-static __inline__ void __change_bit(int nr, volatile void * addr)
-{
-	int	mask;
-	volatile unsigned int *a = addr;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	*a ^= mask;
-}
-
 static __inline__ int test_and_set_bit(int nr, volatile void * addr)
 {
 	int	mask, retval;
@@ -106,19 +77,6 @@
 	return retval;
 }
 
-static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
-{
-	int	mask, retval;
-	volatile unsigned int *a = addr;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	retval = (mask & *a) != 0;
-	*a |= mask;
-
-	return retval;
-}
-
 static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
 {
 	int	mask, retval;
@@ -135,19 +93,6 @@
 	return retval;
 }
 
-static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
-{
-	int	mask, retval;
-	volatile unsigned int *a = addr;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	retval = (mask & *a) != 0;
-	*a &= ~mask;
-
-	return retval;
-}
-
 static __inline__ int test_and_change_bit(int nr, volatile void * addr)
 {
 	int	mask, retval;
@@ -164,23 +109,7 @@
 	return retval;
 }
 
-static __inline__ int __test_and_change_bit(int nr, volatile void * addr)
-{
-	int	mask, retval;
-	volatile unsigned int *a = addr;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	retval = (mask & *a) != 0;
-	*a ^= mask;
-
-	return retval;
-}
-
-static __inline__ int test_bit(int nr, const volatile void *addr)
-{
-	return 1UL & (((const volatile unsigned int *) addr)[nr >> 5] >> (nr & 31));
-}
+#include <asm-generic/bitops/non-atomic.h>
 
 static __inline__ unsigned long ffz(unsigned long word)
 {
@@ -204,313 +133,16 @@
 	return result;
 }
 
-/**
- * __ffs - find first bit in word
- * @word: The word to search
- *
- * Undefined if no bit exists, so code should check against 0 first.
- */
-static inline unsigned long __ffs(unsigned long word)
-{
-	int r = 0;
-
-	if (!word)
-		return 0;
-	if (!(word & 0xffff)) {
-		word >>= 16;
-		r += 16;
-	}
-	if (!(word & 0xff)) {
-		word >>= 8;
-		r += 8;
-	}
-	if (!(word & 0xf)) {
-		word >>= 4;
-		r += 4;
-	}
-	if (!(word & 3)) {
-		word >>= 2;
-		r += 2;
-	}
-	if (!(word & 1)) {
-		word >>= 1;
-		r += 1;
-	}
-	return r;
-}
-
-/**
- * find_next_bit - find the next set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-static inline unsigned long find_next_bit(const unsigned long *addr,
-	unsigned long size, unsigned long offset)
-{
-	unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
-	unsigned int result = offset & ~31UL;
-	unsigned int tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *p++;
-		tmp &= ~0UL << offset;
-		if (size < 32)
-			goto found_first;
-		if (tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size >= 32) {
-		if ((tmp = *p++) != 0)
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp &= ~0UL >> (32 - size);
-	if (tmp == 0UL)        /* Are any bits set? */
-		return result + size; /* Nope. */
-found_middle:
-	return result + __ffs(tmp);
-}
-
-/**
- * find_first_bit - find the first set bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first set bit, not the number of the byte
- * containing a bit.
- */
-#define find_first_bit(addr, size) \
-	find_next_bit((addr), (size), 0)
-
-
-static inline int find_next_zero_bit(void *addr, int size, int offset)
-{
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (32-offset);
-		if (size < 32)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size & ~31UL) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp |= ~0UL << size;
-found_middle:
-	return result + ffz(tmp);
-}
-
-#define find_first_zero_bit(addr, size) \
-        find_next_zero_bit((addr), (size), 0)
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#define hweight32(x)	generic_hweight32(x)
-#define hweight16(x)	generic_hweight16(x)
-#define hweight8(x)	generic_hweight8(x)
-
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-
-static inline int sched_find_first_bit(unsigned long *b)
-{
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-}
-
-/*
- * ffs: find first bit set. This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
- */
-
-#define ffs(x) generic_ffs(x)
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
-
-#ifdef __LITTLE_ENDIAN__
-#define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr))
-#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr), (addr))
-#define ext2_test_bit(nr, addr) test_bit((nr), (addr))
-#define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size))
-#define ext2_find_next_zero_bit(addr, size, offset) \
-                find_next_zero_bit((addr), (size), (offset))
-#else
-static __inline__ int ext2_set_bit(int nr, volatile void * addr)
-{
-	int		mask, retval;
-	unsigned long	flags;
-	volatile unsigned char	*ADDR = (unsigned char *) addr;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	local_irq_save(flags);
-	retval = (mask & *ADDR) != 0;
-	*ADDR |= mask;
-	local_irq_restore(flags);
-	return retval;
-}
-
-static __inline__ int ext2_clear_bit(int nr, volatile void * addr)
-{
-	int		mask, retval;
-	unsigned long	flags;
-	volatile unsigned char	*ADDR = (unsigned char *) addr;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	local_irq_save(flags);
-	retval = (mask & *ADDR) != 0;
-	*ADDR &= ~mask;
-	local_irq_restore(flags);
-	return retval;
-}
-
-static __inline__ int ext2_test_bit(int nr, const volatile void * addr)
-{
-	int			mask;
-	const volatile unsigned char	*ADDR = (const unsigned char *) addr;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	return ((mask & *ADDR) != 0);
-}
-
-#define ext2_find_first_zero_bit(addr, size) \
-        ext2_find_next_zero_bit((addr), (size), 0)
-
-static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
-{
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if(offset) {
-		/* We hold the little endian value in tmp, but then the
-		 * shift is illegal. So we could keep a big endian value
-		 * in tmp, like this:
-		 *
-		 * tmp = __swab32(*(p++));
-		 * tmp |= ~0UL >> (32-offset);
-		 *
-		 * but this would decrease preformance, so we change the
-		 * shift:
-		 */
-		tmp = *(p++);
-		tmp |= __swab32(~0UL >> (32-offset));
-		if(size < 32)
-			goto found_first;
-		if(~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while(size & ~31UL) {
-		if(~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if(!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	/* tmp is little endian, so we would have to swab the shift,
-	 * see above. But then we have to swab tmp below for ffz, so
-	 * we might as well do this here.
-	 */
-	return result + ffz(__swab32(tmp) | (~0UL << size));
-found_middle:
-	return result + ffz(__swab32(tmp));
-}
-#endif
-
-#define ext2_set_bit_atomic(lock, nr, addr)		\
-	({						\
-		int ret;				\
-		spin_lock(lock);			\
-		ret = ext2_set_bit((nr), (addr));	\
-		spin_unlock(lock);			\
-		ret;					\
-	})
-
-#define ext2_clear_bit_atomic(lock, nr, addr)		\
-	({						\
-		int ret;				\
-		spin_lock(lock);			\
-		ret = ext2_clear_bit((nr), (addr));	\
-		spin_unlock(lock);			\
-		ret;					\
-	})
-
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr) test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
-
-#define ffs(x)	generic_ffs(x)
-#define fls(x)	generic_fls(x)
-#define fls64(x)   generic_fls64(x)
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/find.h>
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/ext2-atomic.h>
+#include <asm-generic/bitops/minix.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-sh64/page.h b/include/asm-sh64/page.h
index c86df90..e4937cd 100644
--- a/include/asm-sh64/page.h
+++ b/include/asm-sh64/page.h
@@ -105,9 +105,7 @@
 
 /* PFN start number, because of __MEMORY_START */
 #define PFN_START		(__MEMORY_START >> PAGE_SHIFT)
-
-#define pfn_to_page(pfn)	(mem_map + (pfn) - PFN_START)
-#define page_to_pfn(page)	((unsigned long)((page) - mem_map) + PFN_START)
+#define ARCH_PFN_OFFSET		(PFN_START)
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 #define pfn_valid(pfn)		(((pfn) - PFN_START) < max_mapnr)
 #define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
@@ -117,6 +115,7 @@
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* __ASM_SH64_PAGE_H */
diff --git a/include/asm-sh64/platform.h b/include/asm-sh64/platform.h
index 7046a90..bd0d9c4 100644
--- a/include/asm-sh64/platform.h
+++ b/include/asm-sh64/platform.h
@@ -61,9 +61,4 @@
 #define code_resource (platform_parms.kram_res_p[STANDARD_KRAM_RESOURCES - 2])
 #define data_resource (platform_parms.kram_res_p[STANDARD_KRAM_RESOURCES - 1])
 
-/* Be prepared to 64-bit sign extensions */
-#define PFN_UP(x)       ((((x) + PAGE_SIZE-1) >> PAGE_SHIFT) & 0x000fffff)
-#define PFN_DOWN(x)     (((x) >> PAGE_SHIFT) & 0x000fffff)
-#define PFN_PHYS(x)     ((x) << PAGE_SHIFT)
-
 #endif	/* __ASM_SH64_PLATFORM_H */
diff --git a/include/asm-sparc/bitops.h b/include/asm-sparc/bitops.h
index 41722b5..04aa331 100644
--- a/include/asm-sparc/bitops.h
+++ b/include/asm-sparc/bitops.h
@@ -152,386 +152,22 @@
 	: "memory", "cc");
 }
 
-/*
- * non-atomic versions
- */
-static inline void __set_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned long mask = 1UL << (nr & 0x1f);
-	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
-
-	*p |= mask;
-}
-
-static inline void __clear_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned long mask = 1UL << (nr & 0x1f);
-	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
-
-	*p &= ~mask;
-}
-
-static inline void __change_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned long mask = 1UL << (nr & 0x1f);
-	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
-
-	*p ^= mask;
-}
-
-static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned long mask = 1UL << (nr & 0x1f);
-	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
-	unsigned long old = *p;
-
-	*p = old | mask;
-	return (old & mask) != 0;
-}
-
-static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned long mask = 1UL << (nr & 0x1f);
-	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
-	unsigned long old = *p;
-
-	*p = old & ~mask;
-	return (old & mask) != 0;
-}
-
-static inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned long mask = 1UL << (nr & 0x1f);
-	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
-	unsigned long old = *p;
-
-	*p = old ^ mask;
-	return (old & mask) != 0;
-}
+#include <asm-generic/bitops/non-atomic.h>
 
 #define smp_mb__before_clear_bit()	do { } while(0)
 #define smp_mb__after_clear_bit()	do { } while(0)
 
-/* The following routine need not be atomic. */
-static inline int test_bit(int nr, __const__ volatile unsigned long *addr)
-{
-	return (1UL & (((unsigned long *)addr)[nr >> 5] >> (nr & 31))) != 0UL;
-}
-
-/* The easy/cheese version for now. */
-static inline unsigned long ffz(unsigned long word)
-{
-	unsigned long result = 0;
-
-	while(word & 1) {
-		result++;
-		word >>= 1;
-	}
-	return result;
-}
-
-/**
- * __ffs - find first bit in word.
- * @word: The word to search
- *
- * Undefined if no bit exists, so code should check against 0 first.
- */
-static inline int __ffs(unsigned long word)
-{
-	int num = 0;
-
-	if ((word & 0xffff) == 0) {
-		num += 16;
-		word >>= 16;
-	}
-	if ((word & 0xff) == 0) {
-		num += 8;
-		word >>= 8;
-	}
-	if ((word & 0xf) == 0) {
-		num += 4;
-		word >>= 4;
-	}
-	if ((word & 0x3) == 0) {
-		num += 2;
-		word >>= 2;
-	}
-	if ((word & 0x1) == 0)
-		num += 1;
-	return num;
-}
-
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-static inline int sched_find_first_bit(unsigned long *b)
-{
-
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-}
-
-/*
- * ffs: find first bit set. This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
- */
-static inline int ffs(int x)
-{
-	if (!x)
-		return 0;
-	return __ffs((unsigned long)x) + 1;
-}
-
-/*
- * fls: find last (most-significant) bit set.
- * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
- */
-#define fls(x) generic_fls(x)
-#define fls64(x)   generic_fls64(x)
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
-
-/*
- * find_next_zero_bit() finds the first zero bit in a bit string of length
- * 'size' bits, starting the search at bit 'offset'. This is largely based
- * on Linus's ALPHA routines, which are pretty portable BTW.
- */
-static inline unsigned long find_next_zero_bit(const unsigned long *addr,
-    unsigned long size, unsigned long offset)
-{
-	const unsigned long *p = addr + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (32-offset);
-		if (size < 32)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size & ~31UL) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp |= ~0UL << size;
-	if (tmp == ~0UL)        /* Are any bits zero? */
-		return result + size; /* Nope. */
-found_middle:
-	return result + ffz(tmp);
-}
-
-/*
- * Linus sez that gcc can optimize the following correctly, we'll see if this
- * holds on the Sparc as it does for the ALPHA.
- */
-#define find_first_zero_bit(addr, size) \
-        find_next_zero_bit((addr), (size), 0)
-
-/**
- * find_next_bit - find the first set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- *
- * Scheduler induced bitop, do not use.
- */
-static inline int find_next_bit(const unsigned long *addr, int size, int offset)
-{
-	const unsigned long *p = addr + (offset >> 5);
-	int num = offset & ~0x1f;
-	unsigned long word;
-
-	word = *p++;
-	word &= ~((1 << (offset & 0x1f)) - 1);
-	while (num < size) {
-		if (word != 0) {
-			return __ffs(word) + num;
-		}
-		word = *p++;
-		num += 0x20;
-	}
-	return num;
-}
-
-/**
- * find_first_bit - find the first set bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first set bit, not the number of the byte
- * containing a bit.
- */
-#define find_first_bit(addr, size) \
-	find_next_bit((addr), (size), 0)
-
-/*
- */
-static inline int test_le_bit(int nr, __const__ unsigned long * addr)
-{
-	__const__ unsigned char *ADDR = (__const__ unsigned char *) addr;
-	return (ADDR[nr >> 3] >> (nr & 7)) & 1;
-}
-
-/*
- * non-atomic versions
- */
-static inline void __set_le_bit(int nr, unsigned long *addr)
-{
-	unsigned char *ADDR = (unsigned char *)addr;
-
-	ADDR += nr >> 3;
-	*ADDR |= 1 << (nr & 0x07);
-}
-
-static inline void __clear_le_bit(int nr, unsigned long *addr)
-{
-	unsigned char *ADDR = (unsigned char *)addr;
-
-	ADDR += nr >> 3;
-	*ADDR &= ~(1 << (nr & 0x07));
-}
-
-static inline int __test_and_set_le_bit(int nr, unsigned long *addr)
-{
-	int mask, retval;
-	unsigned char *ADDR = (unsigned char *)addr;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	retval = (mask & *ADDR) != 0;
-	*ADDR |= mask;
-	return retval;
-}
-
-static inline int __test_and_clear_le_bit(int nr, unsigned long *addr)
-{
-	int mask, retval;
-	unsigned char *ADDR = (unsigned char *)addr;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	retval = (mask & *ADDR) != 0;
-	*ADDR &= ~mask;
-	return retval;
-}
-
-static inline unsigned long find_next_zero_le_bit(const unsigned long *addr,
-    unsigned long size, unsigned long offset)
-{
-	const unsigned long *p = addr + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if(offset) {
-		tmp = *(p++);
-		tmp |= __swab32(~0UL >> (32-offset));
-		if(size < 32)
-			goto found_first;
-		if(~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while(size & ~31UL) {
-		if(~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if(!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp = __swab32(tmp) | (~0UL << size);
-	if (tmp == ~0UL)        /* Are any bits zero? */
-		return result + size; /* Nope. */
-	return result + ffz(tmp);
-
-found_middle:
-	return result + ffz(__swab32(tmp));
-}
-
-#define find_first_zero_le_bit(addr, size) \
-        find_next_zero_le_bit((addr), (size), 0)
-
-#define ext2_set_bit(nr,addr)	\
-	__test_and_set_le_bit((nr),(unsigned long *)(addr))
-#define ext2_clear_bit(nr,addr)	\
-	__test_and_clear_le_bit((nr),(unsigned long *)(addr))
-
-#define ext2_set_bit_atomic(lock, nr, addr)		\
-	({						\
-		int ret;				\
-		spin_lock(lock);			\
-		ret = ext2_set_bit((nr), (unsigned long *)(addr)); \
-		spin_unlock(lock);			\
-		ret;					\
-	})
-
-#define ext2_clear_bit_atomic(lock, nr, addr)		\
-	({						\
-		int ret;				\
-		spin_lock(lock);			\
-		ret = ext2_clear_bit((nr), (unsigned long *)(addr)); \
-		spin_unlock(lock);			\
-		ret;					\
-	})
-
-#define ext2_test_bit(nr,addr)	\
-	test_le_bit((nr),(unsigned long *)(addr))
-#define ext2_find_first_zero_bit(addr, size) \
-	find_first_zero_le_bit((unsigned long *)(addr), (size))
-#define ext2_find_next_zero_bit(addr, size, off) \
-	find_next_zero_le_bit((unsigned long *)(addr), (size), (off))
-
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit(nr,addr)	\
-	test_and_set_bit((nr),(unsigned long *)(addr))
-#define minix_set_bit(nr,addr)		\
-	set_bit((nr),(unsigned long *)(addr))
-#define minix_test_and_clear_bit(nr,addr) \
-	test_and_clear_bit((nr),(unsigned long *)(addr))
-#define minix_test_bit(nr,addr)		\
-	test_bit((nr),(unsigned long *)(addr))
-#define minix_find_first_zero_bit(addr,size) \
-	find_first_zero_bit((unsigned long *)(addr),(size))
+#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/find.h>
+#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/ext2-atomic.h>
+#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-sparc/page.h b/include/asm-sparc/page.h
index 9122684..ec3274b 100644
--- a/include/asm-sparc/page.h
+++ b/include/asm-sparc/page.h
@@ -152,8 +152,7 @@
 #define virt_to_phys		__pa
 #define phys_to_virt		__va
 
-#define pfn_to_page(pfn)	(mem_map + ((pfn)-(pfn_base)))
-#define page_to_pfn(page)	((unsigned long)(((page) - mem_map) + pfn_base))
+#define ARCH_PFN_OFFSET		(pfn_base)
 #define virt_to_page(kaddr)	(mem_map + ((((unsigned long)(kaddr)-PAGE_OFFSET)>>PAGE_SHIFT)))
 
 #define pfn_valid(pfn)		(((pfn) >= (pfn_base)) && (((pfn)-(pfn_base)) < max_mapnr))
@@ -164,6 +163,7 @@
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* _SPARC_PAGE_H */
diff --git a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h
index 6efc016..71944b0 100644
--- a/include/asm-sparc64/bitops.h
+++ b/include/asm-sparc64/bitops.h
@@ -18,58 +18,7 @@
 extern void clear_bit(unsigned long nr, volatile unsigned long *addr);
 extern void change_bit(unsigned long nr, volatile unsigned long *addr);
 
-/* "non-atomic" versions... */
-
-static inline void __set_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned long *m = ((unsigned long *)addr) + (nr >> 6);
-
-	*m |= (1UL << (nr & 63));
-}
-
-static inline void __clear_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned long *m = ((unsigned long *)addr) + (nr >> 6);
-
-	*m &= ~(1UL << (nr & 63));
-}
-
-static inline void __change_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned long *m = ((unsigned long *)addr) + (nr >> 6);
-
-	*m ^= (1UL << (nr & 63));
-}
-
-static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned long *m = ((unsigned long *)addr) + (nr >> 6);
-	unsigned long old = *m;
-	unsigned long mask = (1UL << (nr & 63));
-
-	*m = (old | mask);
-	return ((old & mask) != 0);
-}
-
-static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned long *m = ((unsigned long *)addr) + (nr >> 6);
-	unsigned long old = *m;
-	unsigned long mask = (1UL << (nr & 63));
-
-	*m = (old & ~mask);
-	return ((old & mask) != 0);
-}
-
-static inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned long *m = ((unsigned long *)addr) + (nr >> 6);
-	unsigned long old = *m;
-	unsigned long mask = (1UL << (nr & 63));
-
-	*m = (old ^ mask);
-	return ((old & mask) != 0);
-}
+#include <asm-generic/bitops/non-atomic.h>
 
 #ifdef CONFIG_SMP
 #define smp_mb__before_clear_bit()	membar_storeload_loadload()
@@ -79,78 +28,15 @@
 #define smp_mb__after_clear_bit()	barrier()
 #endif
 
-static inline int test_bit(int nr, __const__ volatile unsigned long *addr)
-{
-	return (1UL & (addr[nr >> 6] >> (nr & 63))) != 0UL;
-}
-
-/* The easy/cheese version for now. */
-static inline unsigned long ffz(unsigned long word)
-{
-	unsigned long result;
-
-	result = 0;
-	while(word & 1) {
-		result++;
-		word >>= 1;
-	}
-	return result;
-}
-
-/**
- * __ffs - find first bit in word.
- * @word: The word to search
- *
- * Undefined if no bit exists, so code should check against 0 first.
- */
-static inline unsigned long __ffs(unsigned long word)
-{
-	unsigned long result = 0;
-
-	while (!(word & 1UL)) {
-		result++;
-		word >>= 1;
-	}
-	return result;
-}
-
-/*
- * fls: find last bit set.
- */
-
-#define fls(x) generic_fls(x)
-#define fls64(x)   generic_fls64(x)
+#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
 
 #ifdef __KERNEL__
 
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-static inline int sched_find_first_bit(unsigned long *b)
-{
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(((unsigned int)b[1])))
-		return __ffs(b[1]) + 64;
-	if (b[1] >> 32)
-		return __ffs(b[1] >> 32) + 96;
-	return __ffs(b[2]) + 128;
-}
-
-/*
- * ffs: find first bit set. This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
- */
-static inline int ffs(int x)
-{
-	if (!x)
-		return 0;
-	return __ffs((unsigned long)x) + 1;
-}
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/ffs.h>
 
 /*
  * hweightN: returns the hamming weight (i.e. the number
@@ -193,102 +79,23 @@
 
 #else
 
-#define hweight64(x) generic_hweight64(x)
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
+#include <asm-generic/bitops/hweight.h>
 
 #endif
 #endif /* __KERNEL__ */
 
-/**
- * find_next_bit - find the next set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-extern unsigned long find_next_bit(const unsigned long *, unsigned long,
-					unsigned long);
-
-/**
- * find_first_bit - find the first set bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first set bit, not the number of the byte
- * containing a bit.
- */
-#define find_first_bit(addr, size) \
-	find_next_bit((addr), (size), 0)
-
-/* find_next_zero_bit() finds the first zero bit in a bit string of length
- * 'size' bits, starting the search at bit 'offset'. This is largely based
- * on Linus's ALPHA routines, which are pretty portable BTW.
- */
-
-extern unsigned long find_next_zero_bit(const unsigned long *,
-					unsigned long, unsigned long);
-
-#define find_first_zero_bit(addr, size) \
-        find_next_zero_bit((addr), (size), 0)
-
-#define test_and_set_le_bit(nr,addr)	\
-	test_and_set_bit((nr) ^ 0x38, (addr))
-#define test_and_clear_le_bit(nr,addr)	\
-	test_and_clear_bit((nr) ^ 0x38, (addr))
-
-static inline int test_le_bit(int nr, __const__ unsigned long * addr)
-{
-	int			mask;
-	__const__ unsigned char	*ADDR = (__const__ unsigned char *) addr;
-
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);
-	return ((mask & *ADDR) != 0);
-}
-
-#define find_first_zero_le_bit(addr, size) \
-        find_next_zero_le_bit((addr), (size), 0)
-
-extern unsigned long find_next_zero_le_bit(unsigned long *, unsigned long, unsigned long);
+#include <asm-generic/bitops/find.h>
 
 #ifdef __KERNEL__
 
-#define __set_le_bit(nr, addr) \
-	__set_bit((nr) ^ 0x38, (addr))
-#define __clear_le_bit(nr, addr) \
-	__clear_bit((nr) ^ 0x38, (addr))
-#define __test_and_clear_le_bit(nr, addr) \
-	__test_and_clear_bit((nr) ^ 0x38, (addr))
-#define __test_and_set_le_bit(nr, addr) \
-	__test_and_set_bit((nr) ^ 0x38, (addr))
+#include <asm-generic/bitops/ext2-non-atomic.h>
 
-#define ext2_set_bit(nr,addr)	\
-	__test_and_set_le_bit((nr),(unsigned long *)(addr))
 #define ext2_set_bit_atomic(lock,nr,addr) \
-	test_and_set_le_bit((nr),(unsigned long *)(addr))
-#define ext2_clear_bit(nr,addr)	\
-	__test_and_clear_le_bit((nr),(unsigned long *)(addr))
+	test_and_set_bit((nr) ^ 0x38,(unsigned long *)(addr))
 #define ext2_clear_bit_atomic(lock,nr,addr) \
-	test_and_clear_le_bit((nr),(unsigned long *)(addr))
-#define ext2_test_bit(nr,addr)	\
-	test_le_bit((nr),(unsigned long *)(addr))
-#define ext2_find_first_zero_bit(addr, size) \
-	find_first_zero_le_bit((unsigned long *)(addr), (size))
-#define ext2_find_next_zero_bit(addr, size, off) \
-	find_next_zero_le_bit((unsigned long *)(addr), (size), (off))
+	test_and_clear_bit((nr) ^ 0x38,(unsigned long *)(addr))
 
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit(nr,addr)	\
-	test_and_set_bit((nr),(unsigned long *)(addr))
-#define minix_set_bit(nr,addr)	\
-	set_bit((nr),(unsigned long *)(addr))
-#define minix_test_and_clear_bit(nr,addr) \
-	test_and_clear_bit((nr),(unsigned long *)(addr))
-#define minix_test_bit(nr,addr)	\
-	test_bit((nr),(unsigned long *)(addr))
-#define minix_find_first_zero_bit(addr,size) \
-	find_first_zero_bit((unsigned long *)(addr),(size))
+#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h
index 49d49a2..6a95d5d 100644
--- a/include/asm-sparc64/floppy.h
+++ b/include/asm-sparc64/floppy.h
@@ -738,7 +738,7 @@
 		if (!sun_floppy_types[0] && sun_floppy_types[1]) {
 			/*
 			 * Set the drive exchange bit in FCR on NS87303,
-			 * make shure other bits are sane before doing so.
+			 * make sure other bits are sane before doing so.
 			 */
 			ns87303_modify(config, FER, FER_EDM, 0);
 			ns87303_modify(config, ASC, ASC_DRV2_SEL, 0);
diff --git a/include/asm-sparc64/futex.h b/include/asm-sparc64/futex.h
index 34c4b43..dee4020 100644
--- a/include/asm-sparc64/futex.h
+++ b/include/asm-sparc64/futex.h
@@ -83,4 +83,28 @@
 	return ret;
 }
 
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+	__asm__ __volatile__(
+	"\n1:	lduwa	[%2] %%asi, %0\n"
+	"2:	casa	[%2] %%asi, %0, %1\n"
+	"3:\n"
+	"	.section .fixup,#alloc,#execinstr\n"
+	"	.align	4\n"
+	"4:	ba	3b\n"
+	"	 mov	%3, %0\n"
+	"	.previous\n"
+	"	.section __ex_table,\"a\"\n"
+	"	.align	4\n"
+	"	.word	1b, 4b\n"
+	"	.word	2b, 4b\n"
+	"	.previous\n"
+	: "=&r" (oldval)
+	: "r" (newval), "r" (uaddr), "i" (-EFAULT)
+	: "memory");
+
+	return oldval;
+}
+
 #endif /* !(_SPARC64_FUTEX_H) */
diff --git a/include/asm-sparc64/kdebug.h b/include/asm-sparc64/kdebug.h
index 6321f5a..4040d12 100644
--- a/include/asm-sparc64/kdebug.h
+++ b/include/asm-sparc64/kdebug.h
@@ -15,12 +15,9 @@
 	int signr;
 };
 
-/* Note - you should never unregister because that can race with NMIs.
- * If you really want to do it first unregister - then synchronize_sched
- * - then free.
- */
-int register_die_notifier(struct notifier_block *nb);
-extern struct notifier_block *sparc64die_chain;
+extern int register_die_notifier(struct notifier_block *);
+extern int unregister_die_notifier(struct notifier_block *);
+extern struct atomic_notifier_head sparc64die_chain;
 
 extern void bad_trap(struct pt_regs *, long);
 
@@ -46,7 +43,7 @@
 				 .trapnr	= trap,
 				 .signr		= sig };
 
-	return notifier_call_chain(&sparc64die_chain, val, &args);
+	return atomic_notifier_call_chain(&sparc64die_chain, val, &args);
 }
 
 #endif
diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
index 66fe4ac..aabb219 100644
--- a/include/asm-sparc64/page.h
+++ b/include/asm-sparc64/page.h
@@ -111,6 +111,8 @@
 				 (_AC(0x0000000070000000,UL)) : \
 				 (_AC(0xfffff80000000000,UL) + (1UL << 32UL)))
 
+#include <asm-generic/memory_model.h>
+
 #endif /* !(__ASSEMBLY__) */
 
 /* to align the pointer to the (next) page boundary */
diff --git a/include/asm-um/desc.h b/include/asm-um/desc.h
index ac1d2a2..4ec34a5 100644
--- a/include/asm-um/desc.h
+++ b/include/asm-um/desc.h
@@ -1,6 +1,16 @@
 #ifndef __UM_DESC_H
 #define __UM_DESC_H
 
-#include "asm/arch/desc.h"
+/* Taken from asm-i386/desc.h, it's the only thing we need. The rest wouldn't
+ * compile, and has never been used. */
+#define LDT_empty(info) (\
+	(info)->base_addr	== 0	&& \
+	(info)->limit		== 0	&& \
+	(info)->contents	== 0	&& \
+	(info)->read_exec_only	== 1	&& \
+	(info)->seg_32bit	== 0	&& \
+	(info)->limit_in_pages	== 0	&& \
+	(info)->seg_not_present	== 1	&& \
+	(info)->useable		== 0	)
 
 #endif
diff --git a/include/asm-um/host_ldt-i386.h b/include/asm-um/host_ldt-i386.h
new file mode 100644
index 0000000..b27cb0a
--- /dev/null
+++ b/include/asm-um/host_ldt-i386.h
@@ -0,0 +1,34 @@
+#ifndef __ASM_HOST_LDT_I386_H
+#define __ASM_HOST_LDT_I386_H
+
+#include "asm/arch/ldt.h"
+
+/*
+ * macros stolen from include/asm-i386/desc.h
+ */
+#define LDT_entry_a(info) \
+	((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
+
+#define LDT_entry_b(info) \
+	(((info)->base_addr & 0xff000000) | \
+	(((info)->base_addr & 0x00ff0000) >> 16) | \
+	((info)->limit & 0xf0000) | \
+	(((info)->read_exec_only ^ 1) << 9) | \
+	((info)->contents << 10) | \
+	(((info)->seg_not_present ^ 1) << 15) | \
+	((info)->seg_32bit << 22) | \
+	((info)->limit_in_pages << 23) | \
+	((info)->useable << 20) | \
+	0x7000)
+
+#define LDT_empty(info) (\
+	(info)->base_addr	== 0	&& \
+	(info)->limit		== 0	&& \
+	(info)->contents	== 0	&& \
+	(info)->read_exec_only	== 1	&& \
+	(info)->seg_32bit	== 0	&& \
+	(info)->limit_in_pages	== 0	&& \
+	(info)->seg_not_present	== 1	&& \
+	(info)->useable		== 0	)
+
+#endif
diff --git a/include/asm-um/host_ldt-x86_64.h b/include/asm-um/host_ldt-x86_64.h
new file mode 100644
index 0000000..74a63f7
--- /dev/null
+++ b/include/asm-um/host_ldt-x86_64.h
@@ -0,0 +1,38 @@
+#ifndef __ASM_HOST_LDT_X86_64_H
+#define __ASM_HOST_LDT_X86_64_H
+
+#include "asm/arch/ldt.h"
+
+/*
+ * macros stolen from include/asm-x86_64/desc.h
+ */
+#define LDT_entry_a(info) \
+	((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
+
+/* Don't allow setting of the lm bit. It is useless anyways because
+ * 64bit system calls require __USER_CS. */
+#define LDT_entry_b(info) \
+	(((info)->base_addr & 0xff000000) | \
+	(((info)->base_addr & 0x00ff0000) >> 16) | \
+	((info)->limit & 0xf0000) | \
+	(((info)->read_exec_only ^ 1) << 9) | \
+	((info)->contents << 10) | \
+	(((info)->seg_not_present ^ 1) << 15) | \
+	((info)->seg_32bit << 22) | \
+	((info)->limit_in_pages << 23) | \
+	((info)->useable << 20) | \
+	/* ((info)->lm << 21) | */ \
+	0x7000)
+
+#define LDT_empty(info) (\
+	(info)->base_addr	== 0	&& \
+	(info)->limit		== 0	&& \
+	(info)->contents	== 0	&& \
+	(info)->read_exec_only	== 1	&& \
+	(info)->seg_32bit	== 0	&& \
+	(info)->limit_in_pages	== 0	&& \
+	(info)->seg_not_present	== 1	&& \
+	(info)->useable		== 0	&& \
+	(info)->lm              == 0)
+
+#endif
diff --git a/include/asm-um/ldt-i386.h b/include/asm-um/ldt-i386.h
deleted file mode 100644
index 175722a..0000000
--- a/include/asm-um/ldt-i386.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2004 Fujitsu Siemens Computers GmbH
- * Licensed under the GPL
- *
- * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
- */
-
-#ifndef __ASM_LDT_I386_H
-#define __ASM_LDT_I386_H
-
-#include "asm/semaphore.h"
-#include "asm/arch/ldt.h"
-
-struct mmu_context_skas;
-extern void ldt_host_info(void);
-extern long init_new_ldt(struct mmu_context_skas * to_mm,
-			 struct mmu_context_skas * from_mm);
-extern void free_ldt(struct mmu_context_skas * mm);
-
-#define LDT_PAGES_MAX \
-	((LDT_ENTRIES * LDT_ENTRY_SIZE)/PAGE_SIZE)
-#define LDT_ENTRIES_PER_PAGE \
-	(PAGE_SIZE/LDT_ENTRY_SIZE)
-#define LDT_DIRECT_ENTRIES \
-	((LDT_PAGES_MAX*sizeof(void *))/LDT_ENTRY_SIZE)
-
-struct ldt_entry {
-	__u32 a;
-	__u32 b;
-};
-
-typedef struct uml_ldt {
-	int entry_count;
-	struct semaphore semaphore;
-	union {
-		struct ldt_entry * pages[LDT_PAGES_MAX];
-		struct ldt_entry entries[LDT_DIRECT_ENTRIES];
-	} u;
-} uml_ldt_t;
-
-/*
- * macros stolen from include/asm-i386/desc.h
- */
-#define LDT_entry_a(info) \
-	((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
-
-#define LDT_entry_b(info) \
-	(((info)->base_addr & 0xff000000) | \
-	(((info)->base_addr & 0x00ff0000) >> 16) | \
-	((info)->limit & 0xf0000) | \
-	(((info)->read_exec_only ^ 1) << 9) | \
-	((info)->contents << 10) | \
-	(((info)->seg_not_present ^ 1) << 15) | \
-	((info)->seg_32bit << 22) | \
-	((info)->limit_in_pages << 23) | \
-	((info)->useable << 20) | \
-	0x7000)
-
-#define LDT_empty(info) (\
-	(info)->base_addr	== 0	&& \
-	(info)->limit		== 0	&& \
-	(info)->contents	== 0	&& \
-	(info)->read_exec_only	== 1	&& \
-	(info)->seg_32bit	== 0	&& \
-	(info)->limit_in_pages	== 0	&& \
-	(info)->seg_not_present	== 1	&& \
-	(info)->useable		== 0	)
-
-#endif
diff --git a/include/asm-um/ldt-x86_64.h b/include/asm-um/ldt-x86_64.h
deleted file mode 100644
index 96b35aa..0000000
--- a/include/asm-um/ldt-x86_64.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2004 Fujitsu Siemens Computers GmbH
- * Licensed under the GPL
- *
- * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
- */
-
-#ifndef __ASM_LDT_X86_64_H
-#define __ASM_LDT_X86_64_H
-
-#include "asm/semaphore.h"
-#include "asm/arch/ldt.h"
-
-struct mmu_context_skas;
-extern void ldt_host_info(void);
-extern long init_new_ldt(struct mmu_context_skas * to_mm,
-			 struct mmu_context_skas * from_mm);
-extern void free_ldt(struct mmu_context_skas * mm);
-
-#define LDT_PAGES_MAX \
-	((LDT_ENTRIES * LDT_ENTRY_SIZE)/PAGE_SIZE)
-#define LDT_ENTRIES_PER_PAGE \
-	(PAGE_SIZE/LDT_ENTRY_SIZE)
-#define LDT_DIRECT_ENTRIES \
-	((LDT_PAGES_MAX*sizeof(void *))/LDT_ENTRY_SIZE)
-
-struct ldt_entry {
-	__u32 a;
-	__u32 b;
-};
-
-typedef struct uml_ldt {
-	int entry_count;
-	struct semaphore semaphore;
-	union {
-		struct ldt_entry * pages[LDT_PAGES_MAX];
-		struct ldt_entry entries[LDT_DIRECT_ENTRIES];
-	} u;
-} uml_ldt_t;
-
-/*
- * macros stolen from include/asm-x86_64/desc.h
- */
-#define LDT_entry_a(info) \
-	((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
-
-/* Don't allow setting of the lm bit. It is useless anyways because
- * 64bit system calls require __USER_CS. */
-#define LDT_entry_b(info) \
-	(((info)->base_addr & 0xff000000) | \
-	(((info)->base_addr & 0x00ff0000) >> 16) | \
-	((info)->limit & 0xf0000) | \
-	(((info)->read_exec_only ^ 1) << 9) | \
-	((info)->contents << 10) | \
-	(((info)->seg_not_present ^ 1) << 15) | \
-	((info)->seg_32bit << 22) | \
-	((info)->limit_in_pages << 23) | \
-	((info)->useable << 20) | \
-	/* ((info)->lm << 21) | */ \
-	0x7000)
-
-#define LDT_empty(info) (\
-	(info)->base_addr	== 0	&& \
-	(info)->limit		== 0	&& \
-	(info)->contents	== 0	&& \
-	(info)->read_exec_only	== 1	&& \
-	(info)->seg_32bit	== 0	&& \
-	(info)->limit_in_pages	== 0	&& \
-	(info)->seg_not_present	== 1	&& \
-	(info)->useable		== 0	&& \
-	(info)->lm              == 0)
-
-#endif
diff --git a/include/asm-um/ldt.h b/include/asm-um/ldt.h
new file mode 100644
index 0000000..96f82a4
--- /dev/null
+++ b/include/asm-um/ldt.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2004 Fujitsu Siemens Computers GmbH
+ * Licensed under the GPL
+ *
+ * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
+ */
+
+#ifndef __ASM_LDT_H
+#define __ASM_LDT_H
+
+#include "asm/semaphore.h"
+#include "asm/host_ldt.h"
+
+struct mmu_context_skas;
+extern void ldt_host_info(void);
+extern long init_new_ldt(struct mmu_context_skas * to_mm,
+			 struct mmu_context_skas * from_mm);
+extern void free_ldt(struct mmu_context_skas * mm);
+
+#define LDT_PAGES_MAX \
+	((LDT_ENTRIES * LDT_ENTRY_SIZE)/PAGE_SIZE)
+#define LDT_ENTRIES_PER_PAGE \
+	(PAGE_SIZE/LDT_ENTRY_SIZE)
+#define LDT_DIRECT_ENTRIES \
+	((LDT_PAGES_MAX*sizeof(void *))/LDT_ENTRY_SIZE)
+
+struct ldt_entry {
+	__u32 a;
+	__u32 b;
+};
+
+typedef struct uml_ldt {
+	int entry_count;
+	struct semaphore semaphore;
+	union {
+		struct ldt_entry * pages[LDT_PAGES_MAX];
+		struct ldt_entry entries[LDT_DIRECT_ENTRIES];
+	} u;
+} uml_ldt_t;
+
+#endif
diff --git a/include/asm-um/page.h b/include/asm-um/page.h
index 0229814..4136433 100644
--- a/include/asm-um/page.h
+++ b/include/asm-um/page.h
@@ -106,9 +106,6 @@
 #define __pa(virt) to_phys((void *) (unsigned long) (virt))
 #define __va(phys) to_virt((unsigned long) (phys))
 
-#define page_to_pfn(page) ((page) - mem_map)
-#define pfn_to_page(pfn) (mem_map + (pfn))
-
 #define phys_to_pfn(p) ((p) >> PAGE_SHIFT)
 #define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT)
 
@@ -121,6 +118,7 @@
 extern void arch_free_page(struct page *page, int order);
 #define HAVE_ARCH_FREE_PAGE
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif
diff --git a/include/asm-um/processor-i386.h b/include/asm-um/processor-i386.h
index 4108a57..595f1c3 100644
--- a/include/asm-um/processor-i386.h
+++ b/include/asm-um/processor-i386.h
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
@@ -6,21 +6,48 @@
 #ifndef __UM_PROCESSOR_I386_H
 #define __UM_PROCESSOR_I386_H
 
+#include "linux/string.h"
+#include "asm/host_ldt.h"
+#include "asm/segment.h"
+
 extern int host_has_xmm;
 extern int host_has_cmov;
 
 /* include faultinfo structure */
 #include "sysdep/faultinfo.h"
 
+struct uml_tls_struct {
+	struct user_desc tls;
+	unsigned flushed:1;
+	unsigned present:1;
+};
+
 struct arch_thread {
+	struct uml_tls_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
 	unsigned long debugregs[8];
 	int debugregs_seq;
 	struct faultinfo faultinfo;
 };
 
-#define INIT_ARCH_THREAD { .debugregs  		= { [ 0 ... 7 ] = 0 }, \
-                           .debugregs_seq	= 0, \
-                           .faultinfo		= { 0, 0, 0 } }
+#define INIT_ARCH_THREAD { \
+	.tls_array  		= { [ 0 ... GDT_ENTRY_TLS_ENTRIES - 1 ] = \
+				    { .present = 0, .flushed = 0 } }, \
+	.debugregs  		= { [ 0 ... 7 ] = 0 }, \
+	.debugregs_seq		= 0, \
+	.faultinfo		= { 0, 0, 0 } \
+}
+
+static inline void arch_flush_thread(struct arch_thread *thread)
+{
+	/* Clear any TLS still hanging */
+	memset(&thread->tls_array, 0, sizeof(thread->tls_array));
+}
+
+static inline void arch_copy_thread(struct arch_thread *from,
+                                    struct arch_thread *to)
+{
+        memcpy(&to->tls_array, &from->tls_array, sizeof(from->tls_array));
+}
 
 #include "asm/arch/user.h"
 
diff --git a/include/asm-um/processor-x86_64.h b/include/asm-um/processor-x86_64.h
index e1e1255..10609af 100644
--- a/include/asm-um/processor-x86_64.h
+++ b/include/asm-um/processor-x86_64.h
@@ -28,6 +28,15 @@
                            .debugregs_seq	= 0, \
                            .faultinfo		= { 0, 0, 0 } }
 
+static inline void arch_flush_thread(struct arch_thread *thread)
+{
+}
+
+static inline void arch_copy_thread(struct arch_thread *from,
+                                    struct arch_thread *to)
+{
+}
+
 #include "asm/arch/user.h"
 
 #define current_text_addr() \
diff --git a/include/asm-um/ptrace-generic.h b/include/asm-um/ptrace-generic.h
index 46599ac..5034843 100644
--- a/include/asm-um/ptrace-generic.h
+++ b/include/asm-um/ptrace-generic.h
@@ -28,7 +28,7 @@
 	union uml_pt_regs regs;
 };
 
-#define EMPTY_REGS { regs : EMPTY_UML_PT_REGS }
+#define EMPTY_REGS { .regs = EMPTY_UML_PT_REGS }
 
 #define PT_REGS_IP(r) UPT_IP(&(r)->regs)
 #define PT_REGS_SP(r) UPT_SP(&(r)->regs)
@@ -60,17 +60,9 @@
 extern void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs,
 			 int error_code);
 
-#endif
+extern int arch_copy_tls(struct task_struct *new);
+extern void clear_flushed_tls(struct task_struct *task);
 
 #endif
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+#endif
diff --git a/include/asm-um/ptrace-i386.h b/include/asm-um/ptrace-i386.h
index fe882b9..30656c9 100644
--- a/include/asm-um/ptrace-i386.h
+++ b/include/asm-um/ptrace-i386.h
@@ -8,8 +8,11 @@
 
 #define HOST_AUDIT_ARCH AUDIT_ARCH_I386
 
+#include "linux/compiler.h"
 #include "sysdep/ptrace.h"
 #include "asm/ptrace-generic.h"
+#include "asm/host_ldt.h"
+#include "choose-mode.h"
 
 #define PT_REGS_EAX(r) UPT_EAX(&(r)->regs)
 #define PT_REGS_EBX(r) UPT_EBX(&(r)->regs)
@@ -38,15 +41,31 @@
 
 #define user_mode(r) UPT_IS_USER(&(r)->regs)
 
-#endif
+extern int ptrace_get_thread_area(struct task_struct *child, int idx,
+                                  struct user_desc __user *user_desc);
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+extern int ptrace_set_thread_area(struct task_struct *child, int idx,
+                                  struct user_desc __user *user_desc);
+
+extern int do_set_thread_area_skas(struct user_desc *info);
+extern int do_get_thread_area_skas(struct user_desc *info);
+
+extern int do_set_thread_area_tt(struct user_desc *info);
+extern int do_get_thread_area_tt(struct user_desc *info);
+
+extern int arch_switch_tls_skas(struct task_struct *from, struct task_struct *to);
+extern int arch_switch_tls_tt(struct task_struct *from, struct task_struct *to);
+
+static inline int do_get_thread_area(struct user_desc *info)
+{
+	return CHOOSE_MODE_PROC(do_get_thread_area_tt, do_get_thread_area_skas, info);
+}
+
+static inline int do_set_thread_area(struct user_desc *info)
+{
+	return CHOOSE_MODE_PROC(do_set_thread_area_tt, do_set_thread_area_skas, info);
+}
+
+struct task_struct;
+
+#endif
diff --git a/include/asm-um/ptrace-x86_64.h b/include/asm-um/ptrace-x86_64.h
index be51219..c894e68 100644
--- a/include/asm-um/ptrace-x86_64.h
+++ b/include/asm-um/ptrace-x86_64.h
@@ -8,6 +8,8 @@
 #define __UM_PTRACE_X86_64_H
 
 #include "linux/compiler.h"
+#include "asm/errno.h"
+#include "asm/host_ldt.h"
 
 #define signal_fault signal_fault_x86_64
 #define __FRAME_OFFSETS /* Needed to get the R* macros */
@@ -63,15 +65,26 @@
 
 #define profile_pc(regs) PT_REGS_IP(regs)
 
-#endif
+static inline int ptrace_get_thread_area(struct task_struct *child, int idx,
+                                         struct user_desc __user *user_desc)
+{
+        return -ENOSYS;
+}
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+static inline int ptrace_set_thread_area(struct task_struct *child, int idx,
+                                         struct user_desc __user *user_desc)
+{
+        return -ENOSYS;
+}
+
+static inline void arch_switch_to_tt(struct task_struct *from,
+                                     struct task_struct *to)
+{
+}
+
+static inline void arch_switch_to_skas(struct task_struct *from,
+                                       struct task_struct *to)
+{
+}
+
+#endif
diff --git a/include/asm-um/segment.h b/include/asm-um/segment.h
index 55e4030..45183fc 100644
--- a/include/asm-um/segment.h
+++ b/include/asm-um/segment.h
@@ -1,4 +1,10 @@
 #ifndef __UM_SEGMENT_H
 #define __UM_SEGMENT_H
 
+extern int host_gdt_entry_tls_min;
+
+#define GDT_ENTRY_TLS_ENTRIES 3
+#define GDT_ENTRY_TLS_MIN host_gdt_entry_tls_min
+#define GDT_ENTRY_TLS_MAX (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1)
+
 #endif
diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h
index 17b6b07..f166b98 100644
--- a/include/asm-um/thread_info.h
+++ b/include/asm-um/thread_info.h
@@ -27,14 +27,14 @@
 
 #define INIT_THREAD_INFO(tsk)			\
 {						\
-	task:		&tsk,			\
-	exec_domain:	&default_exec_domain,	\
-	flags:		0,			\
-	cpu:		0,			\
-	preempt_count:	1,			\
-	addr_limit:	KERNEL_DS,		\
-	restart_block:  {			\
-		fn:  do_no_restart_syscall,	\
+	.task =		&tsk,			\
+	.exec_domain =	&default_exec_domain,	\
+	.flags =		0,		\
+	.cpu =		0,			\
+	.preempt_count =	1,		\
+	.addr_limit =	KERNEL_DS,		\
+	.restart_block =  {			\
+		.fn =  do_no_restart_syscall,	\
 	},					\
 }
 
diff --git a/include/asm-um/uaccess.h b/include/asm-um/uaccess.h
index 2ee028b..bea5a01 100644
--- a/include/asm-um/uaccess.h
+++ b/include/asm-um/uaccess.h
@@ -41,23 +41,23 @@
 
 #define __get_user(x, ptr) \
 ({ \
-        const __typeof__(ptr) __private_ptr = ptr; \
-        __typeof__(*(__private_ptr)) __private_val; \
-        int __private_ret = -EFAULT; \
-        (x) = (__typeof__(*(__private_ptr)))0; \
-	if (__copy_from_user(&__private_val, (__private_ptr), \
-	    sizeof(*(__private_ptr))) == 0) {\
-        	(x) = (__typeof__(*(__private_ptr))) __private_val; \
-		__private_ret = 0; \
-	} \
-        __private_ret; \
+	const __typeof__(ptr) __private_ptr = ptr;	\
+	__typeof__(x) __private_val;			\
+	int __private_ret = -EFAULT;			\
+	(x) = (__typeof__(*(__private_ptr)))0;				\
+	if (__copy_from_user((void *) &__private_val, (__private_ptr),	\
+			     sizeof(*(__private_ptr))) == 0) {		\
+		(x) = (__typeof__(*(__private_ptr))) __private_val;	\
+		__private_ret = 0;					\
+	}								\
+	__private_ret;							\
 }) 
 
 #define get_user(x, ptr) \
 ({ \
         const __typeof__((*(ptr))) __user *private_ptr = (ptr); \
         (access_ok(VERIFY_READ, private_ptr, sizeof(*private_ptr)) ? \
-	 __get_user(x, private_ptr) : ((x) = 0, -EFAULT)); \
+	 __get_user(x, private_ptr) : ((x) = (__typeof__(*ptr))0, -EFAULT)); \
 })
 
 #define __put_user(x, ptr) \
@@ -89,14 +89,3 @@
 };
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/include/asm-v850/bitops.h b/include/asm-v850/bitops.h
index 609b9e8..1f6fd5a 100644
--- a/include/asm-v850/bitops.h
+++ b/include/asm-v850/bitops.h
@@ -22,26 +22,12 @@
 
 #ifdef __KERNEL__
 
+#include <asm-generic/bitops/ffz.h>
+
 /*
  * The __ functions are not atomic
  */
 
-/*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
- */
-static inline unsigned long ffz (unsigned long word)
-{
-	unsigned long result = 0;
-
-	while (word & 1) {
-		result++;
-		word >>= 1;
-	}
-	return result;
-}
-
-
 /* In the following constant-bit-op macros, a "g" constraint is used when
    we really need an integer ("i" constraint).  This is to avoid
    warnings/errors from the compiler in the case where the associated
@@ -153,203 +139,19 @@
 #define smp_mb__before_clear_bit()	barrier ()
 #define smp_mb__after_clear_bit()	barrier ()
 
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/find.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/hweight.h>
 
-#define find_first_zero_bit(addr, size) \
-  find_next_zero_bit ((addr), (size), 0)
-
-static inline int find_next_zero_bit(const void *addr, int size, int offset)
-{
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = * (p++);
-		tmp |= ~0UL >> (32-offset);
-		if (size < 32)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size & ~31UL) {
-		if (~ (tmp = * (p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
- found_first:
-	tmp |= ~0UL << size;
- found_middle:
-	return result + ffz (tmp);
-}
-
-
-/* This is the same as generic_ffs, but we can't use that because it's
-   inline and the #include order mucks things up.  */
-static inline int generic_ffs_for_find_next_bit(int x)
-{
-	int r = 1;
-
-	if (!x)
-		return 0;
-	if (!(x & 0xffff)) {
-		x >>= 16;
-		r += 16;
-	}
-	if (!(x & 0xff)) {
-		x >>= 8;
-		r += 8;
-	}
-	if (!(x & 0xf)) {
-		x >>= 4;
-		r += 4;
-	}
-	if (!(x & 3)) {
-		x >>= 2;
-		r += 2;
-	}
-	if (!(x & 1)) {
-		x >>= 1;
-		r += 1;
-	}
-	return r;
-}
-
-/*
- * Find next one bit in a bitmap reasonably efficiently.
- */
-static __inline__ unsigned long find_next_bit(const unsigned long *addr,
-	unsigned long size, unsigned long offset)
-{
-	unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
-	unsigned int result = offset & ~31UL;
-	unsigned int tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *p++;
-		tmp &= ~0UL << offset;
-		if (size < 32)
-			goto found_first;
-		if (tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size >= 32) {
-		if ((tmp = *p++) != 0)
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp &= ~0UL >> (32 - size);
-	if (tmp == 0UL)        /* Are any bits set? */
-		return result + size; /* Nope. */
-found_middle:
-	return result + generic_ffs_for_find_next_bit(tmp);
-}
-
-/*
- * find_first_bit - find the first set bit in a memory region
- */
-#define find_first_bit(addr, size) \
-	find_next_bit((addr), (size), 0)
-
-
-#define ffs(x) generic_ffs (x)
-#define fls(x) generic_fls (x)
-#define fls64(x) generic_fls64(x)
-#define __ffs(x) ffs(x)
-
-
-/*
- * This is just `generic_ffs' from <linux/bitops.h>, except that it assumes
- * that at least one bit is set, and returns the real index of the bit
- * (rather than the bit index + 1, like ffs does).
- */
-static inline int sched_ffs(int x)
-{
-	int r = 0;
-
-	if (!(x & 0xffff)) {
-		x >>= 16;
-		r += 16;
-	}
-	if (!(x & 0xff)) {
-		x >>= 8;
-		r += 8;
-	}
-	if (!(x & 0xf)) {
-		x >>= 4;
-		r += 4;
-	}
-	if (!(x & 3)) {
-		x >>= 2;
-		r += 2;
-	}
-	if (!(x & 1)) {
-		x >>= 1;
-		r += 1;
-	}
-	return r;
-}
-
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is set.
- */
-static inline int sched_find_first_bit(unsigned long *b)
-{
-	unsigned offs = 0;
-	while (! *b) {
-		b++;
-		offs += 32;
-	}
-	return sched_ffs (*b) + offs;
-}
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-#define hweight32(x) 			generic_hweight32 (x)
-#define hweight16(x) 			generic_hweight16 (x)
-#define hweight8(x) 			generic_hweight8 (x)
-
-#define ext2_set_bit			test_and_set_bit
+#include <asm-generic/bitops/ext2-non-atomic.h>
 #define ext2_set_bit_atomic(l,n,a)      test_and_set_bit(n,a)
-#define ext2_clear_bit			test_and_clear_bit
 #define ext2_clear_bit_atomic(l,n,a)    test_and_clear_bit(n,a)
-#define ext2_test_bit			test_bit
-#define ext2_find_first_zero_bit	find_first_zero_bit
-#define ext2_find_next_zero_bit		find_next_zero_bit
 
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit		test_and_set_bit
-#define minix_set_bit			set_bit
-#define minix_test_and_clear_bit	test_and_clear_bit
-#define minix_test_bit 			test_bit
-#define minix_find_first_zero_bit 	find_first_zero_bit
+#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-v850/page.h b/include/asm-v850/page.h
index b4bc85e..ad03c46 100644
--- a/include/asm-v850/page.h
+++ b/include/asm-v850/page.h
@@ -111,8 +111,7 @@
 #define page_to_virt(page) \
   ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
 
-#define pfn_to_page(pfn)	virt_to_page (pfn_to_virt (pfn))
-#define page_to_pfn(page)	virt_to_pfn (page_to_virt (page))
+#define ARCH_PFN_OFFSET		(PAGE_OFFSET >> PAGE_SHIFT)
 #define pfn_valid(pfn)	        ((pfn) < max_mapnr)
 
 #define	virt_addr_valid(kaddr)						\
@@ -125,6 +124,7 @@
 
 #endif /* KERNEL */
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* __V850_PAGE_H__ */
diff --git a/include/asm-x86_64/bitops.h b/include/asm-x86_64/bitops.h
index eb4df23..7921212 100644
--- a/include/asm-x86_64/bitops.h
+++ b/include/asm-x86_64/bitops.h
@@ -356,14 +356,7 @@
 
 #ifdef __KERNEL__
 
-static inline int sched_find_first_bit(const unsigned long *b)
-{
-	if (b[0])
-		return __ffs(b[0]);
-	if (b[1])
-		return __ffs(b[1]) + 64;
-	return __ffs(b[2]) + 128;
-}
+#include <asm-generic/bitops/sched.h>
 
 /**
  * ffs - find first bit set
@@ -412,43 +405,20 @@
 	return r+1;
 }
 
-/**
- * hweightN - returns the hamming weight of a N-bit word
- * @x: the word to weigh
- *
- * The Hamming Weight of a number is the total number of bits set in it.
- */
-
-#define hweight64(x) generic_hweight64(x)
-#define hweight32(x) generic_hweight32(x)
-#define hweight16(x) generic_hweight16(x)
-#define hweight8(x) generic_hweight8(x)
+#include <asm-generic/bitops/hweight.h>
 
 #endif /* __KERNEL__ */
 
 #ifdef __KERNEL__
 
-#define ext2_set_bit(nr,addr) \
-	__test_and_set_bit((nr),(unsigned long*)addr)
+#include <asm-generic/bitops/ext2-non-atomic.h>
+
 #define ext2_set_bit_atomic(lock,nr,addr) \
 	        test_and_set_bit((nr),(unsigned long*)addr)
-#define ext2_clear_bit(nr, addr) \
-	__test_and_clear_bit((nr),(unsigned long*)addr)
 #define ext2_clear_bit_atomic(lock,nr,addr) \
 	        test_and_clear_bit((nr),(unsigned long*)addr)
-#define ext2_test_bit(nr, addr)      test_bit((nr),(unsigned long*)addr)
-#define ext2_find_first_zero_bit(addr, size) \
-	find_first_zero_bit((unsigned long*)addr, size)
-#define ext2_find_next_zero_bit(addr, size, off) \
-	find_next_zero_bit((unsigned long*)addr, size, off)
 
-/* Bitmap functions for the minix filesystem.  */
-#define minix_test_and_set_bit(nr,addr) __test_and_set_bit(nr,(void*)addr)
-#define minix_set_bit(nr,addr) __set_bit(nr,(void*)addr)
-#define minix_test_and_clear_bit(nr,addr) __test_and_clear_bit(nr,(void*)addr)
-#define minix_test_bit(nr,addr) test_bit(nr,(void*)addr)
-#define minix_find_first_zero_bit(addr,size) \
-	find_first_zero_bit((void*)addr,size)
+#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-x86_64/futex.h b/include/asm-x86_64/futex.h
index 8602c09..9804bf0 100644
--- a/include/asm-x86_64/futex.h
+++ b/include/asm-x86_64/futex.h
@@ -94,5 +94,32 @@
 	return ret;
 }
 
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+		return -EFAULT;
+
+	__asm__ __volatile__(
+		"1:	" LOCK_PREFIX "cmpxchgl %3, %1		\n"
+
+		"2:	.section .fixup, \"ax\"			\n"
+		"3:	mov     %2, %0				\n"
+		"	jmp     2b				\n"
+		"	.previous				\n"
+
+		"	.section __ex_table, \"a\"		\n"
+		"	.align  8				\n"
+		"	.quad   1b,3b				\n"
+		"	.previous				\n"
+
+		: "=a" (oldval), "=m" (*uaddr)
+		: "i" (-EFAULT), "r" (newval), "0" (oldval)
+		: "memory"
+	);
+
+	return oldval;
+}
+
 #endif
 #endif
diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h
index b9ed4c0..cf79563 100644
--- a/include/asm-x86_64/kdebug.h
+++ b/include/asm-x86_64/kdebug.h
@@ -5,21 +5,20 @@
 
 struct pt_regs;
 
-struct die_args { 
+struct die_args {
 	struct pt_regs *regs;
 	const char *str;
-	long err; 
+	long err;
 	int trapnr;
 	int signr;
-}; 
+};
 
-/* Note - you should never unregister because that can race with NMIs.
-   If you really want to do it first unregister - then synchronize_sched - then free.
-  */
-int register_die_notifier(struct notifier_block *nb);
-extern struct notifier_block *die_chain;
+extern int register_die_notifier(struct notifier_block *);
+extern int unregister_die_notifier(struct notifier_block *);
+extern struct atomic_notifier_head die_chain;
+
 /* Grossly misnamed. */
-enum die_val { 
+enum die_val {
 	DIE_OOPS = 1,
 	DIE_INT3,
 	DIE_DEBUG,
@@ -33,8 +32,8 @@
 	DIE_CALL,
 	DIE_NMI_IPI,
 	DIE_PAGE_FAULT,
-}; 
-	
+};
+
 static inline int notify_die(enum die_val val, const char *str,
 			struct pt_regs *regs, long err, int trap, int sig)
 {
@@ -45,7 +44,7 @@
 		.trapnr = trap,
 		.signr = sig
 	};
-	return notifier_call_chain(&die_chain, val, &args); 
+	return atomic_notifier_call_chain(&die_chain, val, &args);
 } 
 
 extern int printk_address(unsigned long address);
diff --git a/include/asm-x86_64/local.h b/include/asm-x86_64/local.h
index bf14803..cd17945 100644
--- a/include/asm-x86_64/local.h
+++ b/include/asm-x86_64/local.h
@@ -5,7 +5,7 @@
 
 typedef struct
 {
-	volatile unsigned long counter;
+	volatile long counter;
 } local_t;
 
 #define LOCAL_INIT(i)	{ (i) }
@@ -13,7 +13,7 @@
 #define local_read(v)	((v)->counter)
 #define local_set(v,i)	(((v)->counter) = (i))
 
-static __inline__ void local_inc(local_t *v)
+static inline void local_inc(local_t *v)
 {
 	__asm__ __volatile__(
 		"incq %0"
@@ -21,7 +21,7 @@
 		:"m" (v->counter));
 }
 
-static __inline__ void local_dec(local_t *v)
+static inline void local_dec(local_t *v)
 {
 	__asm__ __volatile__(
 		"decq %0"
@@ -29,7 +29,7 @@
 		:"m" (v->counter));
 }
 
-static __inline__ void local_add(unsigned int i, local_t *v)
+static inline void local_add(long i, local_t *v)
 {
 	__asm__ __volatile__(
 		"addq %1,%0"
@@ -37,7 +37,7 @@
 		:"ir" (i), "m" (v->counter));
 }
 
-static __inline__ void local_sub(unsigned int i, local_t *v)
+static inline void local_sub(long i, local_t *v)
 {
 	__asm__ __volatile__(
 		"subq %1,%0"
diff --git a/include/asm-x86_64/mmzone.h b/include/asm-x86_64/mmzone.h
index 937f99b..6b18cd8 100644
--- a/include/asm-x86_64/mmzone.h
+++ b/include/asm-x86_64/mmzone.h
@@ -44,12 +44,8 @@
 #define pfn_to_nid(pfn) phys_to_nid((unsigned long)(pfn) << PAGE_SHIFT)
 #define kvaddr_to_nid(kaddr)	phys_to_nid(__pa(kaddr))
 
-extern struct page *pfn_to_page(unsigned long pfn);
-extern unsigned long page_to_pfn(struct page *page);
 extern int pfn_valid(unsigned long pfn);
 #endif
 
-#define local_mapnr(kvaddr) \
-	( (__pa(kvaddr) >> PAGE_SHIFT) - node_start_pfn(kvaddr_to_nid(kvaddr)) )
 #endif
 #endif
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
index 615e3e4..408185b 100644
--- a/include/asm-x86_64/page.h
+++ b/include/asm-x86_64/page.h
@@ -123,8 +123,6 @@
 #define __boot_va(x)		__va(x)
 #define __boot_pa(x)		__pa(x)
 #ifdef CONFIG_FLATMEM
-#define pfn_to_page(pfn)	(mem_map + (pfn))
-#define page_to_pfn(page)	((unsigned long)((page) - mem_map))
 #define pfn_valid(pfn)		((pfn) < end_pfn)
 #endif
 
@@ -140,6 +138,7 @@
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
 #endif /* _X86_64_PAGE_H */
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
index 8c8d88c..37a3ec4 100644
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -20,6 +20,7 @@
 #include <asm/mmsegment.h>
 #include <asm/percpu.h>
 #include <linux/personality.h>
+#include <linux/cpumask.h>
 
 #define TF_MASK		0x00000100
 #define IF_MASK		0x00000200
@@ -65,6 +66,9 @@
         __u32   x86_power; 	
 	__u32   extended_cpuid_level;	/* Max extended CPUID function supported */
 	unsigned long loops_per_jiffy;
+#ifdef CONFIG_SMP
+	cpumask_t llc_shared_map;	/* cpus sharing the last level cache */
+#endif
 	__u8	apicid;
 	__u8	booted_cores;	/* number of cores as seen by OS */
 } ____cacheline_aligned;
@@ -354,9 +358,6 @@
 	struct extended_signature sigs[0];
 };
 
-/* '6' because it used to be for P6 only (but now covers Pentium 4 as well) */
-#define MICROCODE_IOCFREE	_IO('6',0)
-
 
 #define ASM_NOP1 K8_NOP1
 #define ASM_NOP2 K8_NOP2
diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h
index 9ccbb2c..a4fdaeb 100644
--- a/include/asm-x86_64/smp.h
+++ b/include/asm-x86_64/smp.h
@@ -56,6 +56,7 @@
 extern cpumask_t cpu_core_map[NR_CPUS];
 extern u8 phys_proc_id[NR_CPUS];
 extern u8 cpu_core_id[NR_CPUS];
+extern u8 cpu_llc_id[NR_CPUS];
 
 #define SMP_TRAMPOLINE_BASE 0x6000
 
diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
index c642f5d..9db54e9 100644
--- a/include/asm-x86_64/topology.h
+++ b/include/asm-x86_64/topology.h
@@ -68,4 +68,6 @@
 
 #include <asm-generic/topology.h>
 
+extern cpumask_t cpu_coregroup_map(int cpu);
+
 #endif
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index da0341c..f21ff2c 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -605,8 +605,14 @@
 __SYSCALL(__NR_ppoll,	sys_ni_syscall)		/* for now */
 #define __NR_unshare		272
 __SYSCALL(__NR_unshare,	sys_unshare)
+#define __NR_set_robust_list	273
+__SYSCALL(__NR_set_robust_list, sys_set_robust_list)
+#define __NR_get_robust_list	274
+__SYSCALL(__NR_get_robust_list, sys_get_robust_list)
+#define __NR_splice		275
+__SYSCALL(__NR_splice, sys_splice)
 
-#define __NR_syscall_max __NR_unshare
+#define __NR_syscall_max __NR_splice
 
 #ifndef __NO_STUBS
 
diff --git a/include/asm-xtensa/bitops.h b/include/asm-xtensa/bitops.h
index 0a2065f..d815649 100644
--- a/include/asm-xtensa/bitops.h
+++ b/include/asm-xtensa/bitops.h
@@ -23,156 +23,11 @@
 # error SMP not supported on this architecture
 #endif
 
-static __inline__ void set_bit(int nr, volatile void * addr)
-{
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
-	unsigned long flags;
-
-	local_irq_save(flags);
-	*a |= mask;
-	local_irq_restore(flags);
-}
-
-static __inline__ void __set_bit(int nr, volatile unsigned long * addr)
-{
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
-
-	*a |= mask;
-}
-
-static __inline__ void clear_bit(int nr, volatile void * addr)
-{
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
-	unsigned long flags;
-
-	local_irq_save(flags);
-	*a &= ~mask;
-	local_irq_restore(flags);
-}
-
-static __inline__ void __clear_bit(int nr, volatile unsigned long *addr)
-{
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
-
-	*a &= ~mask;
-}
-
-/*
- * clear_bit() doesn't provide any barrier for the compiler.
- */
-
 #define smp_mb__before_clear_bit()	barrier()
 #define smp_mb__after_clear_bit()	barrier()
 
-static __inline__ void change_bit(int nr, volatile void * addr)
-{
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
-	unsigned long flags;
-
-	local_irq_save(flags);
-	*a ^= mask;
-	local_irq_restore(flags);
-}
-
-static __inline__ void __change_bit(int nr, volatile void * addr)
-{
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
-
-	*a ^= mask;
-}
-
-static __inline__ int test_and_set_bit(int nr, volatile void * addr)
-{
-  	unsigned long retval;
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
-	unsigned long flags;
-
-	local_irq_save(flags);
-	retval = (mask & *a) != 0;
-	*a |= mask;
-	local_irq_restore(flags);
-
-	return retval;
-}
-
-static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
-{
-  	unsigned long retval;
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
-
-	retval = (mask & *a) != 0;
-	*a |= mask;
-
-	return retval;
-}
-
-static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
-{
-  	unsigned long retval;
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
-	unsigned long flags;
-
-	local_irq_save(flags);
-	retval = (mask & *a) != 0;
-	*a &= ~mask;
-	local_irq_restore(flags);
-
-	return retval;
-}
-
-static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
-{
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
-  	unsigned long old = *a;
-
-	*a = old & ~mask;
-	return (old & mask) != 0;
-}
-
-static __inline__ int test_and_change_bit(int nr, volatile void * addr)
-{
-  	unsigned long retval;
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	retval = (mask & *a) != 0;
-	*a ^= mask;
-	local_irq_restore(flags);
-
-	return retval;
-}
-
-/*
- * non-atomic version; can be reordered
- */
-
-static __inline__ int __test_and_change_bit(int nr, volatile void *addr)
-{
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
-	unsigned long old = *a;
-
-	*a = old ^ mask;
-	return (old & mask) != 0;
-}
-
-static __inline__ int test_bit(int nr, const volatile void *addr)
-{
-	return 1UL & (((const volatile unsigned int *)addr)[nr>>5] >> (nr&31));
-}
+#include <asm-generic/bitops/atomic.h>
+#include <asm-generic/bitops/non-atomic.h>
 
 #if XCHAL_HAVE_NSA
 
@@ -245,202 +100,23 @@
 {
 	return __cntlz(x);
 }
-#define fls64(x)   generic_fls64(x)
-
-static __inline__ int
-find_next_bit(const unsigned long *addr, int size, int offset)
-{
-	const unsigned long *p = addr + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *p++;
-		tmp &= ~0UL << offset;
-		if (size < 32)
-			goto found_first;
-		if (tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size >= 32) {
-		if ((tmp = *p++) != 0)
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp &= ~0UL >> (32 - size);
-	if (tmp == 0UL)	/* Are any bits set? */
-		return result + size;	/* Nope. */
-found_middle:
-	return result + __ffs(tmp);
-}
-
-/**
- * find_first_bit - find the first set bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first set bit, not the number of the byte
- * containing a bit.
- */
-
-#define find_first_bit(addr, size) \
-        find_next_bit((addr), (size), 0)
-
-static __inline__ int
-find_next_zero_bit(const unsigned long *addr, int size, int offset)
-{
-	const unsigned long *p = addr + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if (offset) {
-		tmp = *p++;
-		tmp |= ~0UL >> (32-offset);
-		if (size < 32)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while (size & ~31UL) {
-		if (~(tmp = *p++))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp |= ~0UL << size;
-found_middle:
-	return result + ffz(tmp);
-}
-
-#define find_first_zero_bit(addr, size) \
-        find_next_zero_bit((addr), (size), 0)
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/find.h>
+#include <asm-generic/bitops/ext2-non-atomic.h>
 
 #ifdef __XTENSA_EL__
-# define ext2_set_bit(nr,addr) __test_and_set_bit((nr), (addr))
 # define ext2_set_bit_atomic(lock,nr,addr) test_and_set_bit((nr),(addr))
-# define ext2_clear_bit(nr,addr) __test_and_clear_bit((nr), (addr))
 # define ext2_clear_bit_atomic(lock,nr,addr) test_and_clear_bit((nr),(addr))
-# define ext2_test_bit(nr,addr) test_bit((nr), (addr))
-# define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr),(size))
-# define ext2_find_next_zero_bit(addr, size, offset) \
-                find_next_zero_bit((addr), (size), (offset))
 #elif defined(__XTENSA_EB__)
-# define ext2_set_bit(nr,addr) __test_and_set_bit((nr) ^ 0x18, (addr))
 # define ext2_set_bit_atomic(lock,nr,addr) test_and_set_bit((nr) ^ 0x18, (addr))
-# define ext2_clear_bit(nr,addr) __test_and_clear_bit((nr) ^ 18, (addr))
 # define ext2_clear_bit_atomic(lock,nr,addr) test_and_clear_bit((nr)^0x18,(addr))
-# define ext2_test_bit(nr,addr) test_bit((nr) ^ 0x18, (addr))
-# define ext2_find_first_zero_bit(addr, size) \
-        ext2_find_next_zero_bit((addr), (size), 0)
-
-static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
-{
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 31UL;
-	if(offset) {
-		/* We hold the little endian value in tmp, but then the
-		 * shift is illegal. So we could keep a big endian value
-		 * in tmp, like this:
-		 *
-		 * tmp = __swab32(*(p++));
-		 * tmp |= ~0UL >> (32-offset);
-		 *
-		 * but this would decrease preformance, so we change the
-		 * shift:
-		 */
-		tmp = *(p++);
-		tmp |= __swab32(~0UL >> (32-offset));
-		if(size < 32)
-			goto found_first;
-		if(~tmp)
-			goto found_middle;
-		size -= 32;
-		result += 32;
-	}
-	while(size & ~31UL) {
-		if(~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if(!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	/* tmp is little endian, so we would have to swab the shift,
-	 * see above. But then we have to swab tmp below for ffz, so
-	 * we might as well do this here.
-	 */
-	return result + ffz(__swab32(tmp) | (~0UL << size));
-found_middle:
-	return result + ffz(__swab32(tmp));
-}
-
 #else
 # error processor byte order undefined!
 #endif
 
-
-#define hweight32(x)	generic_hweight32(x)
-#define hweight16(x)	generic_hweight16(x)
-#define hweight8(x)	generic_hweight8(x)
-
-/*
- * Find the first bit set in a 140-bit bitmap.
- * The first 100 bits are unlikely to be set.
- */
-
-static inline int sched_find_first_bit(const unsigned long *b)
-{
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (b[3])
-		return __ffs(b[3]) + 96;
-	return __ffs(b[4]) + 128;
-}
-
-
-/* Bitmap functions for the minix filesystem.  */
-
-#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr) test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/minix.h>
 
 #endif	/* __KERNEL__ */
 
diff --git a/include/asm-xtensa/page.h b/include/asm-xtensa/page.h
index 8ded36f..992bac5 100644
--- a/include/asm-xtensa/page.h
+++ b/include/asm-xtensa/page.h
@@ -109,10 +109,7 @@
 #define __pa(x)			((unsigned long) (x) - PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long) (x) + PAGE_OFFSET))
 #define pfn_valid(pfn)		((unsigned long)pfn < max_mapnr)
-#ifndef CONFIG_DISCONTIGMEM
-# define pfn_to_page(pfn)	(mem_map + (pfn))
-# define page_to_pfn(page)	((unsigned long)((page) - mem_map))
-#else
+#ifdef CONFIG_DISCONTIGMEM
 # error CONFIG_DISCONTIGMEM not supported
 #endif
 
@@ -130,4 +127,5 @@
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #endif /* __KERNEL__ */
+#include <asm-generic/memory_model.h>
 #endif /* _XTENSA_PAGE_H */
diff --git a/include/linux/adb.h b/include/linux/adb.h
index e9fdc63..b7305b1 100644
--- a/include/linux/adb.h
+++ b/include/linux/adb.h
@@ -85,7 +85,7 @@
     ADB_MSG_POST_RESET	/* Called after resetting the bus (re-do init & register) */
 };
 extern struct adb_driver *adb_controller;
-extern struct notifier_block *adb_client_list;
+extern struct blocking_notifier_head adb_client_list;
 
 int adb_request(struct adb_request *req, void (*done)(struct adb_request *),
 		int flags, int nbytes, ...);
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index dc726ff..48ee32a 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -158,4 +158,10 @@
 #define UART01x_RSR_ANY		(UART01x_RSR_OE|UART01x_RSR_BE|UART01x_RSR_PE|UART01x_RSR_FE)
 #define UART01x_FR_MODEM_ANY	(UART01x_FR_DCD|UART01x_FR_DSR|UART01x_FR_CTS)
 
+#ifndef __ASSEMBLY__
+struct amba_pl010_data {
+	void (*set_mctrl)(struct amba_device *dev, void __iomem *base, unsigned int mctrl);
+};
+#endif
+
 #endif
diff --git a/include/linux/auto_fs4.h b/include/linux/auto_fs4.h
index 9343c89..0a6bc52 100644
--- a/include/linux/auto_fs4.h
+++ b/include/linux/auto_fs4.h
@@ -19,18 +19,37 @@
 #undef AUTOFS_MIN_PROTO_VERSION
 #undef AUTOFS_MAX_PROTO_VERSION
 
-#define AUTOFS_PROTO_VERSION		4
+#define AUTOFS_PROTO_VERSION		5
 #define AUTOFS_MIN_PROTO_VERSION	3
-#define AUTOFS_MAX_PROTO_VERSION	4
+#define AUTOFS_MAX_PROTO_VERSION	5
 
-#define AUTOFS_PROTO_SUBVERSION		7
+#define AUTOFS_PROTO_SUBVERSION		0
 
 /* Mask for expire behaviour */
 #define AUTOFS_EXP_IMMEDIATE		1
 #define AUTOFS_EXP_LEAVES		2
 
-/* New message type */
-#define autofs_ptype_expire_multi	2	/* Expire entry (umount request) */
+/* Daemon notification packet types */
+enum autofs_notify {
+	NFY_NONE,
+	NFY_MOUNT,
+	NFY_EXPIRE
+};
+
+/* Kernel protocol version 4 packet types */
+
+/* Expire entry (umount request) */
+#define autofs_ptype_expire_multi	2
+
+/* Kernel protocol version 5 packet types */
+
+/* Indirect mount missing and expire requests. */
+#define autofs_ptype_missing_indirect	3
+#define autofs_ptype_expire_indirect	4
+
+/* Direct mount missing and expire requests */
+#define autofs_ptype_missing_direct	5
+#define autofs_ptype_expire_direct	6
 
 /* v4 multi expire (via pipe) */
 struct autofs_packet_expire_multi {
@@ -40,14 +59,36 @@
 	char name[NAME_MAX+1];
 };
 
+/* autofs v5 common packet struct */
+struct autofs_v5_packet {
+	struct autofs_packet_hdr hdr;
+	autofs_wqt_t wait_queue_token;
+	__u32 dev;
+	__u64 ino;
+	__u32 uid;
+	__u32 gid;
+	__u32 pid;
+	__u32 tgid;
+	__u32 len;
+	char name[NAME_MAX+1];
+};
+
+typedef struct autofs_v5_packet autofs_packet_missing_indirect_t;
+typedef struct autofs_v5_packet autofs_packet_expire_indirect_t;
+typedef struct autofs_v5_packet autofs_packet_missing_direct_t;
+typedef struct autofs_v5_packet autofs_packet_expire_direct_t;
+
 union autofs_packet_union {
 	struct autofs_packet_hdr hdr;
 	struct autofs_packet_missing missing;
 	struct autofs_packet_expire expire;
 	struct autofs_packet_expire_multi expire_multi;
+	struct autofs_v5_packet v5_packet;
 };
 
 #define AUTOFS_IOC_EXPIRE_MULTI		_IOW(0x93,0x66,int)
+#define AUTOFS_IOC_EXPIRE_INDIRECT	AUTOFS_IOC_EXPIRE_MULTI
+#define AUTOFS_IOC_EXPIRE_DIRECT	AUTOFS_IOC_EXPIRE_MULTI
 #define AUTOFS_IOC_PROTOSUBVER		_IOR(0x93,0x67,int)
 #define AUTOFS_IOC_ASKREGHOST           _IOR(0x93,0x68,int)
 #define AUTOFS_IOC_TOGGLEREGHOST        _IOR(0x93,0x69,int)
diff --git a/include/linux/backlight.h b/include/linux/backlight.h
index bb9e543..75e91f5 100644
--- a/include/linux/backlight.h
+++ b/include/linux/backlight.h
@@ -19,20 +19,25 @@
 struct backlight_properties {
 	/* Owner module */
 	struct module *owner;
-	/* Get the backlight power status (0: full on, 1..3: power saving
-	   modes; 4: full off), see FB_BLANK_XXX */
-	int (*get_power)(struct backlight_device *);
-	/* Enable or disable power to the LCD (0: on; 4: off, see FB_BLANK_XXX) */
-	int (*set_power)(struct backlight_device *, int power);
-	/* Maximal value for brightness (read-only) */
-	int max_brightness;
-	/* Get current backlight brightness */
+
+	/* Notify the backlight driver some property has changed */
+	int (*update_status)(struct backlight_device *);
+	/* Return the current backlight brightness (accounting for power,
+	   fb_blank etc.) */
 	int (*get_brightness)(struct backlight_device *);
-	/* Set backlight brightness (0..max_brightness) */
-	int (*set_brightness)(struct backlight_device *, int brightness);
 	/* Check if given framebuffer device is the one bound to this backlight;
 	   return 0 if not, !=0 if it is. If NULL, backlight always matches the fb. */
 	int (*check_fb)(struct fb_info *);
+
+	/* Current User requested brightness (0 - max_brightness) */
+	int brightness;
+	/* Maximal value for brightness (read-only) */
+	int max_brightness;
+	/* Current FB Power mode (0: full on, 1..3: power saving
+	   modes; 4: full off), see FB_BLANK_XXX */
+	int power;
+	/* FB Blanking active? (values as for power) */
+	int fb_blank;
 };
 
 struct backlight_device {
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index f17525a..5d1eabc 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -3,88 +3,11 @@
 #include <asm/types.h>
 
 /*
- * ffs: find first bit set. This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
- */
-
-static inline int generic_ffs(int x)
-{
-	int r = 1;
-
-	if (!x)
-		return 0;
-	if (!(x & 0xffff)) {
-		x >>= 16;
-		r += 16;
-	}
-	if (!(x & 0xff)) {
-		x >>= 8;
-		r += 8;
-	}
-	if (!(x & 0xf)) {
-		x >>= 4;
-		r += 4;
-	}
-	if (!(x & 3)) {
-		x >>= 2;
-		r += 2;
-	}
-	if (!(x & 1)) {
-		x >>= 1;
-		r += 1;
-	}
-	return r;
-}
-
-/*
- * fls: find last bit set.
- */
-
-static __inline__ int generic_fls(int x)
-{
-	int r = 32;
-
-	if (!x)
-		return 0;
-	if (!(x & 0xffff0000u)) {
-		x <<= 16;
-		r -= 16;
-	}
-	if (!(x & 0xff000000u)) {
-		x <<= 8;
-		r -= 8;
-	}
-	if (!(x & 0xf0000000u)) {
-		x <<= 4;
-		r -= 4;
-	}
-	if (!(x & 0xc0000000u)) {
-		x <<= 2;
-		r -= 2;
-	}
-	if (!(x & 0x80000000u)) {
-		x <<= 1;
-		r -= 1;
-	}
-	return r;
-}
-
-/*
  * Include this here because some architectures need generic_ffs/fls in
  * scope
  */
 #include <asm/bitops.h>
 
-
-static inline int generic_fls64(__u64 x)
-{
-	__u32 h = x >> 32;
-	if (h)
-		return fls(h) + 32;
-	return fls(x);
-}
-
 static __inline__ int get_bitmask_order(unsigned int count)
 {
 	int order;
@@ -103,54 +26,9 @@
 	return order;
 }
 
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-static inline unsigned int generic_hweight32(unsigned int w)
-{
-        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
-        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
-        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
-        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
-        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
-}
-
-static inline unsigned int generic_hweight16(unsigned int w)
-{
-        unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
-        res = (res & 0x3333) + ((res >> 2) & 0x3333);
-        res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
-        return (res & 0x00FF) + ((res >> 8) & 0x00FF);
-}
-
-static inline unsigned int generic_hweight8(unsigned int w)
-{
-        unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
-        res = (res & 0x33) + ((res >> 2) & 0x33);
-        return (res & 0x0F) + ((res >> 4) & 0x0F);
-}
-
-static inline unsigned long generic_hweight64(__u64 w)
-{
-#if BITS_PER_LONG < 64
-	return generic_hweight32((unsigned int)(w >> 32)) +
-				generic_hweight32((unsigned int)w);
-#else
-	u64 res;
-	res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul);
-	res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
-	res = (res & 0x0F0F0F0F0F0F0F0Ful) + ((res >> 4) & 0x0F0F0F0F0F0F0F0Ful);
-	res = (res & 0x00FF00FF00FF00FFul) + ((res >> 8) & 0x00FF00FF00FF00FFul);
-	res = (res & 0x0000FFFF0000FFFFul) + ((res >> 16) & 0x0000FFFF0000FFFFul);
-	return (res & 0x00000000FFFFFFFFul) + ((res >> 32) & 0x00000000FFFFFFFFul);
-#endif
-}
-
 static inline unsigned long hweight_long(unsigned long w)
 {
-	return sizeof(w) == 4 ? generic_hweight32(w) : generic_hweight64(w);
+	return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
 }
 
 /*
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index c179966..d0cac8b 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -55,25 +55,29 @@
 
 struct cfq_queue;
 struct cfq_io_context {
-	/*
-	 * circular list of cfq_io_contexts belonging to a process io context
-	 */
-	struct list_head list;
-	struct cfq_queue *cfqq[2];
+	struct rb_node rb_node;
 	void *key;
 
+	struct cfq_queue *cfqq[2];
+
 	struct io_context *ioc;
 
 	unsigned long last_end_request;
-	unsigned long last_queue;
+	sector_t last_request_pos;
+ 	unsigned long last_queue;
+
 	unsigned long ttime_total;
 	unsigned long ttime_samples;
 	unsigned long ttime_mean;
 
+	unsigned int seek_samples;
+	u64 seek_total;
+	sector_t seek_mean;
+
 	struct list_head queue_list;
 
-	void (*dtor)(struct cfq_io_context *);
-	void (*exit)(struct cfq_io_context *);
+	void (*dtor)(struct io_context *); /* destructor */
+	void (*exit)(struct io_context *); /* called on task exit */
 };
 
 /*
@@ -94,7 +98,7 @@
 	int nr_batch_requests;     /* Number of requests left in the batch */
 
 	struct as_io_context *aic;
-	struct cfq_io_context *cic;
+	struct rb_root cic_root;
 };
 
 void put_io_context(struct io_context *ioc);
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index 7155452..de3eb8d 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -38,6 +38,7 @@
 	unsigned long last_pos;
 	unsigned long last_success;	/* Previous allocation point.  To speed
 					 * up searching */
+	struct list_head list;
 } bootmem_data_t;
 
 extern unsigned long __init bootmem_bootmap_pages (unsigned long);
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 9f159ba..fb7e9b7 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -46,25 +46,28 @@
 typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
 
 /*
- * Keep related fields in common cachelines.  The most commonly accessed
- * field (b_state) goes at the start so the compiler does not generate
- * indexed addressing for it.
+ * Historically, a buffer_head was used to map a single block
+ * within a page, and of course as the unit of I/O through the
+ * filesystem and block layers.  Nowadays the basic I/O unit
+ * is the bio, and buffer_heads are used for extracting block
+ * mappings (via a get_block_t call), for tracking state within
+ * a page (via a page_mapping) and for wrapping bio submission
+ * for backward compatibility reasons (e.g. submit_bh).
  */
 struct buffer_head {
-	/* First cache line: */
 	unsigned long b_state;		/* buffer state bitmap (see above) */
 	struct buffer_head *b_this_page;/* circular list of page's buffers */
 	struct page *b_page;		/* the page this bh is mapped to */
-	atomic_t b_count;		/* users using this block */
-	u32 b_size;			/* block size */
 
-	sector_t b_blocknr;		/* block number */
-	char *b_data;			/* pointer to data block */
+	sector_t b_blocknr;		/* start block number */
+	size_t b_size;			/* size of mapping */
+	char *b_data;			/* pointer to data within the page */
 
 	struct block_device *b_bdev;
 	bh_end_io_t *b_end_io;		/* I/O completion */
  	void *b_private;		/* reserved for b_end_io */
 	struct list_head b_assoc_buffers; /* associated with another mapping */
+	atomic_t b_count;		/* users using this buffer_head */
 };
 
 /*
@@ -189,8 +192,8 @@
  * address_spaces.
  */
 int try_to_release_page(struct page * page, gfp_t gfp_mask);
-int block_invalidatepage(struct page *page, unsigned long offset);
-int do_invalidatepage(struct page *page, unsigned long offset);
+void block_invalidatepage(struct page *page, unsigned long offset);
+void do_invalidatepage(struct page *page, unsigned long offset);
 int block_write_full_page(struct page *page, get_block_t *get_block,
 				struct writeback_control *wbc);
 int block_read_full_page(struct page*, get_block_t*);
@@ -200,7 +203,7 @@
 int generic_cont_expand(struct inode *inode, loff_t size);
 int generic_cont_expand_simple(struct inode *inode, loff_t size);
 int block_commit_write(struct page *page, unsigned from, unsigned to);
-int block_sync_page(struct page *);
+void block_sync_page(struct page *);
 sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
 int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
 int block_truncate_page(struct address_space *, loff_t, get_block_t *);
@@ -277,6 +280,7 @@
 	set_buffer_mapped(bh);
 	bh->b_bdev = sb->s_bdev;
 	bh->b_blocknr = block;
+	bh->b_size = sb->s_blocksize;
 }
 
 /*
diff --git a/include/linux/cdev.h b/include/linux/cdev.h
index 8da37e2..2216638 100644
--- a/include/linux/cdev.h
+++ b/include/linux/cdev.h
@@ -5,13 +5,13 @@
 struct cdev {
 	struct kobject kobj;
 	struct module *owner;
-	struct file_operations *ops;
+	const struct file_operations *ops;
 	struct list_head list;
 	dev_t dev;
 	unsigned int count;
 };
 
-void cdev_init(struct cdev *, struct file_operations *);
+void cdev_init(struct cdev *, const struct file_operations *);
 
 struct cdev *cdev_alloc(void);
 
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index cc621ec..b3ecf8f 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -30,9 +30,9 @@
 extern struct address_space_operations coda_file_aops;
 extern struct address_space_operations coda_symlink_aops;
 
-extern struct file_operations coda_dir_operations;
-extern struct file_operations coda_file_operations;
-extern struct file_operations coda_ioctl_operations;
+extern const struct file_operations coda_dir_operations;
+extern const struct file_operations coda_file_operations;
+extern const struct file_operations coda_ioctl_operations;
 
 /* operations shared over more than one file */
 int coda_open(struct inode *i, struct file *f);
diff --git a/include/linux/compat.h b/include/linux/compat.h
index c9ab2a2..6d3a654 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -45,6 +45,32 @@
 	compat_clock_t		tms_cstime;
 };
 
+struct compat_timex {
+	compat_uint_t modes;
+	compat_long_t offset;
+	compat_long_t freq;
+	compat_long_t maxerror;
+	compat_long_t esterror;
+	compat_int_t status;
+	compat_long_t constant;
+	compat_long_t precision;
+	compat_long_t tolerance;
+	struct compat_timeval time;
+	compat_long_t tick;
+	compat_long_t ppsfreq;
+	compat_long_t jitter;
+	compat_int_t shift;
+	compat_long_t stabil;
+	compat_long_t jitcnt;
+	compat_long_t calcnt;
+	compat_long_t errcnt;
+	compat_long_t stbcnt;
+
+	compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
+	compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
+	compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
+};
+
 #define _COMPAT_NSIG_WORDS	(_COMPAT_NSIG / _COMPAT_NSIG_BPW)
 
 typedef struct {
@@ -121,6 +147,24 @@
 	} _sigev_un;
 } compat_sigevent_t;
 
+struct compat_robust_list {
+	compat_uptr_t			next;
+};
+
+struct compat_robust_list_head {
+	struct compat_robust_list	list;
+	compat_long_t			futex_offset;
+	compat_uptr_t			list_op_pending;
+};
+
+extern void compat_exit_robust_list(struct task_struct *curr);
+
+asmlinkage long
+compat_sys_set_robust_list(struct compat_robust_list_head __user *head,
+			   compat_size_t len);
+asmlinkage long
+compat_sys_get_robust_list(int pid, compat_uptr_t *head_ptr,
+			   compat_size_t __user *len_ptr);
 
 long compat_sys_semctl(int first, int second, int third, void __user *uptr);
 long compat_sys_msgsnd(int first, int second, int third, void __user *uptr);
@@ -181,5 +225,7 @@
 	return lhs->tv_nsec - rhs->tv_nsec;
 }
 
+asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
index efb518f..89ab677 100644
--- a/include/linux/compat_ioctl.h
+++ b/include/linux/compat_ioctl.h
@@ -140,6 +140,7 @@
 COMPATIBLE_IOCTL(DM_TABLE_STATUS_32)
 COMPATIBLE_IOCTL(DM_LIST_VERSIONS_32)
 COMPATIBLE_IOCTL(DM_TARGET_MSG_32)
+COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY_32)
 COMPATIBLE_IOCTL(DM_VERSION)
 COMPATIBLE_IOCTL(DM_REMOVE_ALL)
 COMPATIBLE_IOCTL(DM_LIST_DEVICES)
@@ -155,6 +156,7 @@
 COMPATIBLE_IOCTL(DM_TABLE_STATUS)
 COMPATIBLE_IOCTL(DM_LIST_VERSIONS)
 COMPATIBLE_IOCTL(DM_TARGET_MSG)
+COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY)
 /* Big K */
 COMPATIBLE_IOCTL(PIO_FONT)
 COMPATIBLE_IOCTL(GIO_FONT)
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index 99e6115..9cbb781 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -67,7 +67,7 @@
  *
  * int any_online_cpu(mask)		First online cpu in mask
  *
- * for_each_cpu(cpu)			for-loop cpu over cpu_possible_map
+ * for_each_possible_cpu(cpu)		for-loop cpu over cpu_possible_map
  * for_each_online_cpu(cpu)		for-loop cpu over cpu_online_map
  * for_each_present_cpu(cpu)		for-loop cpu over cpu_present_map
  *
@@ -405,7 +405,8 @@
 #define any_online_cpu(mask)		0
 #endif
 
-#define for_each_cpu(cpu)	  for_each_cpu_mask((cpu), cpu_possible_map)
+#define for_each_cpu(cpu)  for_each_cpu_mask((cpu), cpu_possible_map)
+#define for_each_possible_cpu(cpu)  for_each_cpu_mask((cpu), cpu_possible_map)
 #define for_each_online_cpu(cpu)  for_each_cpu_mask((cpu), cpu_online_map)
 #define for_each_present_cpu(cpu) for_each_cpu_mask((cpu), cpu_present_map)
 
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
index 534d750..3250365 100644
--- a/include/linux/crash_dump.h
+++ b/include/linux/crash_dump.h
@@ -11,7 +11,7 @@
 extern unsigned long long elfcorehdr_addr;
 extern ssize_t copy_oldmem_page(unsigned long, char *, size_t,
 						unsigned long, int);
-extern struct file_operations proc_vmcore_operations;
+extern const struct file_operations proc_vmcore_operations;
 extern struct proc_dir_entry *proc_vmcore;
 
 #endif /* CONFIG_CRASH_DUMP */
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index d10bd30..836325e 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -275,6 +275,7 @@
 /* appendix may either be NULL or be used for transname suffixes */
 extern struct dentry * d_lookup(struct dentry *, struct qstr *);
 extern struct dentry * __d_lookup(struct dentry *, struct qstr *);
+extern struct dentry * d_hash_and_lookup(struct dentry *, struct qstr *);
 
 /* validate "insecure" dentry pointer */
 extern int d_validate(struct dentry *, struct dentry *);
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index 4b0428e..176e2d3 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -29,7 +29,7 @@
 #if defined(CONFIG_DEBUG_FS)
 struct dentry *debugfs_create_file(const char *name, mode_t mode,
 				   struct dentry *parent, void *data,
-				   struct file_operations *fops);
+				   const struct file_operations *fops);
 
 struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
 
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 51e0e95..aee10b2 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -97,6 +97,7 @@
 	unsigned short		hardsect_size;
 	unsigned int		max_segment_size;
 	unsigned long		seg_boundary_mask;
+	unsigned char		no_cluster; /* inverted so that 0 is default */
 };
 
 struct dm_target {
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h
index fa75ba0..c67c678 100644
--- a/include/linux/dm-ioctl.h
+++ b/include/linux/dm-ioctl.h
@@ -80,6 +80,16 @@
  *
  * DM_TARGET_MSG:
  * Pass a message string to the target at a specific offset of a device.
+ *
+ * DM_DEV_SET_GEOMETRY:
+ * Set the geometry of a device by passing in a string in this format:
+ *
+ * "cylinders heads sectors_per_track start_sector"
+ *
+ * Beware that CHS geometry is nearly obsolete and only provided
+ * for compatibility with dm devices that can be booted by a PC
+ * BIOS.  See struct hd_geometry for range limits.  Also note that
+ * the geometry is erased if the device size changes.
  */
 
 /*
@@ -218,6 +228,7 @@
 	/* Added later */
 	DM_LIST_VERSIONS_CMD,
 	DM_TARGET_MSG_CMD,
+	DM_DEV_SET_GEOMETRY_CMD
 };
 
 /*
@@ -247,6 +258,7 @@
 #define DM_TABLE_STATUS_32  _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, ioctl_struct)
 #define DM_LIST_VERSIONS_32 _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, ioctl_struct)
 #define DM_TARGET_MSG_32    _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, ioctl_struct)
+#define DM_DEV_SET_GEOMETRY_32	_IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, ioctl_struct)
 #endif
 
 #define DM_IOCTL 0xfd
@@ -270,11 +282,12 @@
 #define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl)
 
 #define DM_TARGET_MSG	 _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl)
+#define DM_DEV_SET_GEOMETRY	_IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR	4
-#define DM_VERSION_MINOR	5
+#define DM_VERSION_MINOR	6
 #define DM_VERSION_PATCHLEVEL	0
-#define DM_VERSION_EXTRA	"-ioctl (2005-10-04)"
+#define DM_VERSION_EXTRA	"-ioctl (2006-02-17)"
 
 /* Status bits */
 #define DM_READONLY_FLAG	(1 << 0) /* In/Out */
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index a873106..9b4751a 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -21,6 +21,7 @@
 #define DMA_30BIT_MASK	0x000000003fffffffULL
 #define DMA_29BIT_MASK	0x000000001fffffffULL
 #define DMA_28BIT_MASK	0x000000000fffffffULL
+#define DMA_24BIT_MASK 0x0000000000ffffffULL
 
 #include <asm/dma-mapping.h>
 
diff --git a/include/linux/efi.h b/include/linux/efi.h
index c7c5dd3..e203613 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -240,19 +240,21 @@
 	unsigned long desc_size;
 };
 
+#define EFI_INVALID_TABLE_ADDR		(~0UL)
+
 /*
  * All runtime access to EFI goes through this structure:
  */
 extern struct efi {
 	efi_system_table_t *systab;	/* EFI system table */
-	void *mps;			/* MPS table */
-	void *acpi;			/* ACPI table  (IA64 ext 0.71) */
-	void *acpi20;			/* ACPI table  (ACPI 2.0) */
-	void *smbios;			/* SM BIOS table */
-	void *sal_systab;		/* SAL system table */
-	void *boot_info;		/* boot info table */
-	void *hcdp;			/* HCDP table */
-	void *uga;			/* UGA table */
+	unsigned long mps;		/* MPS table */
+	unsigned long acpi;		/* ACPI table  (IA64 ext 0.71) */
+	unsigned long acpi20;		/* ACPI table  (ACPI 2.0) */
+	unsigned long smbios;		/* SM BIOS table */
+	unsigned long sal_systab;	/* SAL system table */
+	unsigned long boot_info;	/* boot info table */
+	unsigned long hcdp;		/* HCDP table */
+	unsigned long uga;		/* UGA table */
 	efi_get_time_t *get_time;
 	efi_set_time_t *set_time;
 	efi_get_wakeup_time_t *get_wakeup_time;
@@ -292,6 +294,8 @@
 extern u64 efi_get_iobase (void);
 extern u32 efi_mem_type (unsigned long phys_addr);
 extern u64 efi_mem_attributes (unsigned long phys_addr);
+extern int efi_mem_attribute_range (unsigned long phys_addr, unsigned long size,
+				    u64 attr);
 extern int __init efi_uart_console_only (void);
 extern void efi_initialize_iomem_resources(struct resource *code_resource,
 					struct resource *data_resource);
diff --git a/include/linux/efs_fs.h b/include/linux/efs_fs.h
index 28f368c..fbfa6b5 100644
--- a/include/linux/efs_fs.h
+++ b/include/linux/efs_fs.h
@@ -37,7 +37,7 @@
 struct statfs;
 
 extern struct inode_operations efs_dir_inode_operations;
-extern struct file_operations efs_dir_operations;
+extern const struct file_operations efs_dir_operations;
 extern struct address_space_operations efs_symlink_aops;
 
 extern void efs_read_inode(struct inode *);
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index e7239f2..3ade6a4 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -36,7 +36,8 @@
  * Define EXT3_RESERVATION to reserve data blocks for expanding files
  */
 #define EXT3_DEFAULT_RESERVE_BLOCKS     8
-#define EXT3_MAX_RESERVE_BLOCKS         1024
+/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */
+#define EXT3_MAX_RESERVE_BLOCKS         1027
 #define EXT3_RESERVE_WINDOW_NOT_ALLOCATED 0
 /*
  * Always enable hashed directories
@@ -732,6 +733,8 @@
 extern int ext3_bg_has_super(struct super_block *sb, int group);
 extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
 extern int ext3_new_block (handle_t *, struct inode *, unsigned long, int *);
+extern int ext3_new_blocks (handle_t *, struct inode *, unsigned long,
+			unsigned long *, int *);
 extern void ext3_free_blocks (handle_t *, struct inode *, unsigned long,
 			      unsigned long);
 extern void ext3_free_blocks_sb (handle_t *, struct super_block *,
@@ -775,9 +778,9 @@
 int ext3_forget(handle_t *, int, struct inode *, struct buffer_head *, int);
 struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
 struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
-int ext3_get_block_handle(handle_t *handle, struct inode *inode,
-	sector_t iblock, struct buffer_head *bh_result, int create,
-	int extend_disksize);
+int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
+	sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result,
+	int create, int extend_disksize);
 
 extern void ext3_read_inode (struct inode *);
 extern int  ext3_write_inode (struct inode *, int);
@@ -830,11 +833,11 @@
  */
 
 /* dir.c */
-extern struct file_operations ext3_dir_operations;
+extern const struct file_operations ext3_dir_operations;
 
 /* file.c */
 extern struct inode_operations ext3_file_inode_operations;
-extern struct file_operations ext3_file_operations;
+extern const struct file_operations ext3_file_operations;
 
 /* namei.c */
 extern struct inode_operations ext3_dir_inode_operations;
diff --git a/include/linux/fadvise.h b/include/linux/fadvise.h
index b2913bb..e8e7471 100644
--- a/include/linux/fadvise.h
+++ b/include/linux/fadvise.h
@@ -18,10 +18,4 @@
 #define POSIX_FADV_NOREUSE	5 /* Data will be accessed once.  */
 #endif
 
-/*
- * Linux-specific fadvise() extensions:
- */
-#define LINUX_FADV_ASYNC_WRITE	32	/* Start writeout on range */
-#define LINUX_FADV_WRITE_WAIT	33	/* Wait upon writeout to range */
-
 #endif	/* FADVISE_H_INCLUDED */
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 2cb19e6..315d897 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -734,7 +734,7 @@
 
 /* A driver may set this flag to indicate that it does want a set_par to be
  * called every time when fbcon_switch is executed. The advantage is that with
- * this flag set you can really be shure that set_par is always called before
+ * this flag set you can really be sure that set_par is always called before
  * any of the functions dependant on the correct hardware state or altering
  * that state, even if you are using some broken X releases. The disadvantage
  * is that it introduces unwanted delays to every console switch if set_par
@@ -839,12 +839,10 @@
 #define FB_LEFT_POS(bpp)          (32 - bpp)
 #define FB_SHIFT_HIGH(val, bits)  ((val) >> (bits))
 #define FB_SHIFT_LOW(val, bits)   ((val) << (bits))
-#define FB_BIT_NR(b)              (7 - (b))
 #else
 #define FB_LEFT_POS(bpp)          (0)
 #define FB_SHIFT_HIGH(val, bits)  ((val) << (bits))
 #define FB_SHIFT_LOW(val, bits)   ((val) >> (bits))
-#define FB_BIT_NR(b)              (b)
 #endif
 
     /*
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 5adf32b..4ed7e60 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -252,9 +252,6 @@
 struct buffer_head;
 typedef int (get_block_t)(struct inode *inode, sector_t iblock,
 			struct buffer_head *bh_result, int create);
-typedef int (get_blocks_t)(struct inode *inode, sector_t iblock,
-			unsigned long max_blocks,
-			struct buffer_head *bh_result, int create);
 typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 			ssize_t bytes, void *private);
 
@@ -350,7 +347,7 @@
 struct address_space_operations {
 	int (*writepage)(struct page *page, struct writeback_control *wbc);
 	int (*readpage)(struct file *, struct page *);
-	int (*sync_page)(struct page *);
+	void (*sync_page)(struct page *);
 
 	/* Write back some dirty pages from this mapping. */
 	int (*writepages)(struct address_space *, struct writeback_control *);
@@ -369,7 +366,7 @@
 	int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
 	/* Unfortunately this kludge is needed for FIBMAP. Don't use it */
 	sector_t (*bmap)(struct address_space *, sector_t);
-	int (*invalidatepage) (struct page *, unsigned long);
+	void (*invalidatepage) (struct page *, unsigned long);
 	int (*releasepage) (struct page *, gfp_t);
 	ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
 			loff_t offset, unsigned long nr_segs);
@@ -413,6 +410,9 @@
 	struct list_head	bd_inodes;
 	void *			bd_holder;
 	int			bd_holders;
+#ifdef CONFIG_SYSFS
+	struct list_head	bd_holder_list;
+#endif
 	struct block_device *	bd_contains;
 	unsigned		bd_block_size;
 	struct hd_struct *	bd_part;
@@ -490,13 +490,13 @@
 	unsigned int		i_blkbits;
 	unsigned long		i_blksize;
 	unsigned long		i_version;
-	unsigned long		i_blocks;
+	blkcnt_t		i_blocks;
 	unsigned short          i_bytes;
 	spinlock_t		i_lock;	/* i_blocks, i_bytes, maybe i_size */
 	struct mutex		i_mutex;
 	struct rw_semaphore	i_alloc_sem;
 	struct inode_operations	*i_op;
-	struct file_operations	*i_fop;	/* former ->i_op->default_file_ops */
+	const struct file_operations	*i_fop;	/* former ->i_op->default_file_ops */
 	struct super_block	*i_sb;
 	struct file_lock	*i_flock;
 	struct address_space	*i_mapping;
@@ -636,7 +636,7 @@
 	} f_u;
 	struct dentry		*f_dentry;
 	struct vfsmount         *f_vfsmnt;
-	struct file_operations	*f_op;
+	const struct file_operations	*f_op;
 	atomic_t		f_count;
 	unsigned int 		f_flags;
 	mode_t			f_mode;
@@ -757,12 +757,20 @@
 extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
 extern int fcntl_getlease(struct file *filp);
 
+/* fs/sync.c */
+#define SYNC_FILE_RANGE_WAIT_BEFORE	1
+#define SYNC_FILE_RANGE_WRITE		2
+#define SYNC_FILE_RANGE_WAIT_AFTER	4
+extern int do_sync_file_range(struct file *file, loff_t offset, loff_t endbyte,
+			int flags);
+
 /* fs/locks.c */
 extern void locks_init_lock(struct file_lock *);
 extern void locks_copy_lock(struct file_lock *, struct file_lock *);
 extern void locks_remove_posix(struct file *, fl_owner_t);
 extern void locks_remove_flock(struct file *);
 extern int posix_test_lock(struct file *, struct file_lock *, struct file_lock *);
+extern int posix_lock_file_conf(struct file *, struct file_lock *, struct file_lock *);
 extern int posix_lock_file(struct file *, struct file_lock *);
 extern int posix_lock_file_wait(struct file *, struct file_lock *);
 extern int posix_unblock_lock(struct file *, struct file_lock *);
@@ -1031,6 +1039,8 @@
 	int (*check_flags)(int);
 	int (*dir_notify)(struct file *filp, unsigned long arg);
 	int (*flock) (struct file *, int, struct file_lock *);
+	ssize_t (*splice_write)(struct inode *, struct file *, size_t, unsigned int);
+	ssize_t (*splice_read)(struct file *, struct inode *, size_t, unsigned int);
 };
 
 struct inode_operations {
@@ -1389,11 +1399,11 @@
 extern void bd_forget(struct inode *inode);
 extern void bdput(struct block_device *);
 extern struct block_device *open_by_devnum(dev_t, unsigned);
-extern struct file_operations def_blk_fops;
+extern const struct file_operations def_blk_fops;
 extern struct address_space_operations def_blk_aops;
-extern struct file_operations def_chr_fops;
-extern struct file_operations bad_sock_fops;
-extern struct file_operations def_fifo_fops;
+extern const struct file_operations def_chr_fops;
+extern const struct file_operations bad_sock_fops;
+extern const struct file_operations def_fifo_fops;
 extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
 extern int blkdev_ioctl(struct inode *, struct file *, unsigned, unsigned long);
 extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long);
@@ -1401,34 +1411,34 @@
 extern int blkdev_put(struct block_device *);
 extern int bd_claim(struct block_device *, void *);
 extern void bd_release(struct block_device *);
+#ifdef CONFIG_SYSFS
+extern int bd_claim_by_disk(struct block_device *, void *, struct gendisk *);
+extern void bd_release_from_disk(struct block_device *, struct gendisk *);
+#else
+#define bd_claim_by_disk(bdev, holder, disk)	bd_claim(bdev, holder)
+#define bd_release_from_disk(bdev, disk)	bd_release(bdev)
+#endif
 
 /* fs/char_dev.c */
+#define CHRDEV_MAJOR_HASH_SIZE	255
 extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);
 extern int register_chrdev_region(dev_t, unsigned, const char *);
 extern int register_chrdev(unsigned int, const char *,
-			   struct file_operations *);
+			   const struct file_operations *);
 extern int unregister_chrdev(unsigned int, const char *);
 extern void unregister_chrdev_region(dev_t, unsigned);
 extern int chrdev_open(struct inode *, struct file *);
-extern int get_chrdev_list(char *);
-extern void *acquire_chrdev_list(void);
-extern int count_chrdev_list(void);
-extern void *get_next_chrdev(void *);
-extern int get_chrdev_info(void *, int *, char **);
-extern void release_chrdev_list(void *);
+extern void chrdev_show(struct seq_file *,off_t);
 
 /* fs/block_dev.c */
+#define BLKDEV_MAJOR_HASH_SIZE	255
 #define BDEVNAME_SIZE	32	/* Largest string for a blockdev identifier */
 extern const char *__bdevname(dev_t, char *buffer);
 extern const char *bdevname(struct block_device *bdev, char *buffer);
 extern struct block_device *lookup_bdev(const char *);
 extern struct block_device *open_bdev_excl(const char *, int, void *);
 extern void close_bdev_excl(struct block_device *);
-extern void *acquire_blkdev_list(void);
-extern int count_blkdev_list(void);
-extern void *get_next_blkdev(void *);
-extern int get_blkdev_info(void *, int *, char **);
-extern void release_blkdev_list(void *);
+extern void blkdev_show(struct seq_file *,off_t);
 
 extern void init_special_inode(struct inode *, umode_t, dev_t);
 
@@ -1436,9 +1446,9 @@
 extern void make_bad_inode(struct inode *);
 extern int is_bad_inode(struct inode *);
 
-extern struct file_operations read_fifo_fops;
-extern struct file_operations write_fifo_fops;
-extern struct file_operations rdwr_fifo_fops;
+extern const struct file_operations read_fifo_fops;
+extern const struct file_operations write_fifo_fops;
+extern const struct file_operations rdwr_fifo_fops;
 
 extern int fs_may_remount_ro(struct super_block *);
 
@@ -1601,6 +1611,8 @@
 extern void do_generic_mapping_read(struct address_space *mapping,
 				    struct file_ra_state *, struct file *,
 				    loff_t *, read_descriptor_t *, read_actor_t);
+extern ssize_t generic_file_splice_read(struct file *, struct inode *, size_t, unsigned int);
+extern ssize_t generic_file_splice_write(struct inode *, struct file *, size_t, unsigned int);
 extern void
 file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
 extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov, 
@@ -1644,7 +1656,7 @@
 
 ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
 	struct block_device *bdev, const struct iovec *iov, loff_t offset,
-	unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io,
+	unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
 	int lock_type);
 
 enum {
@@ -1655,32 +1667,32 @@
 
 static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb,
 	struct inode *inode, struct block_device *bdev, const struct iovec *iov,
-	loff_t offset, unsigned long nr_segs, get_blocks_t get_blocks,
+	loff_t offset, unsigned long nr_segs, get_block_t get_block,
 	dio_iodone_t end_io)
 {
 	return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
-				nr_segs, get_blocks, end_io, DIO_LOCKING);
+				nr_segs, get_block, end_io, DIO_LOCKING);
 }
 
 static inline ssize_t blockdev_direct_IO_no_locking(int rw, struct kiocb *iocb,
 	struct inode *inode, struct block_device *bdev, const struct iovec *iov,
-	loff_t offset, unsigned long nr_segs, get_blocks_t get_blocks,
+	loff_t offset, unsigned long nr_segs, get_block_t get_block,
 	dio_iodone_t end_io)
 {
 	return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
-				nr_segs, get_blocks, end_io, DIO_NO_LOCKING);
+				nr_segs, get_block, end_io, DIO_NO_LOCKING);
 }
 
 static inline ssize_t blockdev_direct_IO_own_locking(int rw, struct kiocb *iocb,
 	struct inode *inode, struct block_device *bdev, const struct iovec *iov,
-	loff_t offset, unsigned long nr_segs, get_blocks_t get_blocks,
+	loff_t offset, unsigned long nr_segs, get_block_t get_block,
 	dio_iodone_t end_io)
 {
 	return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
-				nr_segs, get_blocks, end_io, DIO_OWN_LOCKING);
+				nr_segs, get_block, end_io, DIO_OWN_LOCKING);
 }
 
-extern struct file_operations generic_ro_fops;
+extern const struct file_operations generic_ro_fops;
 
 #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
 
@@ -1736,9 +1748,9 @@
 
 extern struct dentry *simple_lookup(struct inode *, struct dentry *, struct nameidata *);
 extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *);
-extern struct file_operations simple_dir_operations;
+extern const struct file_operations simple_dir_operations;
 extern struct inode_operations simple_dir_inode_operations;
-struct tree_descr { char *name; struct file_operations *ops; int mode; };
+struct tree_descr { char *name; const struct file_operations *ops; int mode; };
 struct dentry *d_alloc_name(struct dentry *, const char *);
 extern int simple_fill_super(struct super_block *, int, struct tree_descr *);
 extern int simple_pin_fs(char *name, struct vfsmount **mount, int *count);
diff --git a/include/linux/futex.h b/include/linux/futex.h
index 10f96c3..966a5b3 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -1,6 +1,8 @@
 #ifndef _LINUX_FUTEX_H
 #define _LINUX_FUTEX_H
 
+#include <linux/sched.h>
+
 /* Second argument to futex syscall */
 
 
@@ -11,10 +13,97 @@
 #define FUTEX_CMP_REQUEUE	4
 #define FUTEX_WAKE_OP		5
 
+/*
+ * Support for robust futexes: the kernel cleans up held futexes at
+ * thread exit time.
+ */
+
+/*
+ * Per-lock list entry - embedded in user-space locks, somewhere close
+ * to the futex field. (Note: user-space uses a double-linked list to
+ * achieve O(1) list add and remove, but the kernel only needs to know
+ * about the forward link)
+ *
+ * NOTE: this structure is part of the syscall ABI, and must not be
+ * changed.
+ */
+struct robust_list {
+	struct robust_list __user *next;
+};
+
+/*
+ * Per-thread list head:
+ *
+ * NOTE: this structure is part of the syscall ABI, and must only be
+ * changed if the change is first communicated with the glibc folks.
+ * (When an incompatible change is done, we'll increase the structure
+ *  size, which glibc will detect)
+ */
+struct robust_list_head {
+	/*
+	 * The head of the list. Points back to itself if empty:
+	 */
+	struct robust_list list;
+
+	/*
+	 * This relative offset is set by user-space, it gives the kernel
+	 * the relative position of the futex field to examine. This way
+	 * we keep userspace flexible, to freely shape its data-structure,
+	 * without hardcoding any particular offset into the kernel:
+	 */
+	long futex_offset;
+
+	/*
+	 * The death of the thread may race with userspace setting
+	 * up a lock's links. So to handle this race, userspace first
+	 * sets this field to the address of the to-be-taken lock,
+	 * then does the lock acquire, and then adds itself to the
+	 * list, and then clears this field. Hence the kernel will
+	 * always have full knowledge of all locks that the thread
+	 * _might_ have taken. We check the owner TID in any case,
+	 * so only truly owned locks will be handled.
+	 */
+	struct robust_list __user *list_op_pending;
+};
+
+/*
+ * Are there any waiters for this robust futex:
+ */
+#define FUTEX_WAITERS		0x80000000
+
+/*
+ * The kernel signals via this bit that a thread holding a futex
+ * has exited without unlocking the futex. The kernel also does
+ * a FUTEX_WAKE on such futexes, after setting the bit, to wake
+ * up any possible waiters:
+ */
+#define FUTEX_OWNER_DIED	0x40000000
+
+/*
+ * The rest of the robust-futex field is for the TID:
+ */
+#define FUTEX_TID_MASK		0x3fffffff
+
+/*
+ * This limit protects against a deliberately circular list.
+ * (Not worth introducing an rlimit for it)
+ */
+#define ROBUST_LIST_LIMIT	2048
+
 long do_futex(unsigned long uaddr, int op, int val,
 		unsigned long timeout, unsigned long uaddr2, int val2,
 		int val3);
 
+extern int handle_futex_death(u32 __user *uaddr, struct task_struct *curr);
+
+#ifdef CONFIG_FUTEX
+extern void exit_robust_list(struct task_struct *curr);
+#else
+static inline void exit_robust_list(struct task_struct *curr)
+{
+}
+#endif
+
 #define FUTEX_OP_SET		0	/* *(int *)UADDR2 = OPARG; */
 #define FUTEX_OP_ADD		1	/* *(int *)UADDR2 += OPARG; */
 #define FUTEX_OP_OR		2	/* *(int *)UADDR2 |= OPARG; */
diff --git a/include/linux/gameport.h b/include/linux/gameport.h
index 2401dea..9c8e6da 100644
--- a/include/linux/gameport.h
+++ b/include/linux/gameport.h
@@ -119,7 +119,7 @@
 }
 
 /*
- * Use the following fucntions to manipulate gameport's per-port
+ * Use the following functions to manipulate gameport's per-port
  * driver-specific data.
  */
 static inline void *gameport_get_drvdata(struct gameport *gameport)
@@ -133,7 +133,7 @@
 }
 
 /*
- * Use the following fucntions to pin gameport's driver in process context
+ * Use the following functions to pin gameport's driver in process context
  */
 static inline int gameport_pin_driver(struct gameport *gameport)
 {
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index fd647fd..10a27f2 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -78,6 +78,7 @@
 	sector_t start_sect;
 	sector_t nr_sects;
 	struct kobject kobj;
+	struct kobject *holder_dir;
 	unsigned ios[2], sectors[2];	/* READs and WRITEs */
 	int policy, partno;
 };
@@ -89,12 +90,12 @@
 #define GENHD_FL_SUPPRESS_PARTITION_INFO	32
 
 struct disk_stats {
-	unsigned sectors[2];		/* READs and WRITEs */
-	unsigned ios[2];
-	unsigned merges[2];
-	unsigned ticks[2];
-	unsigned io_ticks;
-	unsigned time_in_queue;
+	unsigned long sectors[2];	/* READs and WRITEs */
+	unsigned long ios[2];
+	unsigned long merges[2];
+	unsigned long ticks[2];
+	unsigned long io_ticks;
+	unsigned long time_in_queue;
 };
 	
 struct gendisk {
@@ -114,6 +115,8 @@
 	int number;			/* more of the same */
 	struct device *driverfs_dev;
 	struct kobject kobj;
+	struct kobject *holder_dir;
+	struct kobject *slave_dir;
 
 	struct timer_rand_state *random;
 	int policy;
@@ -149,14 +152,14 @@
 ({									\
 	typeof(gendiskp->dkstats->field) res = 0;			\
 	int i;								\
-	for_each_cpu(i)							\
+	for_each_possible_cpu(i)					\
 		res += per_cpu_ptr(gendiskp->dkstats, i)->field;	\
 	res;								\
 })
 
 static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)	{
 	int i;
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 		memset(per_cpu_ptr(gendiskp->dkstats, i), value,
 				sizeof (struct disk_stats));
 }		
diff --git a/include/linux/gigaset_dev.h b/include/linux/gigaset_dev.h
new file mode 100644
index 0000000..70ad09c
--- /dev/null
+++ b/include/linux/gigaset_dev.h
@@ -0,0 +1,32 @@
+/*
+ * interface to user space for the gigaset driver
+ *
+ * Copyright (c) 2004 by Hansjoerg Lipp <hjlipp@web.de>
+ *
+ * =====================================================================
+ *    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.
+ * =====================================================================
+ * Version: $Id: gigaset_dev.h,v 1.4.4.4 2005/11/21 22:28:09 hjlipp Exp $
+ * =====================================================================
+ */
+
+#ifndef GIGASET_INTERFACE_H
+#define GIGASET_INTERFACE_H
+
+#include <linux/ioctl.h>
+
+#define GIGASET_IOCTL 0x47
+
+#define GIGVER_DRIVER 0
+#define GIGVER_COMPAT 1
+#define GIGVER_FWBASE 2
+
+#define GIGASET_REDIR    _IOWR (GIGASET_IOCTL, 0, int)
+#define GIGASET_CONFIG   _IOWR (GIGASET_IOCTL, 1, int)
+#define GIGASET_BRKCHARS _IOW  (GIGASET_IOCTL, 2, unsigned char[6]) //FIXME [6] okay?
+#define GIGASET_VERSION  _IOWR (GIGASET_IOCTL, 3, unsigned[4])
+
+#endif
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 6bece92..892c4ea 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -7,6 +7,18 @@
 
 #include <asm/cacheflush.h>
 
+#ifndef ARCH_HAS_FLUSH_ANON_PAGE
+static inline void flush_anon_page(struct page *page, unsigned long vmaddr)
+{
+}
+#endif
+
+#ifndef ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+static inline void flush_kernel_dcache_page(struct page *page)
+{
+}
+#endif
+
 #ifdef CONFIG_HIGHMEM
 
 #include <asm/highmem.h>
diff --git a/include/linux/hpet.h b/include/linux/hpet.h
index 2723819..707f7cb 100644
--- a/include/linux/hpet.h
+++ b/include/linux/hpet.h
@@ -3,6 +3,8 @@
 
 #include <linux/compiler.h>
 
+#ifdef __KERNEL__
+
 /*
  * Offsets into HPET Registers
  */
@@ -85,22 +87,6 @@
 #define	Tn_FSB_INT_ADDR_SHIFT		(32UL)
 #define	Tn_FSB_INT_VAL_MASK		(0x00000000ffffffffULL)
 
-struct hpet_info {
-	unsigned long hi_ireqfreq;	/* Hz */
-	unsigned long hi_flags;	/* information */
-	unsigned short hi_hpet;
-	unsigned short hi_timer;
-};
-
-#define	HPET_INFO_PERIODIC	0x0001	/* timer is periodic */
-
-#define	HPET_IE_ON	_IO('h', 0x01)	/* interrupt on */
-#define	HPET_IE_OFF	_IO('h', 0x02)	/* interrupt off */
-#define	HPET_INFO	_IOR('h', 0x03, struct hpet_info)
-#define	HPET_EPI	_IO('h', 0x04)	/* enable periodic */
-#define	HPET_DPI	_IO('h', 0x05)	/* disable periodic */
-#define	HPET_IRQFREQ	_IOW('h', 0x6, unsigned long)	/* IRQFREQ usec */
-
 /*
  * exported interfaces
  */
@@ -133,4 +119,22 @@
 int hpet_unregister(struct hpet_task *);
 int hpet_control(struct hpet_task *, unsigned int, unsigned long);
 
+#endif /* __KERNEL__ */
+
+struct hpet_info {
+	unsigned long hi_ireqfreq;	/* Hz */
+	unsigned long hi_flags;	/* information */
+	unsigned short hi_hpet;
+	unsigned short hi_timer;
+};
+
+#define	HPET_INFO_PERIODIC	0x0001	/* timer is periodic */
+
+#define	HPET_IE_ON	_IO('h', 0x01)	/* interrupt on */
+#define	HPET_IE_OFF	_IO('h', 0x02)	/* interrupt off */
+#define	HPET_INFO	_IOR('h', 0x03, struct hpet_info)
+#define	HPET_EPI	_IO('h', 0x04)	/* enable periodic */
+#define	HPET_DPI	_IO('h', 0x05)	/* disable periodic */
+#define	HPET_IRQFREQ	_IOW('h', 0x6, unsigned long)	/* IRQFREQ usec */
+
 #endif				/* !__HPET__ */
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 6401c31..b209392 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -34,15 +34,7 @@
 	HRTIMER_RESTART,
 };
 
-/*
- * Timer states:
- */
-enum hrtimer_state {
-	HRTIMER_INACTIVE,	/* Timer is inactive */
-	HRTIMER_EXPIRED,		/* Timer is expired */
-	HRTIMER_RUNNING,		/* Timer is running the callback function */
-	HRTIMER_PENDING,		/* Timer is pending */
-};
+#define HRTIMER_INACTIVE	((void *)1UL)
 
 struct hrtimer_base;
 
@@ -53,9 +45,7 @@
  * @expires:	the absolute expiry time in the hrtimers internal
  *		representation. The time is related to the clock on
  *		which the timer is based.
- * @state:	state of the timer
  * @function:	timer expiry callback function
- * @data:	argument for the callback function
  * @base:	pointer to the timer base (per cpu and per clock)
  *
  * The hrtimer structure must be initialized by init_hrtimer_#CLOCKTYPE()
@@ -63,23 +53,36 @@
 struct hrtimer {
 	struct rb_node		node;
 	ktime_t			expires;
-	enum hrtimer_state	state;
-	int			(*function)(void *);
-	void			*data;
+	int			(*function)(struct hrtimer *);
 	struct hrtimer_base	*base;
 };
 
 /**
+ * struct hrtimer_sleeper - simple sleeper structure
+ *
+ * @timer:	embedded timer structure
+ * @task:	task to wake up
+ *
+ * task is set to NULL, when the timer expires.
+ */
+struct hrtimer_sleeper {
+	struct hrtimer timer;
+	struct task_struct *task;
+};
+
+/**
  * struct hrtimer_base - the timer base for a specific clock
  *
- * @index:	clock type index for per_cpu support when moving a timer
- *		to a base on another cpu.
- * @lock:	lock protecting the base and associated timers
- * @active:	red black tree root node for the active timers
- * @first:	pointer to the timer node which expires first
- * @resolution:	the resolution of the clock, in nanoseconds
- * @get_time:	function to retrieve the current time of the clock
- * @curr_timer:	the timer which is executing a callback right now
+ * @index:		clock type index for per_cpu support when moving a timer
+ *			to a base on another cpu.
+ * @lock:		lock protecting the base and associated timers
+ * @active:		red black tree root node for the active timers
+ * @first:		pointer to the timer node which expires first
+ * @resolution:		the resolution of the clock, in nanoseconds
+ * @get_time:		function to retrieve the current time of the clock
+ * @get_sofirq_time:	function to retrieve the current time from the softirq
+ * @curr_timer:		the timer which is executing a callback right now
+ * @softirq_time:	the time when running the hrtimer queue in the softirq
  */
 struct hrtimer_base {
 	clockid_t		index;
@@ -88,7 +91,9 @@
 	struct rb_node		*first;
 	ktime_t			resolution;
 	ktime_t			(*get_time)(void);
+	ktime_t			(*get_softirq_time)(void);
 	struct hrtimer		*curr_timer;
+	ktime_t			softirq_time;
 };
 
 /*
@@ -122,11 +127,12 @@
 
 static inline int hrtimer_active(const struct hrtimer *timer)
 {
-	return timer->state == HRTIMER_PENDING;
+	return timer->node.rb_parent != HRTIMER_INACTIVE;
 }
 
 /* Forward a hrtimer so it expires after now: */
-extern unsigned long hrtimer_forward(struct hrtimer *timer, ktime_t interval);
+extern unsigned long
+hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);
 
 /* Precise sleep: */
 extern long hrtimer_nanosleep(struct timespec *rqtp,
@@ -134,6 +140,9 @@
 			      const enum hrtimer_mode mode,
 			      const clockid_t clockid);
 
+extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl,
+				 struct task_struct *tsk);
+
 /* Soft interrupt function to run the hrtimer queues: */
 extern void hrtimer_run_queues(void);
 
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index d6f1019..4c5e610 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -154,7 +154,7 @@
 	return sb->s_fs_info;
 }
 
-extern struct file_operations hugetlbfs_file_operations;
+extern const struct file_operations hugetlbfs_file_operations;
 extern struct vm_operations_struct hugetlb_vm_ops;
 struct file *hugetlb_zero_setup(size_t);
 int hugetlb_extend_reservation(struct hugetlbfs_inode_info *info,
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index 679b46a..c8b81f4 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -108,6 +108,10 @@
 #define I2C_DRIVERID_UPD64083	78	/* upd64083 video processor	*/
 #define I2C_DRIVERID_UPD64031A	79	/* upd64031a video processor	*/
 #define I2C_DRIVERID_SAA717X	80	/* saa717x video encoder	*/
+#define I2C_DRIVERID_DS1672	81	/* Dallas/Maxim DS1672 RTC	*/
+#define I2C_DRIVERID_X1205	82	/* Xicor/Intersil X1205 RTC	*/
+#define I2C_DRIVERID_PCF8563	83	/* Philips PCF8563 RTC		*/
+#define I2C_DRIVERID_RS5C372	84	/* Ricoh RS5C372 RTC		*/
 
 #define I2C_DRIVERID_I2CDEV	900
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
diff --git a/include/linux/i2o.h b/include/linux/i2o.h
index 5a9d8c5..dd7d627 100644
--- a/include/linux/i2o.h
+++ b/include/linux/i2o.h
@@ -950,9 +950,7 @@
 	if (!pool->slab)
 		goto free_name;
 
-	pool->mempool =
-	    mempool_create(min_nr, mempool_alloc_slab, mempool_free_slab,
-			   pool->slab);
+	pool->mempool = mempool_create_slab_pool(min_nr, pool->slab);
 	if (!pool->mempool)
 		goto free_slab;
 
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 92146f3..41ecbb8 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -62,6 +62,8 @@
 	.posix_timers	 = LIST_HEAD_INIT(sig.posix_timers),		\
 	.cpu_timers	= INIT_CPU_TIMERS(sig.cpu_timers),		\
 	.rlim		= INIT_RLIMITS,					\
+	.pgrp		= 1,						\
+	.session	= 1,						\
 }
 
 #define INIT_SIGHAND(sighand) {						\
diff --git a/include/linux/input.h b/include/linux/input.h
index 6d4cc3c..1d4e341 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -957,7 +957,7 @@
 	struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id);
 	void (*disconnect)(struct input_handle *handle);
 
-	struct file_operations *fops;
+	const struct file_operations *fops;
 	int minor;
 	char *name;
 
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index d6276e6..0a84b56 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -36,6 +36,7 @@
 
 #include <linux/ipmi_msgdefs.h>
 #include <linux/compiler.h>
+#include <linux/device.h>
 
 /*
  * This file describes an interface to an IPMI driver.  You have to
@@ -397,7 +398,7 @@
 	   the watcher list.  So you can add and remove users from the
 	   IPMI interface, send messages, etc., but you cannot add
 	   or remove SMI watchers or SMI interfaces. */
-	void (*new_smi)(int if_num);
+	void (*new_smi)(int if_num, struct device *dev);
 	void (*smi_gone)(int if_num);
 };
 
diff --git a/include/linux/ipmi_msgdefs.h b/include/linux/ipmi_msgdefs.h
index 03bc64d..22f5e2a 100644
--- a/include/linux/ipmi_msgdefs.h
+++ b/include/linux/ipmi_msgdefs.h
@@ -47,6 +47,7 @@
 #define IPMI_NETFN_APP_RESPONSE			0x07
 #define IPMI_GET_DEVICE_ID_CMD		0x01
 #define IPMI_CLEAR_MSG_FLAGS_CMD	0x30
+#define IPMI_GET_DEVICE_GUID_CMD	0x08
 #define IPMI_GET_MSG_FLAGS_CMD		0x31
 #define IPMI_SEND_MSG_CMD		0x34
 #define IPMI_GET_MSG_CMD		0x33
diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h
index e36ee15..6d9c7e4 100644
--- a/include/linux/ipmi_smi.h
+++ b/include/linux/ipmi_smi.h
@@ -37,6 +37,9 @@
 #include <linux/ipmi_msgdefs.h>
 #include <linux/proc_fs.h>
 #include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/ipmi_smi.h>
 
 /* This files describes the interface for IPMI system management interface
    drivers to bind into the IPMI message handler. */
@@ -79,6 +82,13 @@
 {
 	struct module *owner;
 
+	/* The low-level interface cannot start sending messages to
+	   the upper layer until this function is called.  This may
+	   not be NULL, the lower layer must take the interface from
+	   this call. */
+	int (*start_processing)(void       *send_info,
+				ipmi_smi_t new_intf);
+
 	/* Called to enqueue an SMI message to be sent.  This
 	   operation is not allowed to fail.  If an error occurs, it
 	   should report back the error in a received message.  It may
@@ -113,14 +123,57 @@
 	void (*dec_usecount)(void *send_info);
 };
 
+struct ipmi_device_id {
+	unsigned char device_id;
+	unsigned char device_revision;
+	unsigned char firmware_revision_1;
+	unsigned char firmware_revision_2;
+	unsigned char ipmi_version;
+	unsigned char additional_device_support;
+	unsigned int  manufacturer_id;
+	unsigned int  product_id;
+	unsigned char aux_firmware_revision[4];
+	unsigned int  aux_firmware_revision_set : 1;
+};
+
+#define ipmi_version_major(v) ((v)->ipmi_version & 0xf)
+#define ipmi_version_minor(v) ((v)->ipmi_version >> 4)
+
+/* Take a pointer to a raw data buffer and a length and extract device
+   id information from it.  The first byte of data must point to the
+   byte from the get device id response after the completion code.
+   The caller is responsible for making sure the length is at least
+   11 and the command completed without error. */
+static inline void ipmi_demangle_device_id(unsigned char *data,
+					   unsigned int  data_len,
+					   struct ipmi_device_id *id)
+{
+	id->device_id = data[0];
+	id->device_revision = data[1];
+	id->firmware_revision_1 = data[2];
+	id->firmware_revision_2 = data[3];
+	id->ipmi_version = data[4];
+	id->additional_device_support = data[5];
+	id->manufacturer_id = data[6] | (data[7] << 8) | (data[8] << 16);
+	id->product_id = data[9] | (data[10] << 8);
+	if (data_len >= 15) {
+		memcpy(id->aux_firmware_revision, data+11, 4);
+		id->aux_firmware_revision_set = 1;
+	} else
+		id->aux_firmware_revision_set = 0;
+}
+
 /* Add a low-level interface to the IPMI driver.  Note that if the
-   interface doesn't know its slave address, it should pass in zero. */
+   interface doesn't know its slave address, it should pass in zero.
+   The low-level interface should not deliver any messages to the
+   upper layer until the start_processing() function in the handlers
+   is called, and the lower layer must get the interface from that
+   call. */
 int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
 		      void                     *send_info,
-		      unsigned char            version_major,
-		      unsigned char            version_minor,
-		      unsigned char            slave_addr,
-		      ipmi_smi_t               *intf);
+		      struct ipmi_device_id    *device_id,
+		      struct device            *dev,
+		      unsigned char            slave_addr);
 
 /*
  * Remove a low-level interface from the IPMI driver.  This will
diff --git a/include/linux/jbd.h b/include/linux/jbd.h
index 4fc7dff..6a425e3 100644
--- a/include/linux/jbd.h
+++ b/include/linux/jbd.h
@@ -895,7 +895,7 @@
 extern void	 journal_release_buffer (handle_t *, struct buffer_head *);
 extern int	 journal_forget (handle_t *, struct buffer_head *);
 extern void	 journal_sync_buffer (struct buffer_head *);
-extern int	 journal_invalidatepage(journal_t *,
+extern void	 journal_invalidatepage(journal_t *,
 				struct page *, unsigned long);
 extern int	 journal_try_to_free_buffers(journal_t *, struct page *, gfp_t);
 extern int	 journal_stop(handle_t *);
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 03d6cfa..a3720f9 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -87,7 +87,7 @@
 		(__x < 0) ? -__x : __x;		\
 	})
 
-extern struct notifier_block *panic_notifier_list;
+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)));
diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h
index a484572..b462490 100644
--- a/include/linux/kernel_stat.h
+++ b/include/linux/kernel_stat.h
@@ -46,7 +46,7 @@
 {
 	int cpu, sum = 0;
 
-	for_each_cpu(cpu)
+	for_each_possible_cpu(cpu)
 		sum += kstat_cpu(cpu).irqs[irq];
 
 	return sum;
diff --git a/include/linux/ktime.h b/include/linux/ktime.h
index f3dec45..62bc575 100644
--- a/include/linux/ktime.h
+++ b/include/linux/ktime.h
@@ -64,9 +64,6 @@
 
 #if (BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR)
 
-/* Define a ktime_t variable and initialize it to zero: */
-#define DEFINE_KTIME(kt)		ktime_t kt = { .tv64 = 0 }
-
 /**
  * ktime_set - Set a ktime_t variable from a seconds/nanoseconds value
  *
@@ -113,9 +110,6 @@
 /* Map the ktime_t to timeval conversion to ns_to_timeval function */
 #define ktime_to_timeval(kt)		ns_to_timeval((kt).tv64)
 
-/* Map the ktime_t to clock_t conversion to the inline in jiffies.h: */
-#define ktime_to_clock_t(kt)		nsec_to_clock_t((kt).tv64)
-
 /* Convert ktime_t to nanoseconds - NOP in the scalar storage format: */
 #define ktime_to_ns(kt)			((kt).tv64)
 
@@ -136,9 +130,6 @@
  *   tv.sec < 0 and 0 >= tv.nsec < NSEC_PER_SEC
  */
 
-/* Define a ktime_t variable and initialize it to zero: */
-#define DEFINE_KTIME(kt)		ktime_t kt = { .tv64 = 0 }
-
 /* Set a ktime_t variable to a value in sec/nsec representation: */
 static inline ktime_t ktime_set(const long secs, const unsigned long nsecs)
 {
@@ -255,17 +246,6 @@
 }
 
 /**
- * ktime_to_clock_t - convert a ktime_t variable to clock_t format
- * @kt:		the ktime_t variable to convert
- *
- * Returns a clock_t variable with the converted value
- */
-static inline clock_t ktime_to_clock_t(const ktime_t kt)
-{
-	return nsec_to_clock_t( (u64) kt.tv.sec * NSEC_PER_SEC + kt.tv.nsec);
-}
-
-/**
  * ktime_to_ns - convert a ktime_t variable to scalar nanoseconds
  * @kt:		the ktime_t variable to convert
  *
diff --git a/include/linux/leds.h b/include/linux/leds.h
new file mode 100644
index 0000000..4617e75
--- /dev/null
+++ b/include/linux/leds.h
@@ -0,0 +1,111 @@
+/*
+ * Driver model for leds and led triggers
+ *
+ * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
+ * Copyright (C) 2005 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
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef __LINUX_LEDS_H_INCLUDED
+#define __LINUX_LEDS_H_INCLUDED
+
+struct device;
+struct class_device;
+/*
+ * LED Core
+ */
+
+enum led_brightness {
+	LED_OFF = 0,
+	LED_HALF = 127,
+	LED_FULL = 255,
+};
+
+struct led_classdev {
+	const char *name;
+	int brightness;
+	int flags;
+#define LED_SUSPENDED       (1 << 0)
+
+	/* A function to set the brightness of the led */
+	void (*brightness_set)(struct led_classdev *led_cdev,
+				enum led_brightness brightness);
+
+	struct class_device *class_dev;
+	/* LED Device linked list */
+	struct list_head node;
+
+	/* Trigger data */
+	char *default_trigger;
+#ifdef CONFIG_LEDS_TRIGGERS
+	rwlock_t trigger_lock;
+	/* Protects the trigger data below */
+
+	struct led_trigger *trigger;
+	struct list_head trig_list;
+	void *trigger_data;
+#endif
+};
+
+extern int led_classdev_register(struct device *parent,
+				struct led_classdev *led_cdev);
+extern void led_classdev_unregister(struct led_classdev *led_cdev);
+extern void led_classdev_suspend(struct led_classdev *led_cdev);
+extern void led_classdev_resume(struct led_classdev *led_cdev);
+
+/*
+ * LED Triggers
+ */
+#ifdef CONFIG_LEDS_TRIGGERS
+
+#define TRIG_NAME_MAX 50
+
+struct led_trigger {
+	/* Trigger Properties */
+	const char *name;
+	void (*activate)(struct led_classdev *led_cdev);
+	void (*deactivate)(struct led_classdev *led_cdev);
+
+	/* LEDs under control by this trigger (for simple triggers) */
+	rwlock_t leddev_list_lock;
+	struct list_head led_cdevs;
+
+	/* Link to next registered trigger */
+	struct list_head next_trig;
+};
+
+/* Registration functions for complex triggers */
+extern int led_trigger_register(struct led_trigger *trigger);
+extern void led_trigger_unregister(struct led_trigger *trigger);
+
+/* Registration functions for simple triggers */
+#define DEFINE_LED_TRIGGER(x)		static struct led_trigger *x;
+#define DEFINE_LED_TRIGGER_GLOBAL(x)	struct led_trigger *x;
+extern void led_trigger_register_simple(const char *name,
+				struct led_trigger **trigger);
+extern void led_trigger_unregister_simple(struct led_trigger *trigger);
+extern void led_trigger_event(struct led_trigger *trigger,
+				enum led_brightness event);
+
+#else
+
+/* Triggers aren't active - null macros */
+#define DEFINE_LED_TRIGGER(x)
+#define DEFINE_LED_TRIGGER_GLOBAL(x)
+#define led_trigger_register_simple(x, y) do {} while(0)
+#define led_trigger_unregister_simple(x) do {} while(0)
+#define led_trigger_event(x, y) do {} while(0)
+
+#endif
+
+/* Trigger specific functions */
+#ifdef CONFIG_LEDS_TRIGGER_IDE_DISK
+extern void ledtrig_ide_activity(void);
+#else
+#define ledtrig_ide_activity() do {} while(0)
+#endif
+
+#endif		/* __LINUX_LEDS_H_INCLUDED */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 0471922..0d61357 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -160,8 +160,10 @@
 	ATA_QCFLAG_DMAMAP	= ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
 	ATA_QCFLAG_EH_SCHEDULED = (1 << 5), /* EH scheduled */
 
+	/* host set flags */
+	ATA_HOST_SIMPLEX	= (1 << 0),	/* Host is simplex, one DMA channel per host_set only */
+	
 	/* various lengths of time */
-	ATA_TMOUT_EDD		= 5 * HZ,	/* heuristic */
 	ATA_TMOUT_PIO		= 30 * HZ,
 	ATA_TMOUT_BOOT		= 30 * HZ,	/* heuristic */
 	ATA_TMOUT_BOOT_QUICK	= 7 * HZ,	/* heuristic */
@@ -279,6 +281,7 @@
 	unsigned long		irq;
 	unsigned int		irq_flags;
 	unsigned long		host_flags;
+	unsigned long		host_set_flags;
 	void __iomem		*mmio_base;
 	void			*private_data;
 };
@@ -291,6 +294,9 @@
 	unsigned int		n_ports;
 	void			*private_data;
 	const struct ata_port_operations *ops;
+	unsigned long		flags;
+	int			simplex_claimed;	/* Keep seperate in case we
+							   ever need to do this locked */
 	struct ata_port *	ports[0];
 };
 
@@ -420,6 +426,7 @@
 
 	void (*set_piomode) (struct ata_port *, struct ata_device *);
 	void (*set_dmamode) (struct ata_port *, struct ata_device *);
+	unsigned long (*mode_filter) (const struct ata_port *, struct ata_device *, unsigned long);
 
 	void (*tf_load) (struct ata_port *ap, const struct ata_taskfile *tf);
 	void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
@@ -430,6 +437,7 @@
 	void (*dev_select)(struct ata_port *ap, unsigned int device);
 
 	void (*phy_reset) (struct ata_port *ap); /* obsolete */
+	void (*set_mode) (struct ata_port *ap);
 	int (*probe_reset) (struct ata_port *ap, unsigned int *classes);
 
 	void (*post_set_mode) (struct ata_port *ap);
diff --git a/include/linux/m48t86.h b/include/linux/m48t86.h
new file mode 100644
index 0000000..9065199
--- /dev/null
+++ b/include/linux/m48t86.h
@@ -0,0 +1,16 @@
+/*
+ * ST M48T86 / Dallas DS12887 RTC driver
+ * Copyright (c) 2006 Tower Technologies
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * 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.
+*/
+
+struct m48t86_ops
+{
+	void (*writeb)(unsigned char value, unsigned long addr);
+	unsigned char (*readb)(unsigned long addr);
+};
diff --git a/include/linux/memory.h b/include/linux/memory.h
index e251dc4..8f04143 100644
--- a/include/linux/memory.h
+++ b/include/linux/memory.h
@@ -77,7 +77,6 @@
 
 #define CONFIG_MEM_BLOCK_SIZE	(PAGES_PER_SECTION<<PAGE_SHIFT)
 
-struct notifier_block;
 
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
diff --git a/include/linux/mempool.h b/include/linux/mempool.h
index f2427d7..9be484d 100644
--- a/include/linux/mempool.h
+++ b/include/linux/mempool.h
@@ -6,6 +6,8 @@
 
 #include <linux/wait.h>
 
+struct kmem_cache;
+
 typedef void * (mempool_alloc_t)(gfp_t gfp_mask, void *pool_data);
 typedef void (mempool_free_t)(void *element, void *pool_data);
 
@@ -37,5 +39,41 @@
  */
 void *mempool_alloc_slab(gfp_t gfp_mask, void *pool_data);
 void mempool_free_slab(void *element, void *pool_data);
+static inline mempool_t *
+mempool_create_slab_pool(int min_nr, struct kmem_cache *kc)
+{
+	return mempool_create(min_nr, mempool_alloc_slab, mempool_free_slab,
+			      (void *) kc);
+}
+
+/*
+ * 2 mempool_alloc_t's and a mempool_free_t to kmalloc/kzalloc and kfree
+ * the amount of memory specified by pool_data
+ */
+void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data);
+void *mempool_kzalloc(gfp_t gfp_mask, void *pool_data);
+void mempool_kfree(void *element, void *pool_data);
+static inline mempool_t *mempool_create_kmalloc_pool(int min_nr, size_t size)
+{
+	return mempool_create(min_nr, mempool_kmalloc, mempool_kfree,
+			      (void *) size);
+}
+static inline mempool_t *mempool_create_kzalloc_pool(int min_nr, size_t size)
+{
+	return mempool_create(min_nr, mempool_kzalloc, mempool_kfree,
+			      (void *) size);
+}
+
+/*
+ * A mempool_alloc_t and mempool_free_t for a simple page allocator that
+ * allocates pages of the order specified by pool_data
+ */
+void *mempool_alloc_pages(gfp_t gfp_mask, void *pool_data);
+void mempool_free_pages(void *element, void *pool_data);
+static inline mempool_t *mempool_create_page_pool(int min_nr, int order)
+{
+	return mempool_create(min_nr, mempool_alloc_pages, mempool_free_pages,
+			      (void *)(long)order);
+}
 
 #endif /* _LINUX_MEMPOOL_H */
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 7d09962..ff0a640 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -12,7 +12,7 @@
 extern int migrate_page_remove_references(struct page *, struct page *, int);
 extern int migrate_pages(struct list_head *l, struct list_head *t,
 		struct list_head *moved, struct list_head *failed);
-int migrate_pages_to(struct list_head *pagelist,
+extern int migrate_pages_to(struct list_head *pagelist,
 			struct vm_area_struct *vma, int dest);
 extern int fail_migrate_page(struct page *, struct page *);
 
@@ -26,6 +26,9 @@
 static inline int migrate_pages(struct list_head *l, struct list_head *t,
 	struct list_head *moved, struct list_head *failed) { return -ENOSYS; }
 
+static inline int migrate_pages_to(struct list_head *pagelist,
+			struct vm_area_struct *vma, int dest) { return 0; }
+
 static inline int migrate_prep(void) { return -ENOSYS; }
 
 /* Possible settings for the migrate_page() method in address_operations */
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index 14ceebf..5b584da 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -36,7 +36,7 @@
 struct miscdevice  {
 	int minor;
 	const char *name;
-	struct file_operations *fops;
+	const struct file_operations *fops;
 	struct list_head list;
 	struct device *dev;
 	struct class_device *class;
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ebfc238..b5c2112 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -13,6 +13,7 @@
 #include <linux/numa.h>
 #include <linux/init.h>
 #include <linux/seqlock.h>
+#include <linux/nodemask.h>
 #include <asm/atomic.h>
 
 /* Free memory management - zoned buddy allocator.  */
@@ -225,7 +226,6 @@
 	 * Discontig memory support fields.
 	 */
 	struct pglist_data	*zone_pgdat;
-	struct page		*zone_mem_map;
 	/* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */
 	unsigned long		zone_start_pfn;
 
@@ -307,7 +307,6 @@
 	unsigned long node_spanned_pages; /* total size of physical page
 					     range, including holes */
 	int node_id;
-	struct pglist_data *pgdat_next;
 	wait_queue_head_t kswapd_wait;
 	struct task_struct *kswapd;
 	int kswapd_max_order;
@@ -324,8 +323,6 @@
 
 #include <linux/memory_hotplug.h>
 
-extern struct pglist_data *pgdat_list;
-
 void __get_zone_counts(unsigned long *active, unsigned long *inactive,
 			unsigned long *free, struct pglist_data *pgdat);
 void get_zone_counts(unsigned long *active, unsigned long *inactive,
@@ -350,57 +347,6 @@
  */
 #define zone_idx(zone)		((zone) - (zone)->zone_pgdat->node_zones)
 
-/**
- * for_each_pgdat - helper macro to iterate over all nodes
- * @pgdat - pointer to a pg_data_t variable
- *
- * Meant to help with common loops of the form
- * pgdat = pgdat_list;
- * while(pgdat) {
- * 	...
- * 	pgdat = pgdat->pgdat_next;
- * }
- */
-#define for_each_pgdat(pgdat) \
-	for (pgdat = pgdat_list; pgdat; pgdat = pgdat->pgdat_next)
-
-/*
- * next_zone - helper magic for for_each_zone()
- * Thanks to William Lee Irwin III for this piece of ingenuity.
- */
-static inline struct zone *next_zone(struct zone *zone)
-{
-	pg_data_t *pgdat = zone->zone_pgdat;
-
-	if (zone < pgdat->node_zones + MAX_NR_ZONES - 1)
-		zone++;
-	else if (pgdat->pgdat_next) {
-		pgdat = pgdat->pgdat_next;
-		zone = pgdat->node_zones;
-	} else
-		zone = NULL;
-
-	return zone;
-}
-
-/**
- * for_each_zone - helper macro to iterate over all memory zones
- * @zone - pointer to struct zone variable
- *
- * The user only needs to declare the zone variable, for_each_zone
- * fills it in. This basically means for_each_zone() is an
- * easier to read version of this piece of code:
- *
- * for (pgdat = pgdat_list; pgdat; pgdat = pgdat->node_next)
- * 	for (i = 0; i < MAX_NR_ZONES; ++i) {
- * 		struct zone * z = pgdat->node_zones + i;
- * 		...
- * 	}
- * }
- */
-#define for_each_zone(zone) \
-	for (zone = pgdat_list->node_zones; zone; zone = next_zone(zone))
-
 static inline int populated_zone(struct zone *zone)
 {
 	return (!!zone->present_pages);
@@ -472,6 +418,30 @@
 
 #endif /* !CONFIG_NEED_MULTIPLE_NODES */
 
+extern struct pglist_data *first_online_pgdat(void);
+extern struct pglist_data *next_online_pgdat(struct pglist_data *pgdat);
+extern struct zone *next_zone(struct zone *zone);
+
+/**
+ * for_each_pgdat - helper macro to iterate over all nodes
+ * @pgdat - pointer to a pg_data_t variable
+ */
+#define for_each_online_pgdat(pgdat)			\
+	for (pgdat = first_online_pgdat();		\
+	     pgdat;					\
+	     pgdat = next_online_pgdat(pgdat))
+/**
+ * for_each_zone - helper macro to iterate over all memory zones
+ * @zone - pointer to struct zone variable
+ *
+ * The user only needs to declare the zone variable, for_each_zone
+ * fills it in.
+ */
+#define for_each_zone(zone)			        \
+	for (zone = (first_online_pgdat())->node_zones; \
+	     zone;					\
+	     zone = next_zone(zone))
+
 #ifdef CONFIG_SPARSEMEM
 #include <asm/sparsemem.h>
 #endif
@@ -602,17 +572,6 @@
 	return __nr_to_section(pfn_to_section_nr(pfn));
 }
 
-#define pfn_to_page(pfn) 						\
-({ 									\
-	unsigned long __pfn = (pfn);					\
-	__section_mem_map_addr(__pfn_to_section(__pfn)) + __pfn;	\
-})
-#define page_to_pfn(page)						\
-({									\
-	page - __section_mem_map_addr(__nr_to_section(			\
-		page_to_section(page)));				\
-})
-
 static inline int pfn_valid(unsigned long pfn)
 {
 	if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index 779e6a5..d9035c7 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -334,7 +334,7 @@
 		    unsigned long *mapped_blocks);
 
 /* fat/dir.c */
-extern struct file_operations fat_dir_operations;
+extern const struct file_operations fat_dir_operations;
 extern int fat_search_long(struct inode *inode, const unsigned char *name,
 			   int name_len, struct fat_slot_info *sinfo);
 extern int fat_dir_empty(struct inode *dir);
@@ -397,7 +397,7 @@
 /* fat/file.c */
 extern int fat_generic_ioctl(struct inode *inode, struct file *filp,
 			     unsigned int cmd, unsigned long arg);
-extern struct file_operations fat_file_operations;
+extern const struct file_operations fat_file_operations;
 extern struct inode_operations fat_file_inode_operations;
 extern int fat_notify_change(struct dentry * dentry, struct iattr * attr);
 extern void fat_truncate(struct inode *inode);
@@ -420,6 +420,9 @@
 extern void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date);
 extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
 
+int fat_cache_init(void);
+void fat_cache_destroy(void);
+
 #endif /* __KERNEL__ */
 
 #endif
diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h
index f46afec..72fc68c 100644
--- a/include/linux/mtd/blktrans.h
+++ b/include/linux/mtd/blktrans.h
@@ -10,7 +10,7 @@
 #ifndef __MTD_TRANS_H__
 #define __MTD_TRANS_H__
 
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 struct hd_geometry;
 struct mtd_info;
@@ -22,7 +22,7 @@
 	struct mtd_blktrans_ops *tr;
 	struct list_head list;
 	struct mtd_info *mtd;
-	struct semaphore sem;
+	struct mutex lock;
 	int devnum;
 	int blksize;
 	unsigned long size;
diff --git a/include/linux/mtd/doc2000.h b/include/linux/mtd/doc2000.h
index 386a52c..9addd07 100644
--- a/include/linux/mtd/doc2000.h
+++ b/include/linux/mtd/doc2000.h
@@ -15,7 +15,7 @@
 #define __MTD_DOC2000_H__
 
 #include <linux/mtd/mtd.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #define DoC_Sig1 0
 #define DoC_Sig2 1
@@ -187,7 +187,7 @@
 	int numchips;
 	struct Nand *chips;
 	struct mtd_info *nextdoc;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 int doc_decode_ecc(unsigned char sector[512], unsigned char ecc1[6]);
diff --git a/include/linux/mtd/inftl.h b/include/linux/mtd/inftl.h
index 0268125..d7eaa40 100644
--- a/include/linux/mtd/inftl.h
+++ b/include/linux/mtd/inftl.h
@@ -52,6 +52,11 @@
 int INFTL_mount(struct INFTLrecord *s);
 int INFTL_formatblock(struct INFTLrecord *s, int block);
 
+extern char inftlmountrev[];
+
+void INFTL_dumptables(struct INFTLrecord *s);
+void INFTL_dumpVUchains(struct INFTLrecord *s);
+
 #endif /* __KERNEL__ */
 
 #endif /* __MTD_INFTL_H__ */
diff --git a/include/linux/namei.h b/include/linux/namei.h
index e669801..58cb3d3 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -75,7 +75,6 @@
 extern void release_open_intent(struct nameidata *);
 
 extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
-extern __deprecated_for_modules struct dentry * lookup_hash(struct nameidata *);
 
 extern int follow_down(struct vfsmount **, struct dentry **);
 extern int follow_up(struct vfsmount **, struct dentry **);
diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h
index e013425..96dc237 100644
--- a/include/linux/ncp_fs.h
+++ b/include/linux/ncp_fs.h
@@ -209,7 +209,7 @@
 
 /* linux/fs/ncpfs/dir.c */
 extern struct inode_operations ncp_dir_inode_operations;
-extern struct file_operations ncp_dir_operations;
+extern const struct file_operations ncp_dir_operations;
 int ncp_conn_logged_in(struct super_block *);
 int ncp_date_dos2unix(__le16 time, __le16 date);
 void ncp_date_unix2dos(int unix_date, __le16 * time, __le16 * date);
@@ -230,7 +230,7 @@
 
 /* linux/fs/ncpfs/file.c */
 extern struct inode_operations ncp_file_inode_operations;
-extern struct file_operations ncp_file_operations;
+extern const struct file_operations ncp_file_operations;
 int ncp_make_open(struct inode *, int);
 
 /* linux/fs/ncpfs/mmap.c */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 950dc55..40ccf8c 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -598,20 +598,7 @@
 
 #define HAVE_NETIF_QUEUE
 
-static inline void __netif_schedule(struct net_device *dev)
-{
-	if (!test_and_set_bit(__LINK_STATE_SCHED, &dev->state)) {
-		unsigned long flags;
-		struct softnet_data *sd;
-
-		local_irq_save(flags);
-		sd = &__get_cpu_var(softnet_data);
-		dev->next_sched = sd->output_queue;
-		sd->output_queue = dev;
-		raise_softirq_irqoff(NET_TX_SOFTIRQ);
-		local_irq_restore(flags);
-	}
-}
+extern void __netif_schedule(struct net_device *dev);
 
 static inline void netif_schedule(struct net_device *dev)
 {
@@ -675,13 +662,7 @@
 /* Use this variant in places where it could be invoked
  * either from interrupt or non-interrupt context.
  */
-static inline void dev_kfree_skb_any(struct sk_buff *skb)
-{
-	if (in_irq() || irqs_disabled())
-		dev_kfree_skb_irq(skb);
-	else
-		dev_kfree_skb(skb);
-}
+extern void dev_kfree_skb_any(struct sk_buff *skb);
 
 #define HAVE_NETIF_RX 1
 extern int		netif_rx(struct sk_buff *skb);
@@ -768,22 +749,9 @@
 	return test_bit(__LINK_STATE_PRESENT, &dev->state);
 }
 
-static inline void netif_device_detach(struct net_device *dev)
-{
-	if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) &&
-	    netif_running(dev)) {
-		netif_stop_queue(dev);
-	}
-}
+extern void netif_device_detach(struct net_device *dev);
 
-static inline void netif_device_attach(struct net_device *dev)
-{
-	if (!test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) &&
-	    netif_running(dev)) {
-		netif_wake_queue(dev);
- 		__netdev_watchdog_up(dev);
-	}
-}
+extern void netif_device_attach(struct net_device *dev);
 
 /*
  * Network interface message level settings
@@ -851,20 +819,7 @@
  * already been called and returned 1.
  */
 
-static inline void __netif_rx_schedule(struct net_device *dev)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	dev_hold(dev);
-	list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
-	if (dev->quota < 0)
-		dev->quota += dev->weight;
-	else
-		dev->quota = dev->weight;
-	__raise_softirq_irqoff(NET_RX_SOFTIRQ);
-	local_irq_restore(flags);
-}
+extern void __netif_rx_schedule(struct net_device *dev);
 
 /* Try to reschedule poll. Called by irq handler. */
 
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
index f32d75c..d54d7b2 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -308,29 +308,30 @@
 
 #define CONNTRACK_ECACHE(x)	(__get_cpu_var(ip_conntrack_ecache).x)
  
-extern struct notifier_block *ip_conntrack_chain;
-extern struct notifier_block *ip_conntrack_expect_chain;
+extern struct atomic_notifier_head ip_conntrack_chain;
+extern struct atomic_notifier_head ip_conntrack_expect_chain;
 
 static inline int ip_conntrack_register_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_register(&ip_conntrack_chain, nb);
+	return atomic_notifier_chain_register(&ip_conntrack_chain, nb);
 }
 
 static inline int ip_conntrack_unregister_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_unregister(&ip_conntrack_chain, nb);
+	return atomic_notifier_chain_unregister(&ip_conntrack_chain, nb);
 }
 
 static inline int 
 ip_conntrack_expect_register_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_register(&ip_conntrack_expect_chain, nb);
+	return atomic_notifier_chain_register(&ip_conntrack_expect_chain, nb);
 }
 
 static inline int
 ip_conntrack_expect_unregister_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_unregister(&ip_conntrack_expect_chain, nb);
+	return atomic_notifier_chain_unregister(&ip_conntrack_expect_chain,
+			nb);
 }
 
 extern void ip_ct_deliver_cached_events(const struct ip_conntrack *ct);
@@ -355,14 +356,14 @@
 				      struct ip_conntrack *ct)
 {
 	if (is_confirmed(ct) && !is_dying(ct))
-		notifier_call_chain(&ip_conntrack_chain, event, ct);
+		atomic_notifier_call_chain(&ip_conntrack_chain, event, ct);
 }
 
 static inline void 
 ip_conntrack_expect_event(enum ip_conntrack_expect_events event,
 			  struct ip_conntrack_expect *exp)
 {
-	notifier_call_chain(&ip_conntrack_expect_chain, event, exp);
+	atomic_notifier_call_chain(&ip_conntrack_expect_chain, event, exp);
 }
 #else /* CONFIG_IP_NF_CONNTRACK_EVENTS */
 static inline void ip_conntrack_event_cache(enum ip_conntrack_events event, 
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index cbebd7d..c71227d 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -324,7 +324,7 @@
 #ifdef CONFIG_NFS_V3
 extern struct inode_operations nfs3_file_inode_operations;
 #endif /* CONFIG_NFS_V3 */
-extern struct file_operations nfs_file_operations;
+extern const struct file_operations nfs_file_operations;
 extern struct address_space_operations nfs_file_aops;
 
 static inline struct rpc_cred *nfs_file_cred(struct file *file)
@@ -371,7 +371,7 @@
 #ifdef CONFIG_NFS_V3
 extern struct inode_operations nfs3_dir_inode_operations;
 #endif /* CONFIG_NFS_V3 */
-extern struct file_operations nfs_dir_operations;
+extern const struct file_operations nfs_dir_operations;
 extern struct dentry_operations nfs_dentry_operations;
 
 extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr);
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index 6bad476..d2a8abb 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -67,7 +67,8 @@
 	int			ek_fsidtype;
 	u32			ek_fsid[3];
 
-	struct svc_export *	ek_export;
+	struct vfsmount *	ek_mnt;
+	struct dentry *		ek_dentry;
 };
 
 #define EX_SECURE(exp)		(!((exp)->ex_flags & NFSEXP_INSECURE_PORT))
@@ -85,9 +86,6 @@
 void			nfsd_export_flush(void);
 void			exp_readlock(void);
 void			exp_readunlock(void);
-struct svc_expkey *	exp_find_key(struct auth_domain *clp, 
-				     int fsid_type, u32 *fsidv,
-				     struct cache_req *reqp);
 struct svc_export *	exp_get_by_name(struct auth_domain *clp,
 					struct vfsmount *mnt,
 					struct dentry *dentry,
@@ -101,35 +99,20 @@
 int			exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq);
 int			nfserrno(int errno);
 
-extern void expkey_put(struct cache_head *item, struct cache_detail *cd);
-extern void svc_export_put(struct cache_head *item, struct cache_detail *cd);
-extern struct cache_detail svc_export_cache, svc_expkey_cache;
+extern struct cache_detail svc_export_cache;
 
 static inline void exp_put(struct svc_export *exp)
 {
-	svc_export_put(&exp->h, &svc_export_cache);
+	cache_put(&exp->h, &svc_export_cache);
 }
 
 static inline void exp_get(struct svc_export *exp)
 {
 	cache_get(&exp->h);
 }
-static inline struct svc_export *
+extern struct svc_export *
 exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
-	 struct cache_req *reqp)
-{
-	struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
-	if (ek && !IS_ERR(ek)) {
-		struct svc_export *exp = ek->ek_export;
-		int err;
-		exp_get(exp);
-		expkey_put(&ek->h, &svc_expkey_cache);
-		if ((err = cache_check(&svc_export_cache, &exp->h, reqp)))
-			exp = ERR_PTR(err);
-		return exp;
-	} else
-		return ERR_PTR(PTR_ERR(ek));
-}
+	 struct cache_req *reqp);
 
 #endif /* __KERNEL__ */
 
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
index b959a45..1a9ef3e 100644
--- a/include/linux/nodemask.h
+++ b/include/linux/nodemask.h
@@ -350,11 +350,15 @@
 #define num_possible_nodes()	nodes_weight(node_possible_map)
 #define node_online(node)	node_isset((node), node_online_map)
 #define node_possible(node)	node_isset((node), node_possible_map)
+#define first_online_node	first_node(node_online_map)
+#define next_online_node(nid)	next_node((nid), node_online_map)
 #else
 #define num_online_nodes()	1
 #define num_possible_nodes()	1
 #define node_online(node)	((node) == 0)
 #define node_possible(node)	((node) == 0)
+#define first_online_node	0
+#define next_online_node(nid)	(MAX_NUMNODES)
 #endif
 
 #define any_online_node(mask)			\
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 5937dd60..51dbab9 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -10,25 +10,107 @@
 #ifndef _LINUX_NOTIFIER_H
 #define _LINUX_NOTIFIER_H
 #include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
 
-struct notifier_block
-{
-	int (*notifier_call)(struct notifier_block *self, unsigned long, void *);
+/*
+ * Notifier chains are of three types:
+ *
+ *	Atomic notifier chains: Chain callbacks run in interrupt/atomic
+ *		context. Callouts are not allowed to block.
+ *	Blocking notifier chains: Chain callbacks run in process context.
+ *		Callouts are allowed to block.
+ *	Raw notifier chains: There are no restrictions on callbacks,
+ *		registration, or unregistration.  All locking and protection
+ *		must be provided by the caller.
+ *
+ * atomic_notifier_chain_register() may be called from an atomic context,
+ * but blocking_notifier_chain_register() must be called from a process
+ * context.  Ditto for the corresponding _unregister() routines.
+ *
+ * atomic_notifier_chain_unregister() and blocking_notifier_chain_unregister()
+ * _must not_ be called from within the call chain.
+ */
+
+struct notifier_block {
+	int (*notifier_call)(struct notifier_block *, unsigned long, void *);
 	struct notifier_block *next;
 	int priority;
 };
 
+struct atomic_notifier_head {
+	spinlock_t lock;
+	struct notifier_block *head;
+};
+
+struct blocking_notifier_head {
+	struct rw_semaphore rwsem;
+	struct notifier_block *head;
+};
+
+struct raw_notifier_head {
+	struct notifier_block *head;
+};
+
+#define ATOMIC_INIT_NOTIFIER_HEAD(name) do {	\
+		spin_lock_init(&(name)->lock);	\
+		(name)->head = NULL;		\
+	} while (0)
+#define BLOCKING_INIT_NOTIFIER_HEAD(name) do {	\
+		init_rwsem(&(name)->rwsem);	\
+		(name)->head = NULL;		\
+	} while (0)
+#define RAW_INIT_NOTIFIER_HEAD(name) do {	\
+		(name)->head = NULL;		\
+	} while (0)
+
+#define ATOMIC_NOTIFIER_INIT(name) {				\
+		.lock = SPIN_LOCK_UNLOCKED,			\
+		.head = NULL }
+#define BLOCKING_NOTIFIER_INIT(name) {				\
+		.rwsem = __RWSEM_INITIALIZER((name).rwsem),	\
+		.head = NULL }
+#define RAW_NOTIFIER_INIT(name)	{				\
+		.head = NULL }
+
+#define ATOMIC_NOTIFIER_HEAD(name)				\
+	struct atomic_notifier_head name =			\
+		ATOMIC_NOTIFIER_INIT(name)
+#define BLOCKING_NOTIFIER_HEAD(name)				\
+	struct blocking_notifier_head name =			\
+		BLOCKING_NOTIFIER_INIT(name)
+#define RAW_NOTIFIER_HEAD(name)					\
+	struct raw_notifier_head name =				\
+		RAW_NOTIFIER_INIT(name)
 
 #ifdef __KERNEL__
 
-extern int notifier_chain_register(struct notifier_block **list, struct notifier_block *n);
-extern int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n);
-extern int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v);
+extern int atomic_notifier_chain_register(struct atomic_notifier_head *,
+		struct notifier_block *);
+extern int blocking_notifier_chain_register(struct blocking_notifier_head *,
+		struct notifier_block *);
+extern int raw_notifier_chain_register(struct raw_notifier_head *,
+		struct notifier_block *);
+
+extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *,
+		struct notifier_block *);
+extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *,
+		struct notifier_block *);
+extern int raw_notifier_chain_unregister(struct raw_notifier_head *,
+		struct notifier_block *);
+
+extern int atomic_notifier_call_chain(struct atomic_notifier_head *,
+		unsigned long val, void *v);
+extern int blocking_notifier_call_chain(struct blocking_notifier_head *,
+		unsigned long val, void *v);
+extern int raw_notifier_call_chain(struct raw_notifier_head *,
+		unsigned long val, void *v);
 
 #define NOTIFY_DONE		0x0000		/* Don't care */
 #define NOTIFY_OK		0x0001		/* Suits me */
 #define NOTIFY_STOP_MASK	0x8000		/* Don't call further */
-#define NOTIFY_BAD		(NOTIFY_STOP_MASK|0x0002)	/* Bad/Veto action	*/
+#define NOTIFY_BAD		(NOTIFY_STOP_MASK|0x0002)
+						/* Bad/Veto action */
 /*
  * Clean way to return from the notifier and stop further calls.
  */
diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h
index 559c4c3..0d514b2 100644
--- a/include/linux/oprofile.h
+++ b/include/linux/oprofile.h
@@ -61,6 +61,16 @@
  */
 void oprofile_add_sample(struct pt_regs * const regs, unsigned long event);
 
+/**
+ * Add an extended sample.  Use this when the PC is not from the regs, and
+ * we cannot determine if we're in kernel mode from the regs.
+ *
+ * This function does perform a backtrace.
+ *
+ */
+void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
+				unsigned long event, int is_kernel);
+
 /* Use this instead when the PC value is not from the regs. Doesn't
  * backtrace. */
 void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event);
@@ -74,10 +84,10 @@
  * the specified file operations.
  */
 int oprofilefs_create_file(struct super_block * sb, struct dentry * root,
-	char const * name, struct file_operations * fops);
+	char const * name, const struct file_operations * fops);
 
 int oprofilefs_create_file_perm(struct super_block * sb, struct dentry * root,
-	char const * name, struct file_operations * fops, int perm);
+	char const * name, const struct file_operations * fops, int perm);
  
 /** Create a file for read/write access to an unsigned long. */
 int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root,
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 839f0b3..9539efd 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -72,8 +72,8 @@
 				unsigned long index);
 extern struct page * find_lock_page(struct address_space *mapping,
 				unsigned long index);
-extern struct page * find_trylock_page(struct address_space *mapping,
-				unsigned long index);
+extern __deprecated_for_modules struct page * find_trylock_page(
+			struct address_space *mapping, unsigned long index);
 extern struct page * find_or_create_page(struct address_space *mapping,
 				unsigned long index, gfp_t gfp_mask);
 unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 6f080ae..870fe38 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -642,6 +642,7 @@
 #define PCI_DEVICE_ID_SI_965		0x0965
 #define PCI_DEVICE_ID_SI_5511		0x5511
 #define PCI_DEVICE_ID_SI_5513		0x5513
+#define PCI_DEVICE_ID_SI_5517		0x5517
 #define PCI_DEVICE_ID_SI_5518		0x5518
 #define PCI_DEVICE_ID_SI_5571		0x5571
 #define PCI_DEVICE_ID_SI_5581		0x5581
@@ -772,6 +773,7 @@
 #define PCI_DEVICE_ID_MOTOROLA_HAWK	0x4803
 #define PCI_DEVICE_ID_MOTOROLA_HARRIER	0x480b
 #define PCI_DEVICE_ID_MOTOROLA_MPC5200	0x5803
+#define PCI_DEVICE_ID_MOTOROLA_MPC5200B	0x5809
 
 #define PCI_VENDOR_ID_PROMISE		0x105a
 #define PCI_DEVICE_ID_PROMISE_20265	0x0d30
@@ -1052,6 +1054,7 @@
 #define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2 0x00f2
 #define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1 0x00f3
 #define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT   0x00f9
+#define PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280	0x00fd
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR	0x0100
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR	0x0101
 #define PCI_DEVICE_ID_NVIDIA_QUADRO		0x0103
diff --git a/include/linux/pfn.h b/include/linux/pfn.h
new file mode 100644
index 0000000..bb01f8b
--- /dev/null
+++ b/include/linux/pfn.h
@@ -0,0 +1,9 @@
+#ifndef _LINUX_PFN_H_
+#define _LINUX_PFN_H_
+
+#define PFN_ALIGN(x)	(((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
+#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
+
+#endif
diff --git a/include/linux/pid.h b/include/linux/pid.h
index 5b2fcb1..29960b0 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -1,55 +1,119 @@
 #ifndef _LINUX_PID_H
 #define _LINUX_PID_H
 
+#include <linux/rcupdate.h>
+
 enum pid_type
 {
 	PIDTYPE_PID,
-	PIDTYPE_TGID,
 	PIDTYPE_PGID,
 	PIDTYPE_SID,
 	PIDTYPE_MAX
 };
 
+/*
+ * What is struct pid?
+ *
+ * A struct pid is the kernel's internal notion of a process identifier.
+ * It refers to individual tasks, process groups, and sessions.  While
+ * there are processes attached to it the struct pid lives in a hash
+ * table, so it and then the processes that it refers to can be found
+ * quickly from the numeric pid value.  The attached processes may be
+ * quickly accessed by following pointers from struct pid.
+ *
+ * Storing pid_t values in the kernel and refering to them later has a
+ * problem.  The process originally with that pid may have exited and the
+ * pid allocator wrapped, and another process could have come along
+ * and been assigned that pid.
+ *
+ * Referring to user space processes by holding a reference to struct
+ * task_struct has a problem.  When the user space process exits
+ * the now useless task_struct is still kept.  A task_struct plus a
+ * stack consumes around 10K of low kernel memory.  More precisely
+ * this is THREAD_SIZE + sizeof(struct task_struct).  By comparison
+ * a struct pid is about 64 bytes.
+ *
+ * Holding a reference to struct pid solves both of these problems.
+ * It is small so holding a reference does not consume a lot of
+ * resources, and since a new struct pid is allocated when the numeric
+ * pid value is reused we don't mistakenly refer to new processes.
+ */
+
 struct pid
 {
+	atomic_t count;
 	/* Try to keep pid_chain in the same cacheline as nr for find_pid */
 	int nr;
 	struct hlist_node pid_chain;
-	/* list of pids with the same nr, only one of them is in the hash */
-	struct list_head pid_list;
+	/* lists of tasks that use this pid */
+	struct hlist_head tasks[PIDTYPE_MAX];
+	struct rcu_head rcu;
 };
 
-#define pid_task(elem, type) \
-	list_entry(elem, struct task_struct, pids[type].pid_list)
+struct pid_link
+{
+	struct hlist_node node;
+	struct pid *pid;
+};
+
+static inline struct pid *get_pid(struct pid *pid)
+{
+	if (pid)
+		atomic_inc(&pid->count);
+	return pid;
+}
+
+extern void FASTCALL(put_pid(struct pid *pid));
+extern struct task_struct *FASTCALL(pid_task(struct pid *pid, enum pid_type));
+extern struct task_struct *FASTCALL(get_pid_task(struct pid *pid,
+						enum pid_type));
 
 /*
  * attach_pid() and detach_pid() must be called with the tasklist_lock
  * write-held.
  */
-extern int FASTCALL(attach_pid(struct task_struct *task, enum pid_type type, int nr));
+extern int FASTCALL(attach_pid(struct task_struct *task,
+				enum pid_type type, int nr));
 
 extern void FASTCALL(detach_pid(struct task_struct *task, enum pid_type));
 
 /*
  * look up a PID in the hash table. Must be called with the tasklist_lock
- * held.
+ * or rcu_read_lock() held.
  */
-extern struct pid *FASTCALL(find_pid(enum pid_type, int));
+extern struct pid *FASTCALL(find_pid(int nr));
 
-extern int alloc_pidmap(void);
-extern void FASTCALL(free_pidmap(int));
-extern void switch_exec_pids(struct task_struct *leader, struct task_struct *thread);
+/*
+ * Lookup a PID in the hash table, and return with it's count elevated.
+ */
+extern struct pid *find_get_pid(int nr);
 
+extern struct pid *alloc_pid(void);
+extern void FASTCALL(free_pid(struct pid *pid));
+
+#define pid_next(task, type)					\
+	((task)->pids[(type)].node.next)
+
+#define pid_next_task(task, type) 				\
+	hlist_entry(pid_next(task, type), struct task_struct,	\
+			pids[(type)].node)
+
+
+/* We could use hlist_for_each_entry_rcu here but it takes more arguments
+ * than the do_each_task_pid/while_each_task_pid.  So we roll our own
+ * to preserve the existing interface.
+ */
 #define do_each_task_pid(who, type, task)				\
 	if ((task = find_task_by_pid_type(type, who))) {		\
-		prefetch((task)->pids[type].pid_list.next);		\
+		prefetch(pid_next(task, type));				\
 		do {
 
 #define while_each_task_pid(who, type, task)				\
-		} while (task = pid_task((task)->pids[type].pid_list.next,\
-						type),			\
-			prefetch((task)->pids[type].pid_list.next),	\
-			hlist_unhashed(&(task)->pids[type].pid_chain));	\
-	}								\
+		} while (pid_next(task, type) &&  ({			\
+				task = pid_next_task(task, type);	\
+				rcu_dereference(task);			\
+				prefetch(pid_next(task, type));		\
+				1; }) );				\
+	}
 
 #endif /* _LINUX_PID_H */
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
index b12e59c..75c7f55 100644
--- a/include/linux/pipe_fs_i.h
+++ b/include/linux/pipe_fs_i.h
@@ -9,6 +9,7 @@
 	struct page *page;
 	unsigned int offset, len;
 	struct pipe_buf_operations *ops;
+	unsigned int stolen;
 };
 
 struct pipe_buf_operations {
@@ -16,6 +17,7 @@
 	void * (*map)(struct file *, struct pipe_inode_info *, struct pipe_buffer *);
 	void (*unmap)(struct pipe_inode_info *, struct pipe_buffer *);
 	void (*release)(struct pipe_inode_info *, struct pipe_buffer *);
+	int (*steal)(struct pipe_inode_info *, struct pipe_buffer *);
 };
 
 struct pipe_inode_info {
@@ -53,4 +55,10 @@
 struct inode* pipe_new(struct inode* inode);
 void free_pipe_info(struct inode* inode);
 
+/*
+ * splice is tied to pipes as a transport (at least for now), so we'll just
+ * add the splice flags here.
+ */
+#define SPLICE_F_MOVE	(0x01)	/* move pages instead of copying */
+
 #endif
diff --git a/include/linux/poll.h b/include/linux/poll.h
index 8e8f609..51e1b56 100644
--- a/include/linux/poll.h
+++ b/include/linux/poll.h
@@ -11,6 +11,15 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 
+/* ~832 bytes of stack space used max in sys_select/sys_poll before allocating
+   additional memory. */
+#define MAX_STACK_ALLOC 832
+#define FRONTEND_STACK_ALLOC	256
+#define SELECT_STACK_ALLOC	FRONTEND_STACK_ALLOC
+#define POLL_STACK_ALLOC	FRONTEND_STACK_ALLOC
+#define WQUEUES_STACK_ALLOC	(MAX_STACK_ALLOC - FRONTEND_STACK_ALLOC)
+#define N_INLINE_POLL_ENTRIES	(WQUEUES_STACK_ALLOC / sizeof(struct poll_table_entry))
+
 struct poll_table_struct;
 
 /* 
@@ -33,6 +42,12 @@
 	pt->qproc = qproc;
 }
 
+struct poll_table_entry {
+	struct file * filp;
+	wait_queue_t wait;
+	wait_queue_head_t * wait_address;
+};
+
 /*
  * Structures and helpers for sys_poll/sys_poll
  */
@@ -40,6 +55,8 @@
 	poll_table pt;
 	struct poll_table_page * table;
 	int error;
+	int inline_index;
+	struct poll_table_entry inline_entries[N_INLINE_POLL_ENTRIES];
 };
 
 extern void poll_initwait(struct poll_wqueues *pwq);
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index aa6322d..135871d 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -4,6 +4,7 @@
 #include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
+#include <linux/spinlock.h>
 #include <asm/atomic.h>
 
 /*
@@ -55,9 +56,9 @@
 	nlink_t nlink;
 	uid_t uid;
 	gid_t gid;
-	unsigned long size;
+	loff_t size;
 	struct inode_operations * proc_iops;
-	struct file_operations * proc_fops;
+	const struct file_operations * proc_fops;
 	get_info_t *get_info;
 	struct module *owner;
 	struct proc_dir_entry *next, *parent, *subdir;
@@ -92,6 +93,8 @@
 extern struct proc_dir_entry *proc_root_driver;
 extern struct proc_dir_entry *proc_root_kcore;
 
+extern spinlock_t proc_subdir_lock;
+
 extern void proc_root_init(void);
 extern void proc_misc_init(void);
 
@@ -125,9 +128,9 @@
 extern int proc_readdir(struct file *, void *, filldir_t);
 extern struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *);
 
-extern struct file_operations proc_kcore_operations;
-extern struct file_operations proc_kmsg_operations;
-extern struct file_operations ppc_htab_operations;
+extern const struct file_operations proc_kcore_operations;
+extern const struct file_operations proc_kmsg_operations;
+extern const struct file_operations ppc_htab_operations;
 
 /*
  * proc_tty.c
@@ -186,7 +189,7 @@
 }
 
 static inline struct proc_dir_entry *proc_net_fops_create(const char *name,
-	mode_t mode, struct file_operations *fops)
+	mode_t mode, const struct file_operations *fops)
 {
 	struct proc_dir_entry *res = create_proc_entry(name, mode, proc_net);
 	if (res)
diff --git a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h
index fc610bb..27f49c8 100644
--- a/include/linux/qnx4_fs.h
+++ b/include/linux/qnx4_fs.h
@@ -118,8 +118,8 @@
 
 extern struct inode_operations qnx4_file_inode_operations;
 extern struct inode_operations qnx4_dir_inode_operations;
-extern struct file_operations qnx4_file_operations;
-extern struct file_operations qnx4_dir_operations;
+extern const struct file_operations qnx4_file_operations;
+extern const struct file_operations qnx4_dir_operations;
 extern int qnx4_is_free(struct super_block *sb, long block);
 extern int qnx4_set_bitmap(struct super_block *sb, long block, int busy);
 extern int qnx4_create(struct inode *inode, struct dentry *dentry, int mode, struct nameidata *nd);
diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h
index b6e0bca..66b44e5 100644
--- a/include/linux/raid/md.h
+++ b/include/linux/raid/md.h
@@ -92,7 +92,10 @@
 extern void md_super_wait(mddev_t *mddev);
 extern int sync_page_io(struct block_device *bdev, sector_t sector, int size,
 			struct page *page, int rw);
+extern void md_do_sync(mddev_t *mddev);
+extern void md_new_event(mddev_t *mddev);
 
+extern void md_update_sb(mddev_t * mddev);
 
 #define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); }
 
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index 617b950..e2df61f 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -132,6 +132,14 @@
 
 	char				uuid[16];
 
+	/* If the array is being reshaped, we need to record the
+	 * new shape and an indication of where we are up to.
+	 * This is written to the superblock.
+	 * If reshape_position is MaxSector, then no reshape is happening (yet).
+	 */
+	sector_t			reshape_position;
+	int				delta_disks, new_level, new_layout, new_chunk;
+
 	struct mdk_thread_s		*thread;	/* management thread */
 	struct mdk_thread_s		*sync_thread;	/* doing resync or reconstruct */
 	sector_t			curr_resync;	/* blocks scheduled */
@@ -143,6 +151,10 @@
 	sector_t			resync_mismatches; /* count of sectors where
 							    * parity/replica mismatch found
 							    */
+
+	/* allow user-space to request suspension of IO to regions of the array */
+	sector_t			suspend_lo;
+	sector_t			suspend_hi;
 	/* if zero, use the system-wide default */
 	int				sync_speed_min;
 	int				sync_speed_max;
@@ -157,6 +169,9 @@
 	 * DONE:     thread is done and is waiting to be reaped
 	 * REQUEST:  user-space has requested a sync (used with SYNC)
 	 * CHECK:    user-space request for for check-only, no repair
+	 * RESHAPE:  A reshape is happening
+	 *
+	 * If neither SYNC or RESHAPE are set, then it is a recovery.
 	 */
 #define	MD_RECOVERY_RUNNING	0
 #define	MD_RECOVERY_SYNC	1
@@ -166,10 +181,11 @@
 #define	MD_RECOVERY_NEEDED	5
 #define	MD_RECOVERY_REQUESTED	6
 #define	MD_RECOVERY_CHECK	7
+#define MD_RECOVERY_RESHAPE	8
 	unsigned long			recovery;
 
 	int				in_sync;	/* know to not need resync */
-	struct semaphore		reconfig_sem;
+	struct mutex			reconfig_mutex;
 	atomic_t			active;
 
 	int				changed;	/* true if we might need to reread partition info */
@@ -249,7 +265,8 @@
 	int (*spare_active) (mddev_t *mddev);
 	sector_t (*sync_request)(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster);
 	int (*resize) (mddev_t *mddev, sector_t sectors);
-	int (*reshape) (mddev_t *mddev, int raid_disks);
+	int (*check_reshape) (mddev_t *mddev);
+	int (*start_reshape) (mddev_t *mddev);
 	int (*reconfig) (mddev_t *mddev, int layout, int chunk_size);
 	/* quiesce moves between quiescence states
 	 * 0 - fully active
diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h
index c100fa5..774e1ac 100644
--- a/include/linux/raid/md_p.h
+++ b/include/linux/raid/md_p.h
@@ -102,6 +102,18 @@
 #define MD_SB_ERRORS		1
 
 #define	MD_SB_BITMAP_PRESENT	8 /* bitmap may be present nearby */
+
+/*
+ * Notes:
+ * - if an array is being reshaped (restriped) in order to change the
+ *   the number of active devices in the array, 'raid_disks' will be
+ *   the larger of the old and new numbers.  'delta_disks' will
+ *   be the "new - old".  So if +ve, raid_disks is the new value, and
+ *   "raid_disks-delta_disks" is the old.  If -ve, raid_disks is the
+ *   old value and "raid_disks+delta_disks" is the new (smaller) value.
+ */
+
+
 typedef struct mdp_superblock_s {
 	/*
 	 * Constant generic information
@@ -146,7 +158,13 @@
 	__u32 cp_events_hi;	/* 10 high-order of checkpoint update count   */
 #endif
 	__u32 recovery_cp;	/* 11 recovery checkpoint sector count	      */
-	__u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 12];
+	/* There are only valid for minor_version > 90 */
+	__u64 reshape_position;	/* 12,13 next address in array-space for reshape */
+	__u32 new_level;	/* 14 new level we are reshaping to	      */
+	__u32 delta_disks;	/* 15 change in number of raid_disks	      */
+	__u32 new_layout;	/* 16 new layout			      */
+	__u32 new_chunk;	/* 17 new chunk size (bytes)		      */
+	__u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 18];
 
 	/*
 	 * Personality information
@@ -207,7 +225,14 @@
 				 * NOTE: signed, so bitmap can be before superblock
 				 * only meaningful of feature_map[0] is set.
 				 */
-	__u8	pad1[128-100];	/* set to 0 when written */
+
+	/* These are only valid with feature bit '4' */
+	__u64	reshape_position;	/* next address in array-space for reshape */
+	__u32	new_level;	/* new level we are reshaping to		*/
+	__u32	delta_disks;	/* change in number of raid_disks		*/
+	__u32	new_layout;	/* new layout					*/
+	__u32	new_chunk;	/* new chunk size (bytes)			*/
+	__u8	pad1[128-124];	/* set to 0 when written */
 
 	/* constant this-device information - 64 bytes */
 	__u64	data_offset;	/* sector start of data, often 0 */
@@ -240,8 +265,9 @@
 
 /* feature_map bits */
 #define MD_FEATURE_BITMAP_OFFSET	1
+#define	MD_FEATURE_RESHAPE_ACTIVE	4
 
-#define	MD_FEATURE_ALL			1
+#define	MD_FEATURE_ALL			5
 
 #endif 
 
diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h
index 394da82..914af66 100644
--- a/include/linux/raid/raid5.h
+++ b/include/linux/raid/raid5.h
@@ -135,6 +135,7 @@
 	atomic_t		count;			/* nr of active thread/requests */
 	spinlock_t		lock;
 	int			bm_seq;	/* sequence number for bitmap flushes */
+	int			disks;			/* disks in stripe */
 	struct r5dev {
 		struct bio	req;
 		struct bio_vec	vec;
@@ -156,6 +157,7 @@
 #define	R5_ReadError	8	/* seen a read error here recently */
 #define	R5_ReWrite	9	/* have tried to over-write the readerror */
 
+#define	R5_Expanded	10	/* This block now has post-expand data */
 /*
  * Write method
  */
@@ -174,7 +176,9 @@
 #define	STRIPE_DELAYED		6
 #define	STRIPE_DEGRADED		7
 #define	STRIPE_BIT_DELAY	8
-
+#define	STRIPE_EXPANDING	9
+#define	STRIPE_EXPAND_SOURCE	10
+#define	STRIPE_EXPAND_READY	11
 /*
  * Plugging:
  *
@@ -211,12 +215,24 @@
 	int			raid_disks, working_disks, failed_disks;
 	int			max_nr_stripes;
 
+	/* used during an expand */
+	sector_t		expand_progress;	/* MaxSector when no expand happening */
+	sector_t		expand_lo; /* from here up to expand_progress it out-of-bounds
+					    * as we haven't flushed the metadata yet
+					    */
+	int			previous_raid_disks;
+
 	struct list_head	handle_list; /* stripes needing handling */
 	struct list_head	delayed_list; /* stripes that have plugged requests */
 	struct list_head	bitmap_list; /* stripes delaying awaiting bitmap update */
 	atomic_t		preread_active_stripes; /* stripes with scheduled io */
 
-	char			cache_name[20];
+	atomic_t		reshape_stripes; /* stripes with pending writes for reshape */
+	/* unfortunately we need two cache names as we temporarily have
+	 * two caches.
+	 */
+	int			active_name;
+	char			cache_name[2][20];
 	kmem_cache_t		*slab_cache; /* for allocating stripes */
 
 	int			seq_flush, seq_write;
@@ -238,9 +254,10 @@
 	wait_queue_head_t	wait_for_overlap;
 	int			inactive_blocked;	/* release of inactive stripes blocked,
 							 * waiting for 25% to be free
-							 */        
+							 */
+	int			pool_size; /* number of disks in stripeheads in pool */
 	spinlock_t		device_lock;
-	struct disk_info	disks[0];
+	struct disk_info	*disks;
 };
 
 typedef struct raid5_private_data raid5_conf_t;
diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h
index 953b6df..78ecfa2 100644
--- a/include/linux/ramfs.h
+++ b/include/linux/ramfs.h
@@ -15,7 +15,7 @@
 extern int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma);
 #endif
 
-extern struct file_operations ramfs_file_operations;
+extern const struct file_operations ramfs_file_operations;
 extern struct vm_operations_struct generic_file_vm_ops;
 
 #endif
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index 912f1b7..5676c42 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -1960,7 +1960,7 @@
 extern struct inode_operations reiserfs_dir_inode_operations;
 extern struct inode_operations reiserfs_symlink_inode_operations;
 extern struct inode_operations reiserfs_special_inode_operations;
-extern struct file_operations reiserfs_dir_operations;
+extern const struct file_operations reiserfs_dir_operations;
 
 /* tail_conversion.c */
 int direct2indirect(struct reiserfs_transaction_handle *, struct inode *,
@@ -1972,7 +1972,7 @@
 
 /* file.c */
 extern struct inode_operations reiserfs_file_inode_operations;
-extern struct file_operations reiserfs_file_operations;
+extern const struct file_operations reiserfs_file_operations;
 extern struct address_space_operations reiserfs_address_space_operations;
 
 /* fix_nodes.c */
diff --git a/include/linux/relayfs_fs.h b/include/linux/relayfs_fs.h
deleted file mode 100644
index 7342e66..0000000
--- a/include/linux/relayfs_fs.h
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * linux/include/linux/relayfs_fs.h
- *
- * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
- * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com)
- *
- * RelayFS definitions and declarations
- */
-
-#ifndef _LINUX_RELAYFS_FS_H
-#define _LINUX_RELAYFS_FS_H
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/kref.h>
-
-/*
- * Tracks changes to rchan/rchan_buf structs
- */
-#define RELAYFS_CHANNEL_VERSION		6
-
-/*
- * Per-cpu relay channel buffer
- */
-struct rchan_buf
-{
-	void *start;			/* start of channel buffer */
-	void *data;			/* start of current sub-buffer */
-	size_t offset;			/* current offset into sub-buffer */
-	size_t subbufs_produced;	/* count of sub-buffers produced */
-	size_t subbufs_consumed;	/* count of sub-buffers consumed */
-	struct rchan *chan;		/* associated channel */
-	wait_queue_head_t read_wait;	/* reader wait queue */
-	struct work_struct wake_readers; /* reader wake-up work struct */
-	struct dentry *dentry;		/* channel file dentry */
-	struct kref kref;		/* channel buffer refcount */
-	struct page **page_array;	/* array of current buffer pages */
-	unsigned int page_count;	/* number of current buffer pages */
-	unsigned int finalized;		/* buffer has been finalized */
-	size_t *padding;		/* padding counts per sub-buffer */
-	size_t prev_padding;		/* temporary variable */
-	size_t bytes_consumed;		/* bytes consumed in cur read subbuf */
-	unsigned int cpu;		/* this buf's cpu */
-} ____cacheline_aligned;
-
-/*
- * Relay channel data structure
- */
-struct rchan
-{
-	u32 version;			/* the version of this struct */
-	size_t subbuf_size;		/* sub-buffer size */
-	size_t n_subbufs;		/* number of sub-buffers per buffer */
-	size_t alloc_size;		/* total buffer size allocated */
-	struct rchan_callbacks *cb;	/* client callbacks */
-	struct kref kref;		/* channel refcount */
-	void *private_data;		/* for user-defined data */
-	size_t last_toobig;		/* tried to log event > subbuf size */
-	struct rchan_buf *buf[NR_CPUS]; /* per-cpu channel buffers */
-};
-
-/*
- * Relay channel client callbacks
- */
-struct rchan_callbacks
-{
-	/*
-	 * subbuf_start - called on buffer-switch to a new sub-buffer
-	 * @buf: the channel buffer containing the new sub-buffer
-	 * @subbuf: the start of the new sub-buffer
-	 * @prev_subbuf: the start of the previous sub-buffer
-	 * @prev_padding: unused space at the end of previous sub-buffer
-	 *
-	 * The client should return 1 to continue logging, 0 to stop
-	 * logging.
-	 *
-	 * NOTE: subbuf_start will also be invoked when the buffer is
-	 *       created, so that the first sub-buffer can be initialized
-	 *       if necessary.  In this case, prev_subbuf will be NULL.
-	 *
-	 * NOTE: the client can reserve bytes at the beginning of the new
-	 *       sub-buffer by calling subbuf_start_reserve() in this callback.
-	 */
-	int (*subbuf_start) (struct rchan_buf *buf,
-			     void *subbuf,
-			     void *prev_subbuf,
-			     size_t prev_padding);
-
-	/*
-	 * buf_mapped - relayfs buffer mmap notification
-	 * @buf: the channel buffer
-	 * @filp: relayfs file pointer
-	 *
-	 * Called when a relayfs file is successfully mmapped
-	 */
-        void (*buf_mapped)(struct rchan_buf *buf,
-			   struct file *filp);
-
-	/*
-	 * buf_unmapped - relayfs buffer unmap notification
-	 * @buf: the channel buffer
-	 * @filp: relayfs file pointer
-	 *
-	 * Called when a relayfs file is successfully unmapped
-	 */
-        void (*buf_unmapped)(struct rchan_buf *buf,
-			     struct file *filp);
-	/*
-	 * create_buf_file - create file to represent a relayfs channel buffer
-	 * @filename: the name of the file to create
-	 * @parent: the parent of the file to create
-	 * @mode: the mode of the file to create
-	 * @buf: the channel buffer
-	 * @is_global: outparam - set non-zero if the buffer should be global
-	 *
-	 * Called during relay_open(), once for each per-cpu buffer,
-	 * to allow the client to create a file to be used to
-	 * represent the corresponding channel buffer.  If the file is
-	 * created outside of relayfs, the parent must also exist in
-	 * that filesystem.
-	 *
-	 * The callback should return the dentry of the file created
-	 * to represent the relay buffer.
-	 *
-	 * Setting the is_global outparam to a non-zero value will
-	 * cause relay_open() to create a single global buffer rather
-	 * than the default set of per-cpu buffers.
-	 *
-	 * See Documentation/filesystems/relayfs.txt for more info.
-	 */
-	struct dentry *(*create_buf_file)(const char *filename,
-					  struct dentry *parent,
-					  int mode,
-					  struct rchan_buf *buf,
-					  int *is_global);
-
-	/*
-	 * remove_buf_file - remove file representing a relayfs channel buffer
-	 * @dentry: the dentry of the file to remove
-	 *
-	 * Called during relay_close(), once for each per-cpu buffer,
-	 * to allow the client to remove a file used to represent a
-	 * channel buffer.
-	 *
-	 * The callback should return 0 if successful, negative if not.
-	 */
-	int (*remove_buf_file)(struct dentry *dentry);
-};
-
-/*
- * relayfs kernel API, fs/relayfs/relay.c
- */
-
-struct rchan *relay_open(const char *base_filename,
-			 struct dentry *parent,
-			 size_t subbuf_size,
-			 size_t n_subbufs,
-			 struct rchan_callbacks *cb);
-extern void relay_close(struct rchan *chan);
-extern void relay_flush(struct rchan *chan);
-extern void relay_subbufs_consumed(struct rchan *chan,
-				   unsigned int cpu,
-				   size_t consumed);
-extern void relay_reset(struct rchan *chan);
-extern int relay_buf_full(struct rchan_buf *buf);
-
-extern size_t relay_switch_subbuf(struct rchan_buf *buf,
-				  size_t length);
-extern struct dentry *relayfs_create_dir(const char *name,
-					 struct dentry *parent);
-extern int relayfs_remove_dir(struct dentry *dentry);
-extern struct dentry *relayfs_create_file(const char *name,
-					  struct dentry *parent,
-					  int mode,
-					  struct file_operations *fops,
-					  void *data);
-extern int relayfs_remove_file(struct dentry *dentry);
-
-/**
- *	relay_write - write data into the channel
- *	@chan: relay channel
- *	@data: data to be written
- *	@length: number of bytes to write
- *
- *	Writes data into the current cpu's channel buffer.
- *
- *	Protects the buffer by disabling interrupts.  Use this
- *	if you might be logging from interrupt context.  Try
- *	__relay_write() if you know you	won't be logging from
- *	interrupt context.
- */
-static inline void relay_write(struct rchan *chan,
-			       const void *data,
-			       size_t length)
-{
-	unsigned long flags;
-	struct rchan_buf *buf;
-
-	local_irq_save(flags);
-	buf = chan->buf[smp_processor_id()];
-	if (unlikely(buf->offset + length > chan->subbuf_size))
-		length = relay_switch_subbuf(buf, length);
-	memcpy(buf->data + buf->offset, data, length);
-	buf->offset += length;
-	local_irq_restore(flags);
-}
-
-/**
- *	__relay_write - write data into the channel
- *	@chan: relay channel
- *	@data: data to be written
- *	@length: number of bytes to write
- *
- *	Writes data into the current cpu's channel buffer.
- *
- *	Protects the buffer by disabling preemption.  Use
- *	relay_write() if you might be logging from interrupt
- *	context.
- */
-static inline void __relay_write(struct rchan *chan,
-				 const void *data,
-				 size_t length)
-{
-	struct rchan_buf *buf;
-
-	buf = chan->buf[get_cpu()];
-	if (unlikely(buf->offset + length > buf->chan->subbuf_size))
-		length = relay_switch_subbuf(buf, length);
-	memcpy(buf->data + buf->offset, data, length);
-	buf->offset += length;
-	put_cpu();
-}
-
-/**
- *	relay_reserve - reserve slot in channel buffer
- *	@chan: relay channel
- *	@length: number of bytes to reserve
- *
- *	Returns pointer to reserved slot, NULL if full.
- *
- *	Reserves a slot in the current cpu's channel buffer.
- *	Does not protect the buffer at all - caller must provide
- *	appropriate synchronization.
- */
-static inline void *relay_reserve(struct rchan *chan, size_t length)
-{
-	void *reserved;
-	struct rchan_buf *buf = chan->buf[smp_processor_id()];
-
-	if (unlikely(buf->offset + length > buf->chan->subbuf_size)) {
-		length = relay_switch_subbuf(buf, length);
-		if (!length)
-			return NULL;
-	}
-	reserved = buf->data + buf->offset;
-	buf->offset += length;
-
-	return reserved;
-}
-
-/**
- *	subbuf_start_reserve - reserve bytes at the start of a sub-buffer
- *	@buf: relay channel buffer
- *	@length: number of bytes to reserve
- *
- *	Helper function used to reserve bytes at the beginning of
- *	a sub-buffer in the subbuf_start() callback.
- */
-static inline void subbuf_start_reserve(struct rchan_buf *buf,
-					size_t length)
-{
-	BUG_ON(length >= buf->chan->subbuf_size - 1);
-	buf->offset = length;
-}
-
-/*
- * exported relay file operations, fs/relayfs/inode.c
- */
-extern struct file_operations relay_file_operations;
-
-#endif /* _LINUX_RELAYFS_FS_H */
-
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index b739ac1..ab61cd11 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -91,10 +91,102 @@
 #define RTC_PLL_GET	_IOR('p', 0x11, struct rtc_pll_info)  /* Get PLL correction */
 #define RTC_PLL_SET	_IOW('p', 0x12, struct rtc_pll_info)  /* Set PLL correction */
 
+/* interrupt flags */
+#define RTC_IRQF 0x80 /* any of the following is active */
+#define RTC_PF 0x40
+#define RTC_AF 0x20
+#define RTC_UF 0x10
+
 #ifdef __KERNEL__
 
 #include <linux/interrupt.h>
 
+extern int rtc_month_days(unsigned int month, unsigned int year);
+extern int rtc_valid_tm(struct rtc_time *tm);
+extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
+extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
+
+#include <linux/device.h>
+#include <linux/seq_file.h>
+#include <linux/cdev.h>
+#include <linux/poll.h>
+#include <linux/mutex.h>
+
+extern struct class *rtc_class;
+
+struct rtc_class_ops {
+	int (*open)(struct device *);
+	void (*release)(struct device *);
+	int (*ioctl)(struct device *, unsigned int, unsigned long);
+	int (*read_time)(struct device *, struct rtc_time *);
+	int (*set_time)(struct device *, struct rtc_time *);
+	int (*read_alarm)(struct device *, struct rtc_wkalrm *);
+	int (*set_alarm)(struct device *, struct rtc_wkalrm *);
+	int (*proc)(struct device *, struct seq_file *);
+	int (*set_mmss)(struct device *, unsigned long secs);
+	int (*irq_set_state)(struct device *, int enabled);
+	int (*irq_set_freq)(struct device *, int freq);
+	int (*read_callback)(struct device *, int data);
+};
+
+#define RTC_DEVICE_NAME_SIZE 20
+struct rtc_task;
+
+struct rtc_device
+{
+	struct class_device class_dev;
+	struct module *owner;
+
+	int id;
+	char name[RTC_DEVICE_NAME_SIZE];
+
+	struct rtc_class_ops *ops;
+	struct mutex ops_lock;
+
+	struct class_device *rtc_dev;
+	struct cdev char_dev;
+	struct mutex char_lock;
+
+	unsigned long irq_data;
+	spinlock_t irq_lock;
+	wait_queue_head_t irq_queue;
+	struct fasync_struct *async_queue;
+
+	struct rtc_task *irq_task;
+	spinlock_t irq_task_lock;
+	int irq_freq;
+};
+#define to_rtc_device(d) container_of(d, struct rtc_device, class_dev)
+
+extern struct rtc_device *rtc_device_register(const char *name,
+					struct device *dev,
+					struct rtc_class_ops *ops,
+					struct module *owner);
+extern void rtc_device_unregister(struct rtc_device *rdev);
+extern int rtc_interface_register(struct class_interface *intf);
+
+extern int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm);
+extern int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm);
+extern int rtc_set_mmss(struct class_device *class_dev, unsigned long secs);
+extern int rtc_read_alarm(struct class_device *class_dev,
+			struct rtc_wkalrm *alrm);
+extern int rtc_set_alarm(struct class_device *class_dev,
+				struct rtc_wkalrm *alrm);
+extern void rtc_update_irq(struct class_device *class_dev,
+			unsigned long num, unsigned long events);
+
+extern struct class_device *rtc_class_open(char *name);
+extern void rtc_class_close(struct class_device *class_dev);
+
+extern int rtc_irq_register(struct class_device *class_dev,
+				struct rtc_task *task);
+extern void rtc_irq_unregister(struct class_device *class_dev,
+				struct rtc_task *task);
+extern int rtc_irq_set_state(struct class_device *class_dev,
+				struct rtc_task *task, int enabled);
+extern int rtc_irq_set_freq(struct class_device *class_dev,
+				struct rtc_task *task, int freq);
+
 typedef struct rtc_task {
 	void (*func)(void *private_data);
 	void *private_data;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index e0054c1..541f482 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -35,6 +35,7 @@
 #include <linux/topology.h>
 #include <linux/seccomp.h>
 #include <linux/rcupdate.h>
+#include <linux/futex.h>
 
 #include <linux/auxvec.h>	/* For AT_VECTOR_SIZE */
 
@@ -99,6 +100,7 @@
 extern int nr_processes(void);
 extern unsigned long nr_running(void);
 extern unsigned long nr_uninterruptible(void);
+extern unsigned long nr_active(void);
 extern unsigned long nr_iowait(void);
 
 #include <linux/time.h>
@@ -354,16 +356,8 @@
 	atomic_t		count;
 	struct k_sigaction	action[_NSIG];
 	spinlock_t		siglock;
-	struct rcu_head		rcu;
 };
 
-extern void sighand_free_cb(struct rcu_head *rhp);
-
-static inline void sighand_free(struct sighand_struct *sp)
-{
-	call_rcu(&sp->rcu, sighand_free_cb);
-}
-
 /*
  * NOTE! "signal_struct" does not have it's own
  * locking, because a shared signal_struct always
@@ -402,6 +396,7 @@
 
 	/* ITIMER_REAL timer for the process */
 	struct hrtimer real_timer;
+	struct task_struct *tsk;
 	ktime_t it_real_incr;
 
 	/* ITIMER_PROF and ITIMER_VIRTUAL timers for the process */
@@ -489,6 +484,7 @@
 #define MAX_PRIO		(MAX_RT_PRIO + 40)
 
 #define rt_task(p)		(unlikely((p)->prio < MAX_RT_PRIO))
+#define batch_task(p)		(unlikely((p)->policy == SCHED_BATCH))
 
 /*
  * Some day this will be a full-fledged user tracking system..
@@ -689,6 +685,13 @@
 struct audit_context;		/* See audit.c */
 struct mempolicy;
 
+enum sleep_type {
+	SLEEP_NORMAL,
+	SLEEP_NONINTERACTIVE,
+	SLEEP_INTERACTIVE,
+	SLEEP_INTERRUPTED,
+};
+
 struct task_struct {
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	struct thread_info *thread_info;
@@ -711,7 +714,7 @@
 	unsigned long sleep_avg;
 	unsigned long long timestamp, last_ran;
 	unsigned long long sched_time; /* sched_clock time spent running */
-	int activated;
+	enum sleep_type sleep_type;
 
 	unsigned long policy;
 	cpumask_t cpus_allowed;
@@ -757,7 +760,8 @@
 	struct task_struct *group_leader;	/* threadgroup leader */
 
 	/* PID/PID hash table linkage. */
-	struct pid pids[PIDTYPE_MAX];
+	struct pid_link pids[PIDTYPE_MAX];
+	struct list_head thread_group;
 
 	struct completion *vfork_done;		/* for vfork() */
 	int __user *set_child_tid;		/* CLONE_CHILD_SETTID */
@@ -871,6 +875,11 @@
 	int cpuset_mems_generation;
 	int cpuset_mem_spread_rotor;
 #endif
+	struct robust_list_head __user *robust_list;
+#ifdef CONFIG_COMPAT
+	struct compat_robust_list_head __user *compat_robust_list;
+#endif
+
 	atomic_t fs_excl;	/* holding fs exclusive resources */
 	struct rcu_head rcu;
 };
@@ -890,18 +899,19 @@
  */
 static inline int pid_alive(struct task_struct *p)
 {
-	return p->pids[PIDTYPE_PID].nr != 0;
+	return p->pids[PIDTYPE_PID].pid != NULL;
 }
 
 extern void free_task(struct task_struct *tsk);
 #define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0)
 
 extern void __put_task_struct_cb(struct rcu_head *rhp);
+extern void __put_task_struct(struct task_struct *t);
 
 static inline void put_task_struct(struct task_struct *t)
 {
 	if (atomic_dec_and_test(&t->usage))
-		call_rcu(&t->rcu, __put_task_struct_cb);
+		__put_task_struct(t);
 }
 
 /*
@@ -1094,7 +1104,6 @@
 extern int send_sig(int, struct task_struct *, int);
 extern void zap_other_threads(struct task_struct *p);
 extern int kill_pg(pid_t, int, int);
-extern int kill_sl(pid_t, int, int);
 extern int kill_proc(pid_t, int, int);
 extern struct sigqueue *sigqueue_alloc(void);
 extern void sigqueue_free(struct sigqueue *);
@@ -1151,10 +1160,8 @@
 extern void exit_thread(void);
 
 extern void exit_files(struct task_struct *);
-extern void exit_signal(struct task_struct *);
-extern void __exit_signal(struct task_struct *);
-extern void exit_sighand(struct task_struct *);
-extern void __exit_sighand(struct task_struct *);
+extern void __cleanup_signal(struct signal_struct *);
+extern void __cleanup_sighand(struct sighand_struct *);
 extern void exit_itimers(struct signal_struct *);
 
 extern NORET_TYPE void do_group_exit(int);
@@ -1178,19 +1185,7 @@
 #endif
 
 #define remove_parent(p)	list_del_init(&(p)->sibling)
-#define add_parent(p, parent)	list_add_tail(&(p)->sibling,&(parent)->children)
-
-#define REMOVE_LINKS(p) do {					\
-	if (thread_group_leader(p))				\
-		list_del_init(&(p)->tasks);			\
-	remove_parent(p);					\
-	} while (0)
-
-#define SET_LINKS(p) do {					\
-	if (thread_group_leader(p))				\
-		list_add_tail(&(p)->tasks,&init_task.tasks);	\
-	add_parent(p, (p)->parent);				\
-	} while (0)
+#define add_parent(p)		list_add_tail(&(p)->sibling,&(p)->parent->children)
 
 #define next_task(p)	list_entry((p)->tasks.next, struct task_struct, tasks)
 #define prev_task(p)	list_entry((p)->tasks.prev, struct task_struct, tasks)
@@ -1208,20 +1203,22 @@
 #define while_each_thread(g, t) \
 	while ((t = next_thread(t)) != g)
 
-extern task_t * FASTCALL(next_thread(const task_t *p));
-
 #define thread_group_leader(p)	(p->pid == p->tgid)
 
+static inline task_t *next_thread(task_t *p)
+{
+	return list_entry(rcu_dereference(p->thread_group.next),
+				task_t, thread_group);
+}
+
 static inline int thread_group_empty(task_t *p)
 {
-	return list_empty(&p->pids[PIDTYPE_TGID].pid_list);
+	return list_empty(&p->thread_group);
 }
 
 #define delay_group_leader(p) \
 		(thread_group_leader(p) && !thread_group_empty(p))
 
-extern void unhash_process(struct task_struct *p);
-
 /*
  * Protects ->fs, ->files, ->mm, ->ptrace, ->group_info, ->comm, keyring
  * subscriptions and synchronises with wait4().  Also used in procfs.  Also
@@ -1241,6 +1238,15 @@
 	spin_unlock(&p->alloc_lock);
 }
 
+extern struct sighand_struct *lock_task_sighand(struct task_struct *tsk,
+							unsigned long *flags);
+
+static inline void unlock_task_sighand(struct task_struct *tsk,
+						unsigned long *flags)
+{
+	spin_unlock_irqrestore(&tsk->sighand->siglock, *flags);
+}
+
 #ifndef __HAVE_THREAD_FUNCTIONS
 
 #define task_thread_info(task) (task)->thread_info
diff --git a/include/linux/serio.h b/include/linux/serio.h
index aa4d649..690aabc 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -119,7 +119,7 @@
 }
 
 /*
- * Use the following fucntions to manipulate serio's per-port
+ * Use the following functions to manipulate serio's per-port
  * driver-specific data.
  */
 static inline void *serio_get_drvdata(struct serio *serio)
@@ -133,7 +133,7 @@
 }
 
 /*
- * Use the following fucntions to protect critical sections in
+ * Use the following functions to protect critical sections in
  * driver code from port's interrupt handler
  */
 static inline void serio_pause_rx(struct serio *serio)
@@ -147,7 +147,7 @@
 }
 
 /*
- * Use the following fucntions to pin serio's driver in process context
+ * Use the following functions to pin serio's driver in process context
  */
 static inline int serio_pin_driver(struct serio *serio)
 {
diff --git a/include/linux/signal.h b/include/linux/signal.h
index b7d0935..162a8fd 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -249,6 +249,8 @@
 	INIT_LIST_HEAD(&sig->list);
 }
 
+extern void flush_sigqueue(struct sigpending *queue);
+
 /* Test if 'sig' is valid signal. Use this instead of testing _NSIG directly */
 static inline int valid_signal(unsigned long sig)
 {
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 613b951..c4619a4 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -941,6 +941,25 @@
 #define NET_IP_ALIGN	2
 #endif
 
+/*
+ * The networking layer reserves some headroom in skb data (via
+ * dev_alloc_skb). This is used to avoid having to reallocate skb data when
+ * the header has to grow. In the default case, if the header has to grow
+ * 16 bytes or less we avoid the reallocation.
+ *
+ * Unfortunately this headroom changes the DMA alignment of the resulting
+ * network packet. As for NET_IP_ALIGN, this unaligned DMA is expensive
+ * on some architectures. An architecture can override this value,
+ * perhaps setting it to a cacheline in size (since that will maintain
+ * cacheline alignment of the DMA). It must be a power of 2.
+ *
+ * Various parts of the networking layer expect at least 16 bytes of
+ * headroom, you should not reduce this.
+ */
+#ifndef NET_SKB_PAD
+#define NET_SKB_PAD	16
+#endif
+
 extern int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc);
 
 static inline void __skb_trim(struct sk_buff *skb, unsigned int len)
@@ -1030,9 +1049,9 @@
 static inline struct sk_buff *__dev_alloc_skb(unsigned int length,
 					      gfp_t gfp_mask)
 {
-	struct sk_buff *skb = alloc_skb(length + 16, gfp_mask);
+	struct sk_buff *skb = alloc_skb(length + NET_SKB_PAD, gfp_mask);
 	if (likely(skb))
-		skb_reserve(skb, 16);
+		skb_reserve(skb, NET_SKB_PAD);
 	return skb;
 }
 #else
@@ -1070,13 +1089,15 @@
  */
 static inline int skb_cow(struct sk_buff *skb, unsigned int headroom)
 {
-	int delta = (headroom > 16 ? headroom : 16) - skb_headroom(skb);
+	int delta = (headroom > NET_SKB_PAD ? headroom : NET_SKB_PAD) -
+			skb_headroom(skb);
 
 	if (delta < 0)
 		delta = 0;
 
 	if (delta || skb_cloned(skb))
-		return pskb_expand_head(skb, (delta + 15) & ~15, 0, GFP_ATOMIC);
+		return pskb_expand_head(skb, (delta + (NET_SKB_PAD-1)) &
+				~(NET_SKB_PAD-1), 0, GFP_ATOMIC);
 	return 0;
 }
 
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 15e1d97..3af03b1 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -210,7 +210,6 @@
 extern kmem_cache_t	*files_cachep;
 extern kmem_cache_t	*filp_cachep;
 extern kmem_cache_t	*fs_cachep;
-extern kmem_cache_t	*signal_cachep;
 extern kmem_cache_t	*sighand_cachep;
 extern kmem_cache_t	*bio_cachep;
 
diff --git a/include/linux/smp.h b/include/linux/smp.h
index d699a16..e2fa3ab 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -82,7 +82,11 @@
  */
 #define raw_smp_processor_id()			0
 #define hard_smp_processor_id()			0
-#define smp_call_function(func,info,retry,wait)	({ 0; })
+static inline int up_smp_call_function(void)
+{
+	return 0;
+}
+#define smp_call_function(func,info,retry,wait)	(up_smp_call_function())
 #define on_each_cpu(func,info,retry,wait)	\
 	({					\
 		local_irq_disable();		\
diff --git a/include/linux/sound.h b/include/linux/sound.h
index 72b9af4..f63d834 100644
--- a/include/linux/sound.h
+++ b/include/linux/sound.h
@@ -30,12 +30,12 @@
  */
  
 struct device;
-extern int register_sound_special(struct file_operations *fops, int unit);
-extern int register_sound_special_device(struct file_operations *fops, int unit, struct device *dev);
-extern int register_sound_mixer(struct file_operations *fops, int dev);
-extern int register_sound_midi(struct file_operations *fops, int dev);
-extern int register_sound_dsp(struct file_operations *fops, int dev);
-extern int register_sound_synth(struct file_operations *fops, int dev);
+extern int register_sound_special(const struct file_operations *fops, int unit);
+extern int register_sound_special_device(const struct file_operations *fops, int unit, struct device *dev);
+extern int register_sound_mixer(const struct file_operations *fops, int dev);
+extern int register_sound_midi(const struct file_operations *fops, int dev);
+extern int register_sound_dsp(const struct file_operations *fops, int dev);
+extern int register_sound_synth(const struct file_operations *fops, int dev);
 
 extern void unregister_sound_special(int unit);
 extern void unregister_sound_mixer(int unit);
diff --git a/include/linux/stat.h b/include/linux/stat.h
index 8ff2a12..8669291 100644
--- a/include/linux/stat.h
+++ b/include/linux/stat.h
@@ -69,7 +69,7 @@
 	struct timespec	mtime;
 	struct timespec	ctime;
 	unsigned long	blksize;
-	unsigned long	blocks;
+	unsigned long long	blocks;
 };
 
 #endif
diff --git a/include/linux/statfs.h b/include/linux/statfs.h
index ad83a2b..b34cc82 100644
--- a/include/linux/statfs.h
+++ b/include/linux/statfs.h
@@ -8,11 +8,11 @@
 struct kstatfs {
 	long f_type;
 	long f_bsize;
-	sector_t f_blocks;
-	sector_t f_bfree;
-	sector_t f_bavail;
-	sector_t f_files;
-	sector_t f_ffree;
+	u64 f_blocks;
+	u64 f_bfree;
+	u64 f_bavail;
+	u64 f_files;
+	u64 f_ffree;
 	__kernel_fsid_t f_fsid;
 	long f_namelen;
 	long f_frsize;
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index c4e3ea7..b5612c9 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -50,7 +50,7 @@
 	time_t		last_refresh;   /* If CACHE_PENDING, this is when upcall 
 					 * was sent, else this is when update was received
 					 */
-	atomic_t 	refcnt;
+	struct kref	ref;
 	unsigned long	flags;
 };
 #define	CACHE_VALID	0	/* Entry contains valid data */
@@ -68,8 +68,7 @@
 	atomic_t		inuse; /* active user-space update or lookup */
 
 	char			*name;
-	void			(*cache_put)(struct cache_head *,
-					     struct cache_detail*);
+	void			(*cache_put)(struct kref *);
 
 	void			(*cache_request)(struct cache_detail *cd,
 						 struct cache_head *h,
@@ -81,6 +80,11 @@
 					      struct cache_detail *cd,
 					      struct cache_head *h);
 
+	struct cache_head *	(*alloc)(void);
+	int			(*match)(struct cache_head *orig, struct cache_head *new);
+	void			(*init)(struct cache_head *orig, struct cache_head *new);
+	void			(*update)(struct cache_head *orig, struct cache_head *new);
+
 	/* fields below this comment are for internal use
 	 * and should not be touched by cache owners
 	 */
@@ -123,126 +127,14 @@
 					   int too_many);
 };
 
-/*
- * just like a template in C++, this macro does cache lookup
- * for us.
- * The function is passed some sort of HANDLE from which a cache_detail
- * structure can be determined (via SETUP, DETAIL), a template
- * cache entry (type RTN*), and a "set" flag.  Using the HASHFN and the 
- * TEST, the function will try to find a matching cache entry in the cache.
- * If "set" == 0 :
- *    If an entry is found, it is returned
- *    If no entry is found, a new non-VALID entry is created.
- * If "set" == 1 and INPLACE == 0 :
- *    If no entry is found a new one is inserted with data from "template"
- *    If a non-CACHE_VALID entry is found, it is updated from template using UPDATE
- *    If a CACHE_VALID entry is found, a new entry is swapped in with data
- *       from "template"
- * If set == 1, and INPLACE == 1 :
- *    As above, except that if a CACHE_VALID entry is found, we UPDATE in place
- *       instead of swapping in a new entry.
- *
- * If the passed handle has the CACHE_NEGATIVE flag set, then UPDATE is not
- * run but insteead CACHE_NEGATIVE is set in any new item.
 
- *  In any case, the new entry is returned with a reference count.
- *
- *    
- * RTN is a struct type for a cache entry
- * MEMBER is the member of the cache which is cache_head, which must be first
- * FNAME is the name for the function	
- * ARGS are arguments to function and must contain RTN *item, int set.  May
- *   also contain something to be usedby SETUP or DETAIL to find cache_detail.
- * SETUP  locates the cache detail and makes it available as...
- * DETAIL identifies the cache detail, possibly set up by SETUP
- * HASHFN returns a hash value of the cache entry "item"
- * TEST  tests if "tmp" matches "item"
- * INIT copies key information from "item" to "new"
- * UPDATE copies content information from "item" to "tmp"
- * INPLACE is true if updates can happen inplace rather than allocating a new structure
- *
- * WARNING: any substantial changes to this must be reflected in
- *   net/sunrpc/svcauth.c(auth_domain_lookup)
- *  which is a similar routine that is open-coded.
- */
-#define DefineCacheLookup(RTN,MEMBER,FNAME,ARGS,SETUP,DETAIL,HASHFN,TEST,INIT,UPDATE,INPLACE)	\
-RTN *FNAME ARGS										\
-{											\
-	RTN *tmp, *new=NULL;								\
-	struct cache_head **hp, **head;							\
-	SETUP;										\
-	head = &(DETAIL)->hash_table[HASHFN];						\
- retry:											\
-	if (set||new) write_lock(&(DETAIL)->hash_lock);					\
-	else read_lock(&(DETAIL)->hash_lock);						\
-	for(hp=head; *hp != NULL; hp = &tmp->MEMBER.next) {				\
-		tmp = container_of(*hp, RTN, MEMBER);					\
-		if (TEST) { /* found a match */						\
-											\
-			if (set && !INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags) && !new) \
-				break;							\
-											\
-			if (new)							\
-				{INIT;}							\
-			if (set) {							\
-				if (!INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\
-				{ /* need to swap in new */				\
-					RTN *t2;					\
-											\
-					new->MEMBER.next = tmp->MEMBER.next;		\
-					*hp = &new->MEMBER;				\
-					tmp->MEMBER.next = NULL;			\
-					t2 = tmp; tmp = new; new = t2;			\
-				}							\
-				if (test_bit(CACHE_NEGATIVE,  &item->MEMBER.flags))	\
-					set_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags);	\
-				else {							\
-					UPDATE;						\
-					clear_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags);	\
-				}							\
-			}								\
-			cache_get(&tmp->MEMBER);					\
-			if (set||new) write_unlock(&(DETAIL)->hash_lock);		\
-			else read_unlock(&(DETAIL)->hash_lock);				\
-			if (set)							\
-				cache_fresh(DETAIL, &tmp->MEMBER, item->MEMBER.expiry_time); \
-			if (set && !INPLACE && new) cache_fresh(DETAIL, &new->MEMBER, 0);	\
-			if (new) (DETAIL)->cache_put(&new->MEMBER, DETAIL);		\
-			return tmp;							\
-		}									\
-	}										\
-	/* Didn't find anything */							\
-	if (new) {									\
-		INIT;									\
-		new->MEMBER.next = *head;						\
-		*head = &new->MEMBER;							\
-		(DETAIL)->entries ++;							\
-		cache_get(&new->MEMBER);						\
-		if (set) {								\
-			tmp = new;							\
-			if (test_bit(CACHE_NEGATIVE, &item->MEMBER.flags))		\
-				set_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags);		\
-			else {UPDATE;}							\
-		}									\
-	}										\
-	if (set||new) write_unlock(&(DETAIL)->hash_lock);				\
-	else read_unlock(&(DETAIL)->hash_lock);						\
-	if (new && set)									\
-		cache_fresh(DETAIL, &new->MEMBER, item->MEMBER.expiry_time);		\
-	if (new)				       					\
-		return new;								\
-	new = kmalloc(sizeof(*new), GFP_KERNEL);					\
-	if (new) {									\
-		cache_init(&new->MEMBER);						\
-		goto retry;								\
-	}										\
-	return NULL;									\
-}
+extern struct cache_head *
+sunrpc_cache_lookup(struct cache_detail *detail,
+		    struct cache_head *key, int hash);
+extern struct cache_head *
+sunrpc_cache_update(struct cache_detail *detail,
+		    struct cache_head *new, struct cache_head *old, int hash);
 
-#define DefineSimpleCacheLookup(STRUCT,INPLACE)	\
-	DefineCacheLookup(struct STRUCT, h, STRUCT##_lookup, (struct STRUCT *item, int set), /*no setup */,	\
-			  & STRUCT##_cache, STRUCT##_hash(item), STRUCT##_match(item, tmp),\
-			  STRUCT##_init(new, item), STRUCT##_update(tmp, item),INPLACE)
 
 #define cache_for_each(pos, detail, index, member) 						\
 	for (({read_lock(&(detail)->hash_lock); index = (detail)->hash_size;}) ;		\
@@ -258,22 +150,19 @@
 
 static inline struct cache_head  *cache_get(struct cache_head *h)
 {
-	atomic_inc(&h->refcnt);
+	kref_get(&h->ref);
 	return h;
 }
 
 
-static inline int cache_put(struct cache_head *h, struct cache_detail *cd)
+static inline void cache_put(struct cache_head *h, struct cache_detail *cd)
 {
-	if (atomic_read(&h->refcnt) <= 2 &&
+	if (atomic_read(&h->ref.refcount) <= 2 &&
 	    h->expiry_time < cd->nextcheck)
 		cd->nextcheck = h->expiry_time;
-	return atomic_dec_and_test(&h->refcnt);
+	kref_put(&h->ref, cd->cache_put);
 }
 
-extern void cache_init(struct cache_head *h);
-extern void cache_fresh(struct cache_detail *detail,
-			struct cache_head *head, time_t expiry);
 extern int cache_check(struct cache_detail *detail,
 		       struct cache_head *h, struct cache_req *rqstp);
 extern void cache_flush(void);
diff --git a/include/linux/sunrpc/stats.h b/include/linux/sunrpc/stats.h
index 0d6ed3c..d93c24b 100644
--- a/include/linux/sunrpc/stats.h
+++ b/include/linux/sunrpc/stats.h
@@ -50,7 +50,7 @@
 void			rpc_proc_unregister(const char *);
 void			rpc_proc_zero(struct rpc_program *);
 struct proc_dir_entry *	svc_proc_register(struct svc_stat *,
-					  struct file_operations *);
+					  const struct file_operations *);
 void			svc_proc_unregister(const char *);
 
 void			svc_seq_show(struct seq_file *,
@@ -65,7 +65,7 @@
 static inline void rpc_proc_zero(struct rpc_program *p) {}
 
 static inline struct proc_dir_entry *svc_proc_register(struct svc_stat *s,
-						       struct file_operations *f) { return NULL; }
+						       const struct file_operations *f) { return NULL; }
 static inline void svc_proc_unregister(const char *p) {}
 
 static inline void svc_seq_show(struct seq_file *seq,
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index c119ce7..2fe2087 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -45,9 +45,10 @@
  * of ip addresses to the given client.
  */
 struct auth_domain {
-	struct	cache_head	h;
+	struct kref		ref;
+	struct hlist_node	hash;
 	char			*name;
-	int			flavour;
+	struct auth_ops		*flavour;
 };
 
 /*
@@ -86,6 +87,9 @@
  *
  * domain_release()
  *   This call releases a domain.
+ * set_client()
+ *   Givens a pending request (struct svc_rqst), finds and assigns
+ *   an appropriate 'auth_domain' as the client.
  */
 struct auth_ops {
 	char *	name;
@@ -117,7 +121,7 @@
 extern struct auth_domain *unix_domain_find(char *name);
 extern void auth_domain_put(struct auth_domain *item);
 extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom);
-extern struct auth_domain *auth_domain_lookup(struct auth_domain *item, int set);
+extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
 extern struct auth_domain *auth_domain_find(char *name);
 extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
 extern int auth_unix_forget_old(struct auth_domain *dom);
@@ -160,8 +164,6 @@
 	return hash >> (BITS_PER_LONG - bits);
 }
 
-extern struct cache_detail auth_domain_cache, ip_map_cache;
-
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_SUNRPC_SVCAUTH_H_ */
diff --git a/include/linux/synclink.h b/include/linux/synclink.h
index 1b7cd8d..2993302 100644
--- a/include/linux/synclink.h
+++ b/include/linux/synclink.h
@@ -1,7 +1,7 @@
 /*
  * SyncLink Multiprotocol Serial Adapter Driver
  *
- * $Id: synclink.h,v 3.10 2005/11/08 19:50:54 paulkf Exp $
+ * $Id: synclink.h,v 3.11 2006/02/06 21:20:29 paulkf Exp $
  *
  * Copyright (C) 1998-2000 by Microgate Corporation
  *
@@ -221,6 +221,12 @@
 	__u32	rxidle;
 };
 
+struct gpio_desc {
+	__u32 state;
+	__u32 smask;
+	__u32 dir;
+	__u32 dmask;
+};
 
 #define DEBUG_LEVEL_DATA	1
 #define DEBUG_LEVEL_ERROR 	2
@@ -276,5 +282,8 @@
 #define MGSL_IOCLOOPTXDONE	_IO(MGSL_MAGIC_IOC,9)
 #define MGSL_IOCSIF		_IO(MGSL_MAGIC_IOC,10)
 #define MGSL_IOCGIF		_IO(MGSL_MAGIC_IOC,11)
+#define MGSL_IOCSGPIO		_IOW(MGSL_MAGIC_IOC,16,struct gpio_desc)
+#define MGSL_IOCGGPIO		_IOR(MGSL_MAGIC_IOC,17,struct gpio_desc)
+#define MGSL_IOCWAITGPIO	_IOWR(MGSL_MAGIC_IOC,18,struct gpio_desc)
 
 #endif /* _SYNCLINK_H_ */
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index e487e3b..5717147 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -569,5 +569,9 @@
 asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename,
 				   int flags, int mode);
 asmlinkage long sys_unshare(unsigned long unshare_flags);
+asmlinkage long sys_splice(int fdin, int fdout, size_t len,
+				unsigned int flags);
+asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
+					int flags);
 
 #endif
diff --git a/include/linux/threads.h b/include/linux/threads.h
index b59738a..e646bcd 100644
--- a/include/linux/threads.h
+++ b/include/linux/threads.h
@@ -28,7 +28,8 @@
 #define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)
 
 /*
- * A maximum of 4 million PIDs should be enough for a while:
+ * A maximum of 4 million PIDs should be enough for a while.
+ * [NOTE: PID/TIDs are limited to 2^29 ~= 500+ million, see futex.h.]
  */
 #define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \
 	(sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))
diff --git a/include/linux/time.h b/include/linux/time.h
index bf0e785..0cd696c 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -73,12 +73,6 @@
 #define timespec_valid(ts) \
 	(((ts)->tv_sec >= 0) && (((unsigned long) (ts)->tv_nsec) < NSEC_PER_SEC))
 
-/*
- * 64-bit nanosec type. Large enough to span 292+ years in nanosecond
- * resolution. Ought to be enough for a while.
- */
-typedef s64 nsec_t;
-
 extern struct timespec xtime;
 extern struct timespec wall_to_monotonic;
 extern seqlock_t xtime_lock;
@@ -114,9 +108,9 @@
  * Returns the scalar nanosecond representation of the timespec
  * parameter.
  */
-static inline nsec_t timespec_to_ns(const struct timespec *ts)
+static inline s64 timespec_to_ns(const struct timespec *ts)
 {
-	return ((nsec_t) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
+	return ((s64) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
 }
 
 /**
@@ -126,9 +120,9 @@
  * Returns the scalar nanosecond representation of the timeval
  * parameter.
  */
-static inline nsec_t timeval_to_ns(const struct timeval *tv)
+static inline s64 timeval_to_ns(const struct timeval *tv)
 {
-	return ((nsec_t) tv->tv_sec * NSEC_PER_SEC) +
+	return ((s64) tv->tv_sec * NSEC_PER_SEC) +
 		tv->tv_usec * NSEC_PER_USEC;
 }
 
@@ -138,7 +132,7 @@
  *
  * Returns the timespec representation of the nsec parameter.
  */
-extern struct timespec ns_to_timespec(const nsec_t nsec);
+extern struct timespec ns_to_timespec(const s64 nsec);
 
 /**
  * ns_to_timeval - Convert nanoseconds to timeval
@@ -146,7 +140,7 @@
  *
  * Returns the timeval representation of the nsec parameter.
  */
-extern struct timeval ns_to_timeval(const nsec_t nsec);
+extern struct timeval ns_to_timeval(const s64 nsec);
 
 #endif /* __KERNEL__ */
 
diff --git a/include/linux/timer.h b/include/linux/timer.h
index ee5a09e..0a485be 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -6,7 +6,7 @@
 #include <linux/spinlock.h>
 #include <linux/stddef.h>
 
-struct timer_base_s;
+struct tvec_t_base_s;
 
 struct timer_list {
 	struct list_head entry;
@@ -15,16 +15,16 @@
 	void (*function)(unsigned long);
 	unsigned long data;
 
-	struct timer_base_s *base;
+	struct tvec_t_base_s *base;
 };
 
-extern struct timer_base_s __init_timer_base;
+extern struct tvec_t_base_s boot_tvec_bases;
 
 #define TIMER_INITIALIZER(_function, _expires, _data) {		\
 		.function = (_function),			\
 		.expires = (_expires),				\
 		.data = (_data),				\
-		.base = &__init_timer_base,			\
+		.base = &boot_tvec_bases,			\
 	}
 
 #define DEFINE_TIMER(_name, _function, _expires, _data)		\
@@ -96,6 +96,7 @@
 
 extern void init_timers(void);
 extern void run_local_timers(void);
-extern int it_real_fn(void *);
+struct hrtimer;
+extern int it_real_fn(struct hrtimer *);
 
 #endif
diff --git a/include/linux/timex.h b/include/linux/timex.h
index 82dc9ae..03914b7 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -307,6 +307,8 @@
 /* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */
 extern u64 current_tick_length(void);
 
+extern int do_adjtimex(struct timex *);
+
 #endif /* KERNEL */
 
 #endif /* LINUX_TIMEX_H */
diff --git a/include/linux/tiocl.h b/include/linux/tiocl.h
index 2c9e847..4756862 100644
--- a/include/linux/tiocl.h
+++ b/include/linux/tiocl.h
@@ -34,5 +34,6 @@
 #define TIOCL_SCROLLCONSOLE	13	/* scroll console */
 #define TIOCL_BLANKSCREEN	14	/* keep screen blank even if a key is pressed */
 #define TIOCL_BLANKEDSCREEN	15	/* return which vt was blanked */
+#define TIOCL_GETKMSGREDIRECT	17	/* get the vt the kernel messages are restricted to */
 
 #endif /* _LINUX_TIOCL_H */
diff --git a/include/linux/topology.h b/include/linux/topology.h
index e8eb004..a305ae2 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -164,6 +164,15 @@
 	.nr_balance_failed	= 0,			\
 }
 
+#ifdef CONFIG_SCHED_MC
+#ifndef SD_MC_INIT
+/* for now its same as SD_CPU_INIT.
+ * TBD: Tune Domain parameters!
+ */
+#define SD_MC_INIT   SD_CPU_INIT
+#endif
+#endif
+
 #ifdef CONFIG_NUMA
 #ifndef SD_NODE_INIT
 #error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!!
diff --git a/include/linux/types.h b/include/linux/types.h
index 54ae2d5..1046c7a 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -137,6 +137,10 @@
 typedef unsigned long sector_t;
 #endif
 
+#ifndef HAVE_BLKCNT_T
+typedef unsigned long blkcnt_t;
+#endif
+
 /*
  * The type of an index into the pagecache.  Use a #define so asm/types.h
  * can override it.
diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
index b0ffe43..843aeaa 100644
--- a/include/linux/ufs_fs.h
+++ b/include/linux/ufs_fs.h
@@ -895,7 +895,7 @@
 
 /* file.c */
 extern struct inode_operations ufs_file_inode_operations;
-extern struct file_operations ufs_file_operations;
+extern const struct file_operations ufs_file_operations;
 
 extern struct address_space_operations ufs_aops;
 
@@ -915,7 +915,7 @@
 extern int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create);
 
 /* namei.c */
-extern struct file_operations ufs_dir_operations;
+extern const struct file_operations ufs_dir_operations;
         
 /* super.c */
 extern void ufs_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 130d125..e34e5e3 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -615,7 +615,7 @@
  */
 struct usb_class_driver {
 	char *name;
-	struct file_operations *fops;
+	const struct file_operations *fops;
 	int minor_base;
 };
 
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 2275bfe..af2d615 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -75,7 +75,7 @@
 	int minor;
 
 	/* device ops + callbacks */
-	struct file_operations *fops;
+	const struct file_operations *fops;
 	void (*release)(struct video_device *vfd);
 
 
diff --git a/include/linux/x1205.h b/include/linux/x1205.h
deleted file mode 100644
index 64fd3af..0000000
--- a/include/linux/x1205.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- *  x1205.h - defines for drivers/i2c/chips/x1205.c
- *  Copyright 2004 Karen Spearel
- *  Copyright 2005 Alessandro Zummo
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- */
-
-#ifndef __LINUX_X1205_H__
-#define __LINUX_X1205_H__
-
-/* commands */
-
-#define X1205_CMD_GETDATETIME	0
-#define X1205_CMD_SETTIME	1
-#define X1205_CMD_SETDATETIME	2
-#define X1205_CMD_GETALARM	3
-#define X1205_CMD_SETALARM	4
-#define X1205_CMD_GETDTRIM	5
-#define X1205_CMD_SETDTRIM	6
-#define X1205_CMD_GETATRIM	7
-#define X1205_CMD_SETATRIM	8
-
-extern int x1205_do_command(unsigned int cmd, void *arg);
-extern int x1205_direct_attach(int adapter_id,
-	struct i2c_client_address_data *address_data);
-
-#endif /* __LINUX_X1205_H__ */
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index b6f0905..916013c 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -300,29 +300,30 @@
 
 #define CONNTRACK_ECACHE(x)	(__get_cpu_var(nf_conntrack_ecache).x)
 
-extern struct notifier_block *nf_conntrack_chain;
-extern struct notifier_block *nf_conntrack_expect_chain;
+extern struct atomic_notifier_head nf_conntrack_chain;
+extern struct atomic_notifier_head nf_conntrack_expect_chain;
 
 static inline int nf_conntrack_register_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_register(&nf_conntrack_chain, nb);
+	return atomic_notifier_chain_register(&nf_conntrack_chain, nb);
 }
 
 static inline int nf_conntrack_unregister_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_unregister(&nf_conntrack_chain, nb);
+	return atomic_notifier_chain_unregister(&nf_conntrack_chain, nb);
 }
 
 static inline int
 nf_conntrack_expect_register_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_register(&nf_conntrack_expect_chain, nb);
+	return atomic_notifier_chain_register(&nf_conntrack_expect_chain, nb);
 }
 
 static inline int
 nf_conntrack_expect_unregister_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_unregister(&nf_conntrack_expect_chain, nb);
+	return atomic_notifier_chain_unregister(&nf_conntrack_expect_chain,
+			nb);
 }
 
 extern void nf_ct_deliver_cached_events(const struct nf_conn *ct);
@@ -347,14 +348,14 @@
 				      struct nf_conn *ct)
 {
 	if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct))
-		notifier_call_chain(&nf_conntrack_chain, event, ct);
+		atomic_notifier_call_chain(&nf_conntrack_chain, event, ct);
 }
 
 static inline void
 nf_conntrack_expect_event(enum ip_conntrack_expect_events event,
 			  struct nf_conntrack_expect *exp)
 {
-	notifier_call_chain(&nf_conntrack_expect_chain, event, exp);
+	atomic_notifier_call_chain(&nf_conntrack_expect_chain, event, exp);
 }
 #else /* CONFIG_NF_CONNTRACK_EVENTS */
 static inline void nf_conntrack_event_cache(enum ip_conntrack_events event,
diff --git a/include/net/request_sock.h b/include/net/request_sock.h
index 11641c9..c5d7f92 100644
--- a/include/net/request_sock.h
+++ b/include/net/request_sock.h
@@ -145,7 +145,7 @@
 {
 	struct request_sock *req = queue->rskq_accept_head;
 
-	queue->rskq_accept_head = queue->rskq_accept_head = NULL;
+	queue->rskq_accept_head = NULL;
 	return req;
 }
 
diff --git a/include/net/sock.h b/include/net/sock.h
index 2aa73c0..af2b054 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -938,28 +938,7 @@
 		sk_free(sk);
 }
 
-static inline int sk_receive_skb(struct sock *sk, struct sk_buff *skb)
-{
-	int rc = NET_RX_SUCCESS;
-
-	if (sk_filter(sk, skb, 0))
-		goto discard_and_relse;
-
-	skb->dev = NULL;
-
-	bh_lock_sock(sk);
-	if (!sock_owned_by_user(sk))
-		rc = sk->sk_backlog_rcv(sk, skb);
-	else
-		sk_add_backlog(sk, skb);
-	bh_unlock_sock(sk);
-out:
-	sock_put(sk);
-	return rc;
-discard_and_relse:
-	kfree_skb(skb);
-	goto out;
-}
+extern int sk_receive_skb(struct sock *sk, struct sk_buff *skb);
 
 /* Detach socket from process context.
  * Announce socket dead, detach it from wait queue and inode.
@@ -1044,33 +1023,9 @@
 	write_unlock(&sk->sk_dst_lock);
 }
 
-static inline struct dst_entry *
-__sk_dst_check(struct sock *sk, u32 cookie)
-{
-	struct dst_entry *dst = sk->sk_dst_cache;
+extern struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie);
 
-	if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) {
-		sk->sk_dst_cache = NULL;
-		dst_release(dst);
-		return NULL;
-	}
-
-	return dst;
-}
-
-static inline struct dst_entry *
-sk_dst_check(struct sock *sk, u32 cookie)
-{
-	struct dst_entry *dst = sk_dst_get(sk);
-
-	if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) {
-		sk_dst_reset(sk);
-		dst_release(dst);
-		return NULL;
-	}
-
-	return dst;
-}
+extern struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie);
 
 static inline void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
 {
@@ -1140,45 +1095,7 @@
 
 extern void sk_stop_timer(struct sock *sk, struct timer_list* timer);
 
-static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
-{
-	int err = 0;
-	int skb_len;
-
-	/* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
-	   number of warnings when compiling with -W --ANK
-	 */
-	if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
-	    (unsigned)sk->sk_rcvbuf) {
-		err = -ENOMEM;
-		goto out;
-	}
-
-	/* It would be deadlock, if sock_queue_rcv_skb is used
-	   with socket lock! We assume that users of this
-	   function are lock free.
-	*/
-	err = sk_filter(sk, skb, 1);
-	if (err)
-		goto out;
-
-	skb->dev = NULL;
-	skb_set_owner_r(skb, sk);
-
-	/* Cache the SKB length before we tack it onto the receive
-	 * queue.  Once it is added it no longer belongs to us and
-	 * may be freed by other threads of control pulling packets
-	 * from the queue.
-	 */
-	skb_len = skb->len;
-
-	skb_queue_tail(&sk->sk_receive_queue, skb);
-
-	if (!sock_flag(sk, SOCK_DEAD))
-		sk->sk_data_ready(sk, skb_len);
-out:
-	return err;
-}
+extern int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
 
 static inline int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
 {
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 9418f4d..3c989db 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -405,9 +405,6 @@
 
 extern void			tcp_unhash(struct sock *sk);
 
-extern int			tcp_v4_hash_connecting(struct sock *sk);
-
-
 /* From syncookies.c */
 extern struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, 
 				    struct ip_options *opt);
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 61b7504..e100291 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -864,13 +864,19 @@
 /* XFRM tunnel handlers.  */
 struct xfrm_tunnel {
 	int (*handler)(struct sk_buff *skb);
-	void (*err_handler)(struct sk_buff *skb, __u32 info);
+	int (*err_handler)(struct sk_buff *skb, __u32 info);
+
+	struct xfrm_tunnel *next;
+	int priority;
 };
 
 struct xfrm6_tunnel {
-	int (*handler)(struct sk_buff **pskb);
-	void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
-			    int type, int code, int offset, __u32 info);
+	int (*handler)(struct sk_buff *skb);
+	int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
+			   int type, int code, int offset, __u32 info);
+
+	struct xfrm6_tunnel *next;
+	int priority;
 };
 
 extern void xfrm_init(void);
@@ -906,7 +912,7 @@
 extern int xfrm4_output(struct sk_buff *skb);
 extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
 extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
-extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi);
+extern int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi);
 extern int xfrm6_rcv(struct sk_buff **pskb);
 extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler);
 extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler);
diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h
index 51ab8ed..5ff7755 100644
--- a/include/rdma/ib_mad.h
+++ b/include/rdma/ib_mad.h
@@ -3,7 +3,7 @@
  * Copyright (c) 2004 Infinicon Corporation.  All rights reserved.
  * Copyright (c) 2004 Intel Corporation.  All rights reserved.
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
- * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
+ * Copyright (c) 2004-2006 Voltaire Corporation.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -55,6 +55,10 @@
 #define IB_MGMT_CLASS_DEVICE_MGMT		0x06
 #define IB_MGMT_CLASS_CM			0x07
 #define IB_MGMT_CLASS_SNMP			0x08
+#define IB_MGMT_CLASS_DEVICE_ADM		0x10
+#define IB_MGMT_CLASS_BOOT_MGMT			0x11
+#define IB_MGMT_CLASS_BIS			0x12
+#define IB_MGMT_CLASS_CONG_MGMT			0x21
 #define IB_MGMT_CLASS_VENDOR_RANGE2_START	0x30
 #define IB_MGMT_CLASS_VENDOR_RANGE2_END		0x4F
 
@@ -117,6 +121,8 @@
 	IB_MGMT_VENDOR_DATA = 216,
 	IB_MGMT_SA_HDR = 56,
 	IB_MGMT_SA_DATA = 200,
+	IB_MGMT_DEVICE_HDR = 64,
+	IB_MGMT_DEVICE_DATA = 192,
 };
 
 struct ib_mad_hdr {
@@ -603,6 +609,25 @@
 					    gfp_t gfp_mask);
 
 /**
+ * ib_is_mad_class_rmpp - returns whether given management class
+ * supports RMPP.
+ * @mgmt_class: management class
+ *
+ * This routine returns whether the management class supports RMPP.
+ */
+int ib_is_mad_class_rmpp(u8 mgmt_class);
+
+/**
+ * ib_get_mad_data_offset - returns the data offset for a given
+ * management class.
+ * @mgmt_class: management class
+ *
+ * This routine returns the data offset in the MAD for the management
+ * class requested.
+ */
+int ib_get_mad_data_offset(u8 mgmt_class);
+
+/**
  * ib_get_rmpp_segment - returns the data buffer for a given RMPP segment.
  * @send_buf: Previously allocated send data buffer.
  * @seg_num: number of segment to return
diff --git a/include/sound/core.h b/include/sound/core.h
index 144bdc2..7f32c12 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -186,7 +186,7 @@
 	int type;			/* SNDRV_DEVICE_TYPE_XXX */
 	int card;			/* card number */
 	int device;			/* device number */
-	struct file_operations *f_ops;	/* file operations */
+	const struct file_operations *f_ops;	/* file operations */
 	void *private_data;		/* private data for f_ops->open */
 	char name[0];			/* device name (keep at the end of
 								structure) */
@@ -200,14 +200,14 @@
 void snd_request_card(int card);
 
 int snd_register_device(int type, struct snd_card *card, int dev,
-			struct file_operations *f_ops, void *private_data,
+			const struct file_operations *f_ops, void *private_data,
 			const char *name);
 int snd_unregister_device(int type, struct snd_card *card, int dev);
 void *snd_lookup_minor_data(unsigned int minor, int type);
 
 #ifdef CONFIG_SND_OSSEMUL
 int snd_register_oss_device(int type, struct snd_card *card, int dev,
-			    struct file_operations *f_ops, void *private_data,
+			    const struct file_operations *f_ops, void *private_data,
 			    const char *name);
 int snd_unregister_oss_device(int type, struct snd_card *card, int dev);
 void *snd_lookup_oss_minor_data(unsigned int minor, int type);
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 8b671fe..adb7cad 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -23,7 +23,6 @@
 char * __initdata root_device_name;
 static char __initdata saved_root_name[64];
 
-/* this is initialized in init/main.c */
 dev_t ROOT_DEV;
 
 static int __init load_ramdisk(char *str)
diff --git a/init/initramfs.c b/init/initramfs.c
index 77b934c..679d870 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -519,7 +519,7 @@
 			return;
 		}
 		printk("it isn't (%s); looks like an initrd\n", err);
-		fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 700);
+		fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);
 		if (fd >= 0) {
 			sys_write(fd, (char *)initrd_start,
 					initrd_end - initrd_start);
diff --git a/init/main.c b/init/main.c
index 006dcd5..4a2f089 100644
--- a/init/main.c
+++ b/init/main.c
@@ -341,7 +341,7 @@
 #endif
 	ptr = alloc_bootmem(size * nr_possible_cpus);
 
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		__per_cpu_offset[i] = ptr - __per_cpu_start;
 		memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
 		ptr += size;
@@ -645,24 +645,6 @@
 	execve(init_filename, argv_init, envp_init);
 }
 
-static inline void fixup_cpu_present_map(void)
-{
-#ifdef CONFIG_SMP
-	int i;
-
-	/*
-	 * If arch is not hotplug ready and did not populate
-	 * cpu_present_map, just make cpu_present_map same as cpu_possible_map
-	 * for other cpu bringup code to function as normal. e.g smp_init() etc.
-	 */
-	if (cpus_empty(cpu_present_map)) {
-		for_each_cpu(i) {
-			cpu_set(i, cpu_present_map);
-		}
-	}
-#endif
-}
-
 static int init(void * unused)
 {
 	lock_kernel();
@@ -684,7 +666,6 @@
 
 	do_pre_smp_initcalls();
 
-	fixup_cpu_present_map();
 	smp_init();
 	sched_init_smp();
 
diff --git a/ipc/compat.c b/ipc/compat.c
index 1fe95f6..a544dfb 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -30,7 +30,7 @@
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include "util.h"
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 85c52fd..41ecbd4 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -25,6 +25,8 @@
 #include <linux/netlink.h>
 #include <linux/syscalls.h>
 #include <linux/signal.h>
+#include <linux/mutex.h>
+
 #include <net/sock.h>
 #include "util.h"
 
@@ -760,7 +762,7 @@
  * The receiver accepts the message and returns without grabbing the queue
  * spinlock. Therefore an intermediate STATE_PENDING state and memory barriers
  * are necessary. The same algorithm is used for sysv semaphores, see
- * ipc/sem.c fore more details.
+ * ipc/sem.c for more details.
  *
  * The same algorithm is used for senders.
  */
diff --git a/ipc/msg.c b/ipc/msg.c
index 7eec5ed..48a7f17 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -28,6 +28,8 @@
 #include <linux/syscalls.h>
 #include <linux/audit.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
+
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include "util.h"
@@ -179,8 +181,8 @@
  * removes the message queue from message queue ID 
  * array, and cleans up all the messages associated with this queue.
  *
- * msg_ids.sem and the spinlock for this message queue is hold
- * before freeque() is called. msg_ids.sem remains locked on exit.
+ * msg_ids.mutex and the spinlock for this message queue is hold
+ * before freeque() is called. msg_ids.mutex remains locked on exit.
  */
 static void freeque (struct msg_queue *msq, int id)
 {
@@ -208,7 +210,7 @@
 	int id, ret = -EPERM;
 	struct msg_queue *msq;
 	
-	down(&msg_ids.sem);
+	mutex_lock(&msg_ids.mutex);
 	if (key == IPC_PRIVATE) 
 		ret = newque(key, msgflg);
 	else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */
@@ -231,7 +233,7 @@
 		}
 		msg_unlock(msq);
 	}
-	up(&msg_ids.sem);
+	mutex_unlock(&msg_ids.mutex);
 	return ret;
 }
 
@@ -361,7 +363,7 @@
 		msginfo.msgmnb = msg_ctlmnb;
 		msginfo.msgssz = MSGSSZ;
 		msginfo.msgseg = MSGSEG;
-		down(&msg_ids.sem);
+		mutex_lock(&msg_ids.mutex);
 		if (cmd == MSG_INFO) {
 			msginfo.msgpool = msg_ids.in_use;
 			msginfo.msgmap = atomic_read(&msg_hdrs);
@@ -372,7 +374,7 @@
 			msginfo.msgtql = MSGTQL;
 		}
 		max_id = msg_ids.max_id;
-		up(&msg_ids.sem);
+		mutex_unlock(&msg_ids.mutex);
 		if (copy_to_user (buf, &msginfo, sizeof(struct msginfo)))
 			return -EFAULT;
 		return (max_id < 0) ? 0: max_id;
@@ -435,7 +437,7 @@
 		return  -EINVAL;
 	}
 
-	down(&msg_ids.sem);
+	mutex_lock(&msg_ids.mutex);
 	msq = msg_lock(msqid);
 	err=-EINVAL;
 	if (msq == NULL)
@@ -489,7 +491,7 @@
 	}
 	err = 0;
 out_up:
-	up(&msg_ids.sem);
+	mutex_unlock(&msg_ids.mutex);
 	return err;
 out_unlock_up:
 	msg_unlock(msq);
diff --git a/ipc/sem.c b/ipc/sem.c
index 59696a8..642659c 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -75,6 +75,8 @@
 #include <linux/audit.h>
 #include <linux/capability.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 #include "util.h"
 
@@ -139,7 +141,7 @@
  *   	* if it's IN_WAKEUP, then it must wait until the value changes
  *   	* if it's not -EINTR, then the operation was completed by
  *   	  update_queue. semtimedop can return queue.status without
- *   	  performing any operation on the semaphore array.
+ *   	  performing any operation on the sem array.
  *   	* otherwise it must acquire the spinlock and check what's up.
  *
  * The two-stage algorithm is necessary to protect against the following
@@ -214,7 +216,7 @@
 
 	if (nsems < 0 || nsems > sc_semmsl)
 		return -EINVAL;
-	down(&sem_ids.sem);
+	mutex_lock(&sem_ids.mutex);
 	
 	if (key == IPC_PRIVATE) {
 		err = newary(key, nsems, semflg);
@@ -227,8 +229,7 @@
 		err = -EEXIST;
 	} else {
 		sma = sem_lock(id);
-		if(sma==NULL)
-			BUG();
+		BUG_ON(sma==NULL);
 		if (nsems > sma->sem_nsems)
 			err = -EINVAL;
 		else if (ipcperms(&sma->sem_perm, semflg))
@@ -242,7 +243,7 @@
 		sem_unlock(sma);
 	}
 
-	up(&sem_ids.sem);
+	mutex_unlock(&sem_ids.mutex);
 	return err;
 }
 
@@ -437,8 +438,8 @@
 	return semzcnt;
 }
 
-/* Free a semaphore set. freeary() is called with sem_ids.sem down and
- * the spinlock for this semaphore set hold. sem_ids.sem remains locked
+/* Free a semaphore set. freeary() is called with sem_ids.mutex locked and
+ * the spinlock for this semaphore set hold. sem_ids.mutex remains locked
  * on exit.
  */
 static void freeary (struct sem_array *sma, int id)
@@ -525,7 +526,7 @@
 		seminfo.semmnu = SEMMNU;
 		seminfo.semmap = SEMMAP;
 		seminfo.semume = SEMUME;
-		down(&sem_ids.sem);
+		mutex_lock(&sem_ids.mutex);
 		if (cmd == SEM_INFO) {
 			seminfo.semusz = sem_ids.in_use;
 			seminfo.semaem = used_sems;
@@ -534,7 +535,7 @@
 			seminfo.semaem = SEMAEM;
 		}
 		max_id = sem_ids.max_id;
-		up(&sem_ids.sem);
+		mutex_unlock(&sem_ids.mutex);
 		if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) 
 			return -EFAULT;
 		return (max_id < 0) ? 0: max_id;
@@ -885,9 +886,9 @@
 		return err;
 	case IPC_RMID:
 	case IPC_SET:
-		down(&sem_ids.sem);
+		mutex_lock(&sem_ids.mutex);
 		err = semctl_down(semid,semnum,cmd,version,arg);
-		up(&sem_ids.sem);
+		mutex_unlock(&sem_ids.mutex);
 		return err;
 	default:
 		return -EINVAL;
@@ -1181,8 +1182,7 @@
 
 	sma = sem_lock(semid);
 	if(sma==NULL) {
-		if(queue.prev != NULL)
-			BUG();
+		BUG_ON(queue.prev != NULL);
 		error = -EIDRM;
 		goto out_free;
 	}
@@ -1299,9 +1299,9 @@
 		/* perform adjustments registered in u */
 		nsems = sma->sem_nsems;
 		for (i = 0; i < nsems; i++) {
-			struct sem * sem = &sma->sem_base[i];
+			struct sem * semaphore = &sma->sem_base[i];
 			if (u->semadj[i]) {
-				sem->semval += u->semadj[i];
+				semaphore->semval += u->semadj[i];
 				/*
 				 * Range checks of the new semaphore value,
 				 * not defined by sus:
@@ -1315,11 +1315,11 @@
 				 *
 				 * 	Manfred <manfred@colorfullife.com>
 				 */
-				if (sem->semval < 0)
-					sem->semval = 0;
-				if (sem->semval > SEMVMX)
-					sem->semval = SEMVMX;
-				sem->sempid = current->tgid;
+				if (semaphore->semval < 0)
+					semaphore->semval = 0;
+				if (semaphore->semval > SEMVMX)
+					semaphore->semval = SEMVMX;
+				semaphore->sempid = current->tgid;
 			}
 		}
 		sma->sem_otime = get_seconds();
diff --git a/ipc/shm.c b/ipc/shm.c
index 6f9615c..f806a2e 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -30,6 +30,7 @@
 #include <linux/capability.h>
 #include <linux/ptrace.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 
@@ -109,7 +110,7 @@
  *
  * @shp: struct to free
  *
- * It has to be called with shp and shm_ids.sem locked,
+ * It has to be called with shp and shm_ids.mutex locked,
  * but returns with shp unlocked and freed.
  */
 static void shm_destroy (struct shmid_kernel *shp)
@@ -139,7 +140,7 @@
 	int id = file->f_dentry->d_inode->i_ino;
 	struct shmid_kernel *shp;
 
-	down (&shm_ids.sem);
+	mutex_lock(&shm_ids.mutex);
 	/* remove from the list of attaches of the shm segment */
 	if(!(shp = shm_lock(id)))
 		BUG();
@@ -151,7 +152,7 @@
 		shm_destroy (shp);
 	else
 		shm_unlock(shp);
-	up (&shm_ids.sem);
+	mutex_unlock(&shm_ids.mutex);
 }
 
 static int shm_mmap(struct file * file, struct vm_area_struct * vma)
@@ -270,7 +271,7 @@
 	struct shmid_kernel *shp;
 	int err, id = 0;
 
-	down(&shm_ids.sem);
+	mutex_lock(&shm_ids.mutex);
 	if (key == IPC_PRIVATE) {
 		err = newseg(key, shmflg, size);
 	} else if ((id = ipc_findkey(&shm_ids, key)) == -1) {
@@ -296,7 +297,7 @@
 		}
 		shm_unlock(shp);
 	}
-	up(&shm_ids.sem);
+	mutex_unlock(&shm_ids.mutex);
 
 	return err;
 }
@@ -467,14 +468,14 @@
 			return err;
 
 		memset(&shm_info,0,sizeof(shm_info));
-		down(&shm_ids.sem);
+		mutex_lock(&shm_ids.mutex);
 		shm_info.used_ids = shm_ids.in_use;
 		shm_get_stat (&shm_info.shm_rss, &shm_info.shm_swp);
 		shm_info.shm_tot = shm_tot;
 		shm_info.swap_attempts = 0;
 		shm_info.swap_successes = 0;
 		err = shm_ids.max_id;
-		up(&shm_ids.sem);
+		mutex_unlock(&shm_ids.mutex);
 		if(copy_to_user (buf, &shm_info, sizeof(shm_info))) {
 			err = -EFAULT;
 			goto out;
@@ -583,7 +584,7 @@
 		 *	Instead we set a destroyed flag, and then blow
 		 *	the name away when the usage hits zero.
 		 */
-		down(&shm_ids.sem);
+		mutex_lock(&shm_ids.mutex);
 		shp = shm_lock(shmid);
 		err = -EINVAL;
 		if (shp == NULL) 
@@ -610,7 +611,7 @@
 			shm_unlock(shp);
 		} else
 			shm_destroy (shp);
-		up(&shm_ids.sem);
+		mutex_unlock(&shm_ids.mutex);
 		goto out;
 	}
 
@@ -620,12 +621,13 @@
 			err = -EFAULT;
 			goto out;
 		}
-		down(&shm_ids.sem);
+		mutex_lock(&shm_ids.mutex);
 		shp = shm_lock(shmid);
 		err=-EINVAL;
 		if(shp==NULL)
 			goto out_up;
-		if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm))))
+		if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid,
+					setbuf.mode, &(shp->shm_perm))))
 			goto out_unlock_up;
 		err = shm_checkid(shp,shmid);
 		if(err)
@@ -658,7 +660,7 @@
 out_unlock_up:
 	shm_unlock(shp);
 out_up:
-	up(&shm_ids.sem);
+	mutex_unlock(&shm_ids.mutex);
 	goto out;
 out_unlock:
 	shm_unlock(shp);
@@ -771,7 +773,7 @@
 invalid:
 	up_write(&current->mm->mmap_sem);
 
-	down (&shm_ids.sem);
+	mutex_lock(&shm_ids.mutex);
 	if(!(shp = shm_lock(shmid)))
 		BUG();
 	shp->shm_nattch--;
@@ -780,7 +782,7 @@
 		shm_destroy (shp);
 	else
 		shm_unlock(shp);
-	up (&shm_ids.sem);
+	mutex_unlock(&shm_ids.mutex);
 
 	*raddr = (unsigned long) user_addr;
 	err = 0;
diff --git a/ipc/util.c b/ipc/util.c
index 8626219..23151ef 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -68,7 +68,8 @@
 void __init ipc_init_ids(struct ipc_ids* ids, int size)
 {
 	int i;
-	sema_init(&ids->sem,1);
+
+	mutex_init(&ids->mutex);
 
 	if(size > IPCMNI)
 		size = IPCMNI;
@@ -138,7 +139,7 @@
  *	@ids: Identifier set
  *	@key: The key to find
  *	
- *	Requires ipc_ids.sem locked.
+ *	Requires ipc_ids.mutex locked.
  *	Returns the identifier if found or -1 if not.
  */
  
@@ -150,7 +151,7 @@
 
 	/*
 	 * rcu_dereference() is not needed here
-	 * since ipc_ids.sem is held
+	 * since ipc_ids.mutex is held
 	 */
 	for (id = 0; id <= max_id; id++) {
 		p = ids->entries->p[id];
@@ -163,7 +164,7 @@
 }
 
 /*
- * Requires ipc_ids.sem locked
+ * Requires ipc_ids.mutex locked
  */
 static int grow_ary(struct ipc_ids* ids, int newsize)
 {
@@ -210,7 +211,7 @@
  *	is returned. The list is returned in a locked state on success.
  *	On failure the list is not locked and -1 is returned.
  *
- *	Called with ipc_ids.sem held.
+ *	Called with ipc_ids.mutex held.
  */
  
 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
@@ -221,7 +222,7 @@
 
 	/*
 	 * rcu_dereference()() is not needed here since
-	 * ipc_ids.sem is held
+	 * ipc_ids.mutex is held
 	 */
 	for (id = 0; id < size; id++) {
 		if(ids->entries->p[id] == NULL)
@@ -257,7 +258,7 @@
  *	fed an invalid identifier. The entry is removed and internal
  *	variables recomputed. The object associated with the identifier
  *	is returned.
- *	ipc_ids.sem and the spinlock for this ID is hold before this function
+ *	ipc_ids.mutex and the spinlock for this ID is hold before this function
  *	is called, and remain locked on the exit.
  */
  
@@ -270,7 +271,7 @@
 
 	/* 
 	 * do not need a rcu_dereference()() here to force ordering
-	 * on Alpha, since the ipc_ids.sem is held.
+	 * on Alpha, since the ipc_ids.mutex is held.
 	 */	
 	p = ids->entries->p[lid];
 	ids->entries->p[lid] = NULL;
@@ -530,13 +531,13 @@
 
 /*
  * So far only shm_get_stat() calls ipc_get() via shm_get(), so ipc_get()
- * is called with shm_ids.sem locked.  Since grow_ary() is also called with
- * shm_ids.sem down(for Shared Memory), there is no need to add read 
+ * is called with shm_ids.mutex locked.  Since grow_ary() is also called with
+ * shm_ids.mutex down(for Shared Memory), there is no need to add read
  * barriers here to gurantee the writes in grow_ary() are seen in order 
  * here (for Alpha).
  *
- * However ipc_get() itself does not necessary require ipc_ids.sem down. So
- * if in the future ipc_get() is used by other places without ipc_ids.sem
+ * However ipc_get() itself does not necessary require ipc_ids.mutex down. So
+ * if in the future ipc_get() is used by other places without ipc_ids.mutex
  * down, then ipc_get() needs read memery barriers as ipc_lock() does.
  */
 struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id)
@@ -667,7 +668,7 @@
 	 * Take the lock - this will be released by the corresponding
 	 * call to stop().
 	 */
-	down(&iface->ids->sem);
+	mutex_lock(&iface->ids->mutex);
 
 	/* pos < 0 is invalid */
 	if (*pos < 0)
@@ -697,7 +698,7 @@
 		ipc_unlock(ipc);
 
 	/* Release the lock we took in start() */
-	up(&iface->ids->sem);
+	mutex_unlock(&iface->ids->mutex);
 }
 
 static int sysvipc_proc_show(struct seq_file *s, void *it)
diff --git a/ipc/util.h b/ipc/util.h
index efaff3e..0181553 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -25,7 +25,7 @@
 	int max_id;
 	unsigned short seq;
 	unsigned short seq_max;
-	struct semaphore sem;	
+	struct mutex mutex;
 	struct ipc_id_ary nullentry;
 	struct ipc_id_ary* entries;
 };
@@ -40,7 +40,7 @@
 #define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
 #endif
 
-/* must be called with ids->sem acquired.*/
+/* must be called with ids->mutex acquired.*/
 int ipc_findkey(struct ipc_ids* ids, key_t key);
 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size);
 
diff --git a/kernel/Makefile b/kernel/Makefile
index ff1c11d..58908f9 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -12,6 +12,9 @@
 
 obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o
 obj-$(CONFIG_FUTEX) += futex.o
+ifeq ($(CONFIG_COMPAT),y)
+obj-$(CONFIG_FUTEX) += futex_compat.o
+endif
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o spinlock.o
 obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
diff --git a/kernel/acct.c b/kernel/acct.c
index 065d8b4..b327f4d 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -449,8 +449,8 @@
 	/* calculate run_time in nsec*/
 	do_posix_clock_monotonic_gettime(&uptime);
 	run_time = (u64)uptime.tv_sec*NSEC_PER_SEC + uptime.tv_nsec;
-	run_time -= (u64)current->start_time.tv_sec*NSEC_PER_SEC
-					+ current->start_time.tv_nsec;
+	run_time -= (u64)current->group_leader->start_time.tv_sec * NSEC_PER_SEC
+		       + current->group_leader->start_time.tv_nsec;
 	/* convert nsec -> AHZ */
 	elapsed = nsec_to_AHZ(run_time);
 #if ACCT_VERSION==3
@@ -469,10 +469,10 @@
 #endif
 	do_div(elapsed, AHZ);
 	ac.ac_btime = xtime.tv_sec - elapsed;
-	jiffies = cputime_to_jiffies(cputime_add(current->group_leader->utime,
+	jiffies = cputime_to_jiffies(cputime_add(current->utime,
 						 current->signal->utime));
 	ac.ac_utime = encode_comp_t(jiffies_to_AHZ(jiffies));
-	jiffies = cputime_to_jiffies(cputime_add(current->group_leader->stime,
+	jiffies = cputime_to_jiffies(cputime_add(current->stime,
 						 current->signal->stime));
 	ac.ac_stime = encode_comp_t(jiffies_to_AHZ(jiffies));
 	/* we really need to bite the bullet and change layout */
@@ -522,9 +522,9 @@
 	ac.ac_io = encode_comp_t(0 /* current->io_usage */);	/* %% */
 	ac.ac_rw = encode_comp_t(ac.ac_io / 1024);
 	ac.ac_minflt = encode_comp_t(current->signal->min_flt +
-				     current->group_leader->min_flt);
+				     current->min_flt);
 	ac.ac_majflt = encode_comp_t(current->signal->maj_flt +
-				     current->group_leader->maj_flt);
+				     current->maj_flt);
 	ac.ac_swaps = encode_comp_t(0);
 	ac.ac_exitcode = exitcode;
 
diff --git a/kernel/audit.c b/kernel/audit.c
index 04fe2e3..c8ccbd0 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -578,7 +578,7 @@
 	       audit_initialized ? "" : " (after initialization)");
 	if (audit_initialized)
 		audit_enabled = audit_default;
-	return 0;
+	return 1;
 }
 
 __setup("audit=", audit_enable);
diff --git a/kernel/compat.c b/kernel/compat.c
index 8c9cd88..c1601a8 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -17,10 +17,10 @@
 #include <linux/time.h>
 #include <linux/signal.h>
 #include <linux/sched.h>	/* for MAX_SCHEDULE_TIMEOUT */
-#include <linux/futex.h>	/* for FUTEX_WAIT */
 #include <linux/syscalls.h>
 #include <linux/unistd.h>
 #include <linux/security.h>
+#include <linux/timex.h>
 
 #include <asm/uaccess.h>
 
@@ -238,28 +238,6 @@
 	return ret;
 }
 
-#ifdef CONFIG_FUTEX
-asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, int val,
-		struct compat_timespec __user *utime, u32 __user *uaddr2,
-		int val3)
-{
-	struct timespec t;
-	unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
-	int val2 = 0;
-
-	if ((op == FUTEX_WAIT) && utime) {
-		if (get_compat_timespec(&t, utime))
-			return -EFAULT;
-		timeout = timespec_to_jiffies(&t) + 1;
-	}
-	if (op >= FUTEX_REQUEUE)
-		val2 = (int) (unsigned long) utime;
-
-	return do_futex((unsigned long)uaddr, op, val, timeout,
-			(unsigned long)uaddr2, val2, val3);
-}
-#endif
-
 asmlinkage long compat_sys_setrlimit(unsigned int resource,
 		struct compat_rlimit __user *rlim)
 {
@@ -898,3 +876,61 @@
 	return -ERESTARTNOHAND;
 }
 #endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */
+
+asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
+{
+	struct timex txc;
+	int ret;
+
+	memset(&txc, 0, sizeof(struct timex));
+
+	if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) ||
+			__get_user(txc.modes, &utp->modes) ||
+			__get_user(txc.offset, &utp->offset) ||
+			__get_user(txc.freq, &utp->freq) ||
+			__get_user(txc.maxerror, &utp->maxerror) ||
+			__get_user(txc.esterror, &utp->esterror) ||
+			__get_user(txc.status, &utp->status) ||
+			__get_user(txc.constant, &utp->constant) ||
+			__get_user(txc.precision, &utp->precision) ||
+			__get_user(txc.tolerance, &utp->tolerance) ||
+			__get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
+			__get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
+			__get_user(txc.tick, &utp->tick) ||
+			__get_user(txc.ppsfreq, &utp->ppsfreq) ||
+			__get_user(txc.jitter, &utp->jitter) ||
+			__get_user(txc.shift, &utp->shift) ||
+			__get_user(txc.stabil, &utp->stabil) ||
+			__get_user(txc.jitcnt, &utp->jitcnt) ||
+			__get_user(txc.calcnt, &utp->calcnt) ||
+			__get_user(txc.errcnt, &utp->errcnt) ||
+			__get_user(txc.stbcnt, &utp->stbcnt))
+		return -EFAULT;
+
+	ret = do_adjtimex(&txc);
+
+	if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) ||
+			__put_user(txc.modes, &utp->modes) ||
+			__put_user(txc.offset, &utp->offset) ||
+			__put_user(txc.freq, &utp->freq) ||
+			__put_user(txc.maxerror, &utp->maxerror) ||
+			__put_user(txc.esterror, &utp->esterror) ||
+			__put_user(txc.status, &utp->status) ||
+			__put_user(txc.constant, &utp->constant) ||
+			__put_user(txc.precision, &utp->precision) ||
+			__put_user(txc.tolerance, &utp->tolerance) ||
+			__put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
+			__put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
+			__put_user(txc.tick, &utp->tick) ||
+			__put_user(txc.ppsfreq, &utp->ppsfreq) ||
+			__put_user(txc.jitter, &utp->jitter) ||
+			__put_user(txc.shift, &utp->shift) ||
+			__put_user(txc.stabil, &utp->stabil) ||
+			__put_user(txc.jitcnt, &utp->jitcnt) ||
+			__put_user(txc.calcnt, &utp->calcnt) ||
+			__put_user(txc.errcnt, &utp->errcnt) ||
+			__put_user(txc.stbcnt, &utp->stbcnt))
+		ret = -EFAULT;
+
+	return ret;
+}
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 8be22bd..fe2b8d0 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -18,7 +18,7 @@
 /* This protects CPUs going up and down... */
 static DECLARE_MUTEX(cpucontrol);
 
-static struct notifier_block *cpu_chain;
+static BLOCKING_NOTIFIER_HEAD(cpu_chain);
 
 #ifdef CONFIG_HOTPLUG_CPU
 static struct task_struct *lock_cpu_hotplug_owner;
@@ -71,21 +71,13 @@
 /* Need to know about CPUs going up/down? */
 int register_cpu_notifier(struct notifier_block *nb)
 {
-	int ret;
-
-	if ((ret = lock_cpu_hotplug_interruptible()) != 0)
-		return ret;
-	ret = notifier_chain_register(&cpu_chain, nb);
-	unlock_cpu_hotplug();
-	return ret;
+	return blocking_notifier_chain_register(&cpu_chain, nb);
 }
 EXPORT_SYMBOL(register_cpu_notifier);
 
 void unregister_cpu_notifier(struct notifier_block *nb)
 {
-	lock_cpu_hotplug();
-	notifier_chain_unregister(&cpu_chain, nb);
-	unlock_cpu_hotplug();
+	blocking_notifier_chain_unregister(&cpu_chain, nb);
 }
 EXPORT_SYMBOL(unregister_cpu_notifier);
 
@@ -141,7 +133,7 @@
 		goto out;
 	}
 
-	err = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE,
+	err = blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE,
 						(void *)(long)cpu);
 	if (err == NOTIFY_BAD) {
 		printk("%s: attempt to take down CPU %u failed\n",
@@ -159,7 +151,7 @@
 	p = __stop_machine_run(take_cpu_down, NULL, cpu);
 	if (IS_ERR(p)) {
 		/* CPU didn't die: tell everyone.  Can't complain. */
-		if (notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED,
+		if (blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED,
 				(void *)(long)cpu) == NOTIFY_BAD)
 			BUG();
 
@@ -182,8 +174,8 @@
 	put_cpu();
 
 	/* CPU is completely dead: tell everyone.  Too late to complain. */
-	if (notifier_call_chain(&cpu_chain, CPU_DEAD, (void *)(long)cpu)
-	    == NOTIFY_BAD)
+	if (blocking_notifier_call_chain(&cpu_chain, CPU_DEAD,
+			(void *)(long)cpu) == NOTIFY_BAD)
 		BUG();
 
 	check_for_tasks(cpu);
@@ -211,7 +203,7 @@
 		goto out;
 	}
 
-	ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu);
+	ret = blocking_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu);
 	if (ret == NOTIFY_BAD) {
 		printk("%s: attempt to bring up CPU %u failed\n",
 				__FUNCTION__, cpu);
@@ -226,11 +218,12 @@
 	BUG_ON(!cpu_online(cpu));
 
 	/* Now call notifier in preparation. */
-	notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu);
+	blocking_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu);
 
 out_notify:
 	if (ret != 0)
-		notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu);
+		blocking_notifier_call_chain(&cpu_chain,
+				CPU_UP_CANCELED, hcpu);
 out:
 	unlock_cpu_hotplug();
 	return ret;
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 18aea1b..72248d1 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -616,12 +616,10 @@
  * current->cpuset if a task has its memory placement changed.
  * Do not call this routine if in_interrupt().
  *
- * Call without callback_mutex or task_lock() held.  May be called
- * with or without manage_mutex held.  Doesn't need task_lock to guard
- * against another task changing a non-NULL cpuset pointer to NULL,
- * as that is only done by a task on itself, and if the current task
- * is here, it is not simultaneously in the exit code NULL'ing its
- * cpuset pointer.  This routine also might acquire callback_mutex and
+ * Call without callback_mutex or task_lock() held.  May be
+ * called with or without manage_mutex held.  Thanks in part to
+ * 'the_top_cpuset_hack', the tasks cpuset pointer will never
+ * be NULL.  This routine also might acquire callback_mutex and
  * current->mm->mmap_sem during call.
  *
  * Reading current->cpuset->mems_generation doesn't need task_lock
@@ -836,6 +834,55 @@
 }
 
 /*
+ * cpuset_migrate_mm
+ *
+ *    Migrate memory region from one set of nodes to another.
+ *
+ *    Temporarilly set tasks mems_allowed to target nodes of migration,
+ *    so that the migration code can allocate pages on these nodes.
+ *
+ *    Call holding manage_mutex, so our current->cpuset won't change
+ *    during this call, as manage_mutex holds off any attach_task()
+ *    calls.  Therefore we don't need to take task_lock around the
+ *    call to guarantee_online_mems(), as we know no one is changing
+ *    our tasks cpuset.
+ *
+ *    Hold callback_mutex around the two modifications of our tasks
+ *    mems_allowed to synchronize with cpuset_mems_allowed().
+ *
+ *    While the mm_struct we are migrating is typically from some
+ *    other task, the task_struct mems_allowed that we are hacking
+ *    is for our current task, which must allocate new pages for that
+ *    migrating memory region.
+ *
+ *    We call cpuset_update_task_memory_state() before hacking
+ *    our tasks mems_allowed, so that we are assured of being in
+ *    sync with our tasks cpuset, and in particular, callbacks to
+ *    cpuset_update_task_memory_state() from nested page allocations
+ *    won't see any mismatch of our cpuset and task mems_generation
+ *    values, so won't overwrite our hacked tasks mems_allowed
+ *    nodemask.
+ */
+
+static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
+							const nodemask_t *to)
+{
+	struct task_struct *tsk = current;
+
+	cpuset_update_task_memory_state();
+
+	mutex_lock(&callback_mutex);
+	tsk->mems_allowed = *to;
+	mutex_unlock(&callback_mutex);
+
+	do_migrate_pages(mm, from, to, MPOL_MF_MOVE_ALL);
+
+	mutex_lock(&callback_mutex);
+	guarantee_online_mems(tsk->cpuset, &tsk->mems_allowed);
+	mutex_unlock(&callback_mutex);
+}
+
+/*
  * Handle user request to change the 'mems' memory placement
  * of a cpuset.  Needs to validate the request, update the
  * cpusets mems_allowed and mems_generation, and for each
@@ -947,10 +994,8 @@
 		struct mm_struct *mm = mmarray[i];
 
 		mpol_rebind_mm(mm, &cs->mems_allowed);
-		if (migrate) {
-			do_migrate_pages(mm, &oldmem, &cs->mems_allowed,
-							MPOL_MF_MOVE_ALL);
-		}
+		if (migrate)
+			cpuset_migrate_mm(mm, &oldmem, &cs->mems_allowed);
 		mmput(mm);
 	}
 
@@ -1185,11 +1230,11 @@
 	mm = get_task_mm(tsk);
 	if (mm) {
 		mpol_rebind_mm(mm, &to);
+		if (is_memory_migrate(cs))
+			cpuset_migrate_mm(mm, &from, &to);
 		mmput(mm);
 	}
 
-	if (is_memory_migrate(cs))
-		do_migrate_pages(tsk->mm, &from, &to, MPOL_MF_MOVE_ALL);
 	put_task_struct(tsk);
 	synchronize_rcu();
 	if (atomic_dec_and_test(&oldcs->count))
diff --git a/kernel/exit.c b/kernel/exit.c
index 8037405..6c2eeb8 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -29,8 +29,11 @@
 #include <linux/cpuset.h>
 #include <linux/syscalls.h>
 #include <linux/signal.h>
+#include <linux/posix-timers.h>
 #include <linux/cn_proc.h>
 #include <linux/mutex.h>
+#include <linux/futex.h>
+#include <linux/compat.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -48,15 +51,85 @@
 {
 	nr_threads--;
 	detach_pid(p, PIDTYPE_PID);
-	detach_pid(p, PIDTYPE_TGID);
 	if (thread_group_leader(p)) {
 		detach_pid(p, PIDTYPE_PGID);
 		detach_pid(p, PIDTYPE_SID);
-		if (p->pid)
-			__get_cpu_var(process_counts)--;
+
+		list_del_init(&p->tasks);
+		__get_cpu_var(process_counts)--;
+	}
+	list_del_rcu(&p->thread_group);
+	remove_parent(p);
+}
+
+/*
+ * This function expects the tasklist_lock write-locked.
+ */
+static void __exit_signal(struct task_struct *tsk)
+{
+	struct signal_struct *sig = tsk->signal;
+	struct sighand_struct *sighand;
+
+	BUG_ON(!sig);
+	BUG_ON(!atomic_read(&sig->count));
+
+	rcu_read_lock();
+	sighand = rcu_dereference(tsk->sighand);
+	spin_lock(&sighand->siglock);
+
+	posix_cpu_timers_exit(tsk);
+	if (atomic_dec_and_test(&sig->count))
+		posix_cpu_timers_exit_group(tsk);
+	else {
+		/*
+		 * If there is any task waiting for the group exit
+		 * then notify it:
+		 */
+		if (sig->group_exit_task && atomic_read(&sig->count) == sig->notify_count) {
+			wake_up_process(sig->group_exit_task);
+			sig->group_exit_task = NULL;
+		}
+		if (tsk == sig->curr_target)
+			sig->curr_target = next_thread(tsk);
+		/*
+		 * Accumulate here the counters for all threads but the
+		 * group leader as they die, so they can be added into
+		 * the process-wide totals when those are taken.
+		 * The group leader stays around as a zombie as long
+		 * as there are other threads.  When it gets reaped,
+		 * the exit.c code will add its counts into these totals.
+		 * We won't ever get here for the group leader, since it
+		 * will have been the last reference on the signal_struct.
+		 */
+		sig->utime = cputime_add(sig->utime, tsk->utime);
+		sig->stime = cputime_add(sig->stime, tsk->stime);
+		sig->min_flt += tsk->min_flt;
+		sig->maj_flt += tsk->maj_flt;
+		sig->nvcsw += tsk->nvcsw;
+		sig->nivcsw += tsk->nivcsw;
+		sig->sched_time += tsk->sched_time;
+		sig = NULL; /* Marker for below. */
 	}
 
-	REMOVE_LINKS(p);
+	__unhash_process(tsk);
+
+	tsk->signal = NULL;
+	tsk->sighand = NULL;
+	spin_unlock(&sighand->siglock);
+	rcu_read_unlock();
+
+	__cleanup_sighand(sighand);
+	clear_tsk_thread_flag(tsk,TIF_SIGPENDING);
+	flush_sigqueue(&tsk->pending);
+	if (sig) {
+		flush_sigqueue(&sig->shared_pending);
+		__cleanup_signal(sig);
+	}
+}
+
+static void delayed_put_task_struct(struct rcu_head *rhp)
+{
+	put_task_struct(container_of(rhp, struct task_struct, rcu));
 }
 
 void release_task(struct task_struct * p)
@@ -65,21 +138,14 @@
 	task_t *leader;
 	struct dentry *proc_dentry;
 
-repeat: 
+repeat:
 	atomic_dec(&p->user->processes);
 	spin_lock(&p->proc_lock);
 	proc_dentry = proc_pid_unhash(p);
 	write_lock_irq(&tasklist_lock);
-	if (unlikely(p->ptrace))
-		__ptrace_unlink(p);
+	ptrace_unlink(p);
 	BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children));
 	__exit_signal(p);
-	/*
-	 * Note that the fastpath in sys_times depends on __exit_signal having
-	 * updated the counters before a task is removed from the tasklist of
-	 * the process by __unhash_process.
-	 */
-	__unhash_process(p);
 
 	/*
 	 * If we are the last non-leader member of the thread
@@ -107,28 +173,13 @@
 	spin_unlock(&p->proc_lock);
 	proc_pid_flush(proc_dentry);
 	release_thread(p);
-	put_task_struct(p);
+	call_rcu(&p->rcu, delayed_put_task_struct);
 
 	p = leader;
 	if (unlikely(zap_leader))
 		goto repeat;
 }
 
-/* we are using it only for SMP init */
-
-void unhash_process(struct task_struct *p)
-{
-	struct dentry *proc_dentry;
-
-	spin_lock(&p->proc_lock);
-	proc_dentry = proc_pid_unhash(p);
-	write_lock_irq(&tasklist_lock);
-	__unhash_process(p);
-	write_unlock_irq(&tasklist_lock);
-	spin_unlock(&p->proc_lock);
-	proc_pid_flush(proc_dentry);
-}
-
 /*
  * This checks not only the pgrp, but falls back on the pid if no
  * satisfactory pgrp is found. I dunno - gdb doesn't work correctly
@@ -236,10 +287,10 @@
 
 	ptrace_unlink(current);
 	/* Reparent to init */
-	REMOVE_LINKS(current);
+	remove_parent(current);
 	current->parent = child_reaper;
 	current->real_parent = child_reaper;
-	SET_LINKS(current);
+	add_parent(current);
 
 	/* Set the exit signal to SIGCHLD so we signal init on exit */
 	current->exit_signal = SIGCHLD;
@@ -536,13 +587,13 @@
 	mmput(mm);
 }
 
-static inline void choose_new_parent(task_t *p, task_t *reaper, task_t *child_reaper)
+static inline void choose_new_parent(task_t *p, task_t *reaper)
 {
 	/*
 	 * Make sure we're not reparenting to ourselves and that
 	 * the parent is not a zombie.
 	 */
-	BUG_ON(p == reaper || reaper->exit_state >= EXIT_ZOMBIE);
+	BUG_ON(p == reaper || reaper->exit_state);
 	p->real_parent = reaper;
 }
 
@@ -567,9 +618,9 @@
 		 * anyway, so let go of it.
 		 */
 		p->ptrace = 0;
-		list_del_init(&p->sibling);
+		remove_parent(p);
 		p->parent = p->real_parent;
-		list_add_tail(&p->sibling, &p->parent->children);
+		add_parent(p);
 
 		/* If we'd notified the old parent about this child's death,
 		 * also notify the new parent.
@@ -643,7 +694,7 @@
 
 		if (father == p->real_parent) {
 			/* reparent with a reaper, real father it's us */
-			choose_new_parent(p, reaper, child_reaper);
+			choose_new_parent(p, reaper);
 			reparent_thread(p, father, 0);
 		} else {
 			/* reparent ptraced task to its real parent */
@@ -664,7 +715,7 @@
 	}
 	list_for_each_safe(_p, _n, &father->ptrace_children) {
 		p = list_entry(_p,struct task_struct,ptrace_list);
-		choose_new_parent(p, reaper, child_reaper);
+		choose_new_parent(p, reaper);
 		reparent_thread(p, father, 1);
 	}
 }
@@ -805,7 +856,7 @@
 		panic("Aiee, killing interrupt handler!");
 	if (unlikely(!tsk->pid))
 		panic("Attempted to kill the idle task!");
-	if (unlikely(tsk->pid == 1))
+	if (unlikely(tsk == child_reaper))
 		panic("Attempted to kill init!");
 
 	if (unlikely(current->ptrace & PT_TRACE_EXIT)) {
@@ -852,6 +903,12 @@
 		exit_itimers(tsk->signal);
 		acct_process(code);
 	}
+	if (unlikely(tsk->robust_list))
+		exit_robust_list(tsk);
+#ifdef CONFIG_COMPAT
+	if (unlikely(tsk->compat_robust_list))
+		compat_exit_robust_list(tsk);
+#endif
 	exit_mm(tsk);
 
 	exit_sem(tsk);
@@ -912,13 +969,6 @@
 	do_exit((error_code&0xff)<<8);
 }
 
-task_t fastcall *next_thread(const task_t *p)
-{
-	return pid_task(p->pids[PIDTYPE_TGID].pid_list.next, PIDTYPE_TGID);
-}
-
-EXPORT_SYMBOL(next_thread);
-
 /*
  * Take down every thread in the group.  This is called by fatal signals
  * as well as by sys_exit_group (below).
@@ -933,7 +983,6 @@
 	else if (!thread_group_empty(current)) {
 		struct signal_struct *const sig = current->signal;
 		struct sighand_struct *const sighand = current->sighand;
-		read_lock(&tasklist_lock);
 		spin_lock_irq(&sighand->siglock);
 		if (sig->flags & SIGNAL_GROUP_EXIT)
 			/* Another thread got here before we took the lock.  */
@@ -943,7 +992,6 @@
 			zap_other_threads(current);
 		}
 		spin_unlock_irq(&sighand->siglock);
-		read_unlock(&tasklist_lock);
 	}
 
 	do_exit(exit_code);
@@ -1273,7 +1321,7 @@
 
 	/* move to end of parent's list to avoid starvation */
 	remove_parent(p);
-	add_parent(p, p->parent);
+	add_parent(p);
 
 	write_unlock_irq(&tasklist_lock);
 
diff --git a/kernel/fork.c b/kernel/fork.c
index a020639..3384eb8 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -84,7 +84,7 @@
 #endif
 
 /* SLAB cache for signal_struct structures (tsk->signal) */
-kmem_cache_t *signal_cachep;
+static kmem_cache_t *signal_cachep;
 
 /* SLAB cache for sighand_struct structures (tsk->sighand) */
 kmem_cache_t *sighand_cachep;
@@ -108,10 +108,8 @@
 }
 EXPORT_SYMBOL(free_task);
 
-void __put_task_struct_cb(struct rcu_head *rhp)
+void __put_task_struct(struct task_struct *tsk)
 {
-	struct task_struct *tsk = container_of(rhp, struct task_struct, rcu);
-
 	WARN_ON(!(tsk->exit_state & (EXIT_DEAD | EXIT_ZOMBIE)));
 	WARN_ON(atomic_read(&tsk->usage));
 	WARN_ON(tsk == current);
@@ -126,6 +124,12 @@
 		free_task(tsk);
 }
 
+void __put_task_struct_cb(struct rcu_head *rhp)
+{
+	struct task_struct *tsk = container_of(rhp, struct task_struct, rcu);
+	__put_task_struct(tsk);
+}
+
 void __init fork_init(unsigned long mempages)
 {
 #ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR
@@ -721,7 +725,7 @@
 	free_fdset (new_fdt->open_fds, new_fdt->max_fdset);
 	free_fd_array(new_fdt->fd, new_fdt->max_fds);
 	kmem_cache_free(files_cachep, newf);
-	goto out;
+	return NULL;
 }
 
 static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
@@ -769,8 +773,7 @@
 	struct files_struct *files  = current->files;
 	int rc;
 
-	if(!files)
-		BUG();
+	BUG_ON(!files);
 
 	/* This can race but the race causes us to copy when we don't
 	   need to and drop the copy */
@@ -787,14 +790,6 @@
 
 EXPORT_SYMBOL(unshare_files);
 
-void sighand_free_cb(struct rcu_head *rhp)
-{
-	struct sighand_struct *sp;
-
-	sp = container_of(rhp, struct sighand_struct, rcu);
-	kmem_cache_free(sighand_cachep, sp);
-}
-
 static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk)
 {
 	struct sighand_struct *sig;
@@ -807,12 +802,17 @@
 	rcu_assign_pointer(tsk->sighand, sig);
 	if (!sig)
 		return -ENOMEM;
-	spin_lock_init(&sig->siglock);
 	atomic_set(&sig->count, 1);
 	memcpy(sig->action, current->sighand->action, sizeof(sig->action));
 	return 0;
 }
 
+void __cleanup_sighand(struct sighand_struct *sighand)
+{
+	if (atomic_dec_and_test(&sighand->count))
+		kmem_cache_free(sighand_cachep, sighand);
+}
+
 static inline int copy_signal(unsigned long clone_flags, struct task_struct * tsk)
 {
 	struct signal_struct *sig;
@@ -848,7 +848,7 @@
 	hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_REL);
 	sig->it_real_incr.tv64 = 0;
 	sig->real_timer.function = it_real_fn;
-	sig->real_timer.data = tsk;
+	sig->tsk = tsk;
 
 	sig->it_virt_expires = cputime_zero;
 	sig->it_virt_incr = cputime_zero;
@@ -882,6 +882,22 @@
 	return 0;
 }
 
+void __cleanup_signal(struct signal_struct *sig)
+{
+	exit_thread_group_keys(sig);
+	kmem_cache_free(signal_cachep, sig);
+}
+
+static inline void cleanup_signal(struct task_struct *tsk)
+{
+	struct signal_struct *sig = tsk->signal;
+
+	atomic_dec(&sig->live);
+
+	if (atomic_dec_and_test(&sig->count))
+		__cleanup_signal(sig);
+}
+
 static inline void copy_flags(unsigned long clone_flags, struct task_struct *p)
 {
 	unsigned long new_flags = p->flags;
@@ -1062,7 +1078,10 @@
 	 * Clear TID on mm_release()?
 	 */
 	p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr: NULL;
-
+	p->robust_list = NULL;
+#ifdef CONFIG_COMPAT
+	p->compat_robust_list = NULL;
+#endif
 	/*
 	 * sigaltstack should be cleared when sharing the same VM
 	 */
@@ -1093,6 +1112,7 @@
 	 * We dont wake it up yet.
 	 */
 	p->group_leader = p;
+	INIT_LIST_HEAD(&p->thread_group);
 	INIT_LIST_HEAD(&p->ptrace_children);
 	INIT_LIST_HEAD(&p->ptrace_list);
 
@@ -1116,16 +1136,6 @@
 			!cpu_online(task_cpu(p))))
 		set_task_cpu(p, smp_processor_id());
 
-	/*
-	 * Check for pending SIGKILL! The new thread should not be allowed
-	 * to slip out of an OOM kill. (or normal SIGKILL.)
-	 */
-	if (sigismember(&current->pending.signal, SIGKILL)) {
-		write_unlock_irq(&tasklist_lock);
-		retval = -EINTR;
-		goto bad_fork_cleanup_namespace;
-	}
-
 	/* CLONE_PARENT re-uses the old parent */
 	if (clone_flags & (CLONE_PARENT|CLONE_THREAD))
 		p->real_parent = current->real_parent;
@@ -1134,6 +1144,23 @@
 	p->parent = p->real_parent;
 
 	spin_lock(&current->sighand->siglock);
+
+	/*
+	 * Process group and session signals need to be delivered to just the
+	 * parent before the fork or both the parent and the child after the
+	 * fork. Restart if a signal comes in before we add the new process to
+	 * it's process group.
+	 * A fatal signal pending means that current will exit, so the new
+	 * thread can't slip out of an OOM kill (or normal SIGKILL).
+ 	 */
+ 	recalc_sigpending();
+	if (signal_pending(current)) {
+		spin_unlock(&current->sighand->siglock);
+		write_unlock_irq(&tasklist_lock);
+		retval = -ERESTARTNOINTR;
+		goto bad_fork_cleanup_namespace;
+	}
+
 	if (clone_flags & CLONE_THREAD) {
 		/*
 		 * Important: if an exit-all has been started then
@@ -1146,17 +1173,9 @@
 			retval = -EAGAIN;
 			goto bad_fork_cleanup_namespace;
 		}
-		p->group_leader = current->group_leader;
 
-		if (current->signal->group_stop_count > 0) {
-			/*
-			 * There is an all-stop in progress for the group.
-			 * We ourselves will stop as soon as we check signals.
-			 * Make the new thread part of that group stop too.
-			 */
-			current->signal->group_stop_count++;
-			set_tsk_thread_flag(p, TIF_SIGPENDING);
-		}
+		p->group_leader = current->group_leader;
+		list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group);
 
 		if (!cputime_eq(current->signal->it_virt_expires,
 				cputime_zero) ||
@@ -1179,23 +1198,25 @@
 	 */
 	p->ioprio = current->ioprio;
 
-	SET_LINKS(p);
-	if (unlikely(p->ptrace & PT_PTRACED))
-		__ptrace_link(p, current->parent);
+	if (likely(p->pid)) {
+		add_parent(p);
+		if (unlikely(p->ptrace & PT_PTRACED))
+			__ptrace_link(p, current->parent);
 
-	if (thread_group_leader(p)) {
-		p->signal->tty = current->signal->tty;
-		p->signal->pgrp = process_group(current);
-		p->signal->session = current->signal->session;
-		attach_pid(p, PIDTYPE_PGID, process_group(p));
-		attach_pid(p, PIDTYPE_SID, p->signal->session);
-		if (p->pid)
+		if (thread_group_leader(p)) {
+			p->signal->tty = current->signal->tty;
+			p->signal->pgrp = process_group(current);
+			p->signal->session = current->signal->session;
+			attach_pid(p, PIDTYPE_PGID, process_group(p));
+			attach_pid(p, PIDTYPE_SID, p->signal->session);
+
+			list_add_tail(&p->tasks, &init_task.tasks);
 			__get_cpu_var(process_counts)++;
+		}
+		attach_pid(p, PIDTYPE_PID, p->pid);
+		nr_threads++;
 	}
-	attach_pid(p, PIDTYPE_TGID, p->tgid);
-	attach_pid(p, PIDTYPE_PID, p->pid);
 
-	nr_threads++;
 	total_forks++;
 	spin_unlock(&current->sighand->siglock);
 	write_unlock_irq(&tasklist_lock);
@@ -1210,9 +1231,9 @@
 	if (p->mm)
 		mmput(p->mm);
 bad_fork_cleanup_signal:
-	exit_signal(p);
+	cleanup_signal(p);
 bad_fork_cleanup_sighand:
-	exit_sighand(p);
+	__cleanup_sighand(p->sighand);
 bad_fork_cleanup_fs:
 	exit_fs(p); /* blocking */
 bad_fork_cleanup_files:
@@ -1259,7 +1280,7 @@
 	if (!task)
 		return ERR_PTR(-ENOMEM);
 	init_idle(task, cpu);
-	unhash_process(task);
+
 	return task;
 }
 
@@ -1294,17 +1315,19 @@
 {
 	struct task_struct *p;
 	int trace = 0;
-	long pid = alloc_pidmap();
+	struct pid *pid = alloc_pid();
+	long nr;
 
-	if (pid < 0)
+	if (!pid)
 		return -EAGAIN;
+	nr = pid->nr;
 	if (unlikely(current->ptrace)) {
 		trace = fork_traceflag (clone_flags);
 		if (trace)
 			clone_flags |= CLONE_PTRACE;
 	}
 
-	p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid);
+	p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, nr);
 	/*
 	 * Do this prior waking up the new thread - the thread pointer
 	 * might get invalid after that point, if the thread exits quickly.
@@ -1331,7 +1354,7 @@
 			p->state = TASK_STOPPED;
 
 		if (unlikely (trace)) {
-			current->ptrace_message = pid;
+			current->ptrace_message = nr;
 			ptrace_notify ((trace << 8) | SIGTRAP);
 		}
 
@@ -1341,21 +1364,31 @@
 				ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);
 		}
 	} else {
-		free_pidmap(pid);
-		pid = PTR_ERR(p);
+		free_pid(pid);
+		nr = PTR_ERR(p);
 	}
-	return pid;
+	return nr;
 }
 
 #ifndef ARCH_MIN_MMSTRUCT_ALIGN
 #define ARCH_MIN_MMSTRUCT_ALIGN 0
 #endif
 
+static void sighand_ctor(void *data, kmem_cache_t *cachep, unsigned long flags)
+{
+	struct sighand_struct *sighand = data;
+
+	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+					SLAB_CTOR_CONSTRUCTOR)
+		spin_lock_init(&sighand->siglock);
+}
+
 void __init proc_caches_init(void)
 {
 	sighand_cachep = kmem_cache_create("sighand_cache",
 			sizeof(struct sighand_struct), 0,
-			SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+			SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_DESTROY_BY_RCU,
+			sighand_ctor, NULL);
 	signal_cachep = kmem_cache_create("signal_cache",
 			sizeof(struct signal_struct), 0,
 			SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
diff --git a/kernel/futex.c b/kernel/futex.c
index 5efa2f9..5699c51 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -8,6 +8,10 @@
  *  Removed page pinning, fix privately mapped COW pages and other cleanups
  *  (C) Copyright 2003, 2004 Jamie Lokier
  *
+ *  Robust futex support started by Ingo Molnar
+ *  (C) Copyright 2006 Red Hat Inc, All Rights Reserved
+ *  Thanks to Thomas Gleixner for suggestions, analysis and fixes.
+ *
  *  Thanks to Ben LaHaise for yelling "hashed waitqueues" loudly
  *  enough at me, Linus for the original (flawed) idea, Matthew
  *  Kirkwood for proof-of-concept implementation.
@@ -829,6 +833,172 @@
 	goto out;
 }
 
+/*
+ * Support for robust futexes: the kernel cleans up held futexes at
+ * thread exit time.
+ *
+ * Implementation: user-space maintains a per-thread list of locks it
+ * is holding. Upon do_exit(), the kernel carefully walks this list,
+ * and marks all locks that are owned by this thread with the
+ * FUTEX_OWNER_DEAD bit, and wakes up a waiter (if any). The list is
+ * always manipulated with the lock held, so the list is private and
+ * per-thread. Userspace also maintains a per-thread 'list_op_pending'
+ * field, to allow the kernel to clean up if the thread dies after
+ * acquiring the lock, but just before it could have added itself to
+ * the list. There can only be one such pending lock.
+ */
+
+/**
+ * sys_set_robust_list - set the robust-futex list head of a task
+ * @head: pointer to the list-head
+ * @len: length of the list-head, as userspace expects
+ */
+asmlinkage long
+sys_set_robust_list(struct robust_list_head __user *head,
+		    size_t len)
+{
+	/*
+	 * The kernel knows only one size for now:
+	 */
+	if (unlikely(len != sizeof(*head)))
+		return -EINVAL;
+
+	current->robust_list = head;
+
+	return 0;
+}
+
+/**
+ * sys_get_robust_list - get the robust-futex list head of a task
+ * @pid: pid of the process [zero for current task]
+ * @head_ptr: pointer to a list-head pointer, the kernel fills it in
+ * @len_ptr: pointer to a length field, the kernel fills in the header size
+ */
+asmlinkage long
+sys_get_robust_list(int pid, struct robust_list_head __user **head_ptr,
+		    size_t __user *len_ptr)
+{
+	struct robust_list_head *head;
+	unsigned long ret;
+
+	if (!pid)
+		head = current->robust_list;
+	else {
+		struct task_struct *p;
+
+		ret = -ESRCH;
+		read_lock(&tasklist_lock);
+		p = find_task_by_pid(pid);
+		if (!p)
+			goto err_unlock;
+		ret = -EPERM;
+		if ((current->euid != p->euid) && (current->euid != p->uid) &&
+				!capable(CAP_SYS_PTRACE))
+			goto err_unlock;
+		head = p->robust_list;
+		read_unlock(&tasklist_lock);
+	}
+
+	if (put_user(sizeof(*head), len_ptr))
+		return -EFAULT;
+	return put_user(head, head_ptr);
+
+err_unlock:
+	read_unlock(&tasklist_lock);
+
+	return ret;
+}
+
+/*
+ * Process a futex-list entry, check whether it's owned by the
+ * dying task, and do notification if so:
+ */
+int handle_futex_death(u32 __user *uaddr, struct task_struct *curr)
+{
+	u32 uval;
+
+retry:
+	if (get_user(uval, uaddr))
+		return -1;
+
+	if ((uval & FUTEX_TID_MASK) == curr->pid) {
+		/*
+		 * Ok, this dying thread is truly holding a futex
+		 * of interest. Set the OWNER_DIED bit atomically
+		 * via cmpxchg, and if the value had FUTEX_WAITERS
+		 * set, wake up a waiter (if any). (We have to do a
+		 * futex_wake() even if OWNER_DIED is already set -
+		 * to handle the rare but possible case of recursive
+		 * thread-death.) The rest of the cleanup is done in
+		 * userspace.
+		 */
+		if (futex_atomic_cmpxchg_inatomic(uaddr, uval,
+					 uval | FUTEX_OWNER_DIED) != uval)
+			goto retry;
+
+		if (uval & FUTEX_WAITERS)
+			futex_wake((unsigned long)uaddr, 1);
+	}
+	return 0;
+}
+
+/*
+ * Walk curr->robust_list (very carefully, it's a userspace list!)
+ * and mark any locks found there dead, and notify any waiters.
+ *
+ * We silently return on any sign of list-walking problem.
+ */
+void exit_robust_list(struct task_struct *curr)
+{
+	struct robust_list_head __user *head = curr->robust_list;
+	struct robust_list __user *entry, *pending;
+	unsigned int limit = ROBUST_LIST_LIMIT;
+	unsigned long futex_offset;
+
+	/*
+	 * Fetch the list head (which was registered earlier, via
+	 * sys_set_robust_list()):
+	 */
+	if (get_user(entry, &head->list.next))
+		return;
+	/*
+	 * Fetch the relative futex offset:
+	 */
+	if (get_user(futex_offset, &head->futex_offset))
+		return;
+	/*
+	 * Fetch any possibly pending lock-add first, and handle it
+	 * if it exists:
+	 */
+	if (get_user(pending, &head->list_op_pending))
+		return;
+	if (pending)
+		handle_futex_death((void *)pending + futex_offset, curr);
+
+	while (entry != &head->list) {
+		/*
+		 * A pending lock might already be on the list, so
+		 * dont process it twice:
+		 */
+		if (entry != pending)
+			if (handle_futex_death((void *)entry + futex_offset,
+						curr))
+				return;
+		/*
+		 * Fetch the next entry in the list:
+		 */
+		if (get_user(entry, &entry->next))
+			return;
+		/*
+		 * Avoid excessively long or circular lists:
+		 */
+		if (!--limit)
+			break;
+
+		cond_resched();
+	}
+}
+
 long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout,
 		unsigned long uaddr2, int val2, int val3)
 {
@@ -869,9 +1039,11 @@
 	unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
 	int val2 = 0;
 
-	if ((op == FUTEX_WAIT) && utime) {
+	if (utime && (op == FUTEX_WAIT)) {
 		if (copy_from_user(&t, utime, sizeof(t)) != 0)
 			return -EFAULT;
+		if (!timespec_valid(&t))
+			return -EINVAL;
 		timeout = timespec_to_jiffies(&t) + 1;
 	}
 	/*
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
new file mode 100644
index 0000000..1ab6a0e
--- /dev/null
+++ b/kernel/futex_compat.c
@@ -0,0 +1,144 @@
+/*
+ * linux/kernel/futex_compat.c
+ *
+ * Futex compatibililty routines.
+ *
+ * Copyright 2006, Red Hat, Inc., Ingo Molnar
+ */
+
+#include <linux/linkage.h>
+#include <linux/compat.h>
+#include <linux/futex.h>
+
+#include <asm/uaccess.h>
+
+/*
+ * Walk curr->robust_list (very carefully, it's a userspace list!)
+ * and mark any locks found there dead, and notify any waiters.
+ *
+ * We silently return on any sign of list-walking problem.
+ */
+void compat_exit_robust_list(struct task_struct *curr)
+{
+	struct compat_robust_list_head __user *head = curr->compat_robust_list;
+	struct robust_list __user *entry, *pending;
+	compat_uptr_t uentry, upending;
+	unsigned int limit = ROBUST_LIST_LIMIT;
+	compat_long_t futex_offset;
+
+	/*
+	 * Fetch the list head (which was registered earlier, via
+	 * sys_set_robust_list()):
+	 */
+	if (get_user(uentry, &head->list.next))
+		return;
+	entry = compat_ptr(uentry);
+	/*
+	 * Fetch the relative futex offset:
+	 */
+	if (get_user(futex_offset, &head->futex_offset))
+		return;
+	/*
+	 * Fetch any possibly pending lock-add first, and handle it
+	 * if it exists:
+	 */
+	if (get_user(upending, &head->list_op_pending))
+		return;
+	pending = compat_ptr(upending);
+	if (upending)
+		handle_futex_death((void *)pending + futex_offset, curr);
+
+	while (compat_ptr(uentry) != &head->list) {
+		/*
+		 * A pending lock might already be on the list, so
+		 * dont process it twice:
+		 */
+		if (entry != pending)
+			if (handle_futex_death((void *)entry + futex_offset,
+						curr))
+				return;
+
+		/*
+		 * Fetch the next entry in the list:
+		 */
+		if (get_user(uentry, (compat_uptr_t *)&entry->next))
+			return;
+		entry = compat_ptr(uentry);
+		/*
+		 * Avoid excessively long or circular lists:
+		 */
+		if (!--limit)
+			break;
+
+		cond_resched();
+	}
+}
+
+asmlinkage long
+compat_sys_set_robust_list(struct compat_robust_list_head __user *head,
+			   compat_size_t len)
+{
+	if (unlikely(len != sizeof(*head)))
+		return -EINVAL;
+
+	current->compat_robust_list = head;
+
+	return 0;
+}
+
+asmlinkage long
+compat_sys_get_robust_list(int pid, compat_uptr_t *head_ptr,
+			   compat_size_t __user *len_ptr)
+{
+	struct compat_robust_list_head *head;
+	unsigned long ret;
+
+	if (!pid)
+		head = current->compat_robust_list;
+	else {
+		struct task_struct *p;
+
+		ret = -ESRCH;
+		read_lock(&tasklist_lock);
+		p = find_task_by_pid(pid);
+		if (!p)
+			goto err_unlock;
+		ret = -EPERM;
+		if ((current->euid != p->euid) && (current->euid != p->uid) &&
+				!capable(CAP_SYS_PTRACE))
+			goto err_unlock;
+		head = p->compat_robust_list;
+		read_unlock(&tasklist_lock);
+	}
+
+	if (put_user(sizeof(*head), len_ptr))
+		return -EFAULT;
+	return put_user(ptr_to_compat(head), head_ptr);
+
+err_unlock:
+	read_unlock(&tasklist_lock);
+
+	return ret;
+}
+
+asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
+		struct compat_timespec __user *utime, u32 __user *uaddr2,
+		u32 val3)
+{
+	struct timespec t;
+	unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
+	int val2 = 0;
+
+	if (utime && (op == FUTEX_WAIT)) {
+		if (get_compat_timespec(&t, utime))
+			return -EFAULT;
+		if (!timespec_valid(&t))
+			return -EINVAL;
+		timeout = timespec_to_jiffies(&t) + 1;
+	}
+	if (op >= FUTEX_REQUEUE)
+		val2 = (int) (unsigned long) utime;
+
+	return do_futex((unsigned long)uaddr, op, val, timeout,
+			(unsigned long)uaddr2, val2, val3);
+}
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 14bc9cf..f181ff4 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -123,6 +123,26 @@
 EXPORT_SYMBOL_GPL(ktime_get_ts);
 
 /*
+ * Get the coarse grained time at the softirq based on xtime and
+ * wall_to_monotonic.
+ */
+static void hrtimer_get_softirq_time(struct hrtimer_base *base)
+{
+	ktime_t xtim, tomono;
+	unsigned long seq;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		xtim = timespec_to_ktime(xtime);
+		tomono = timespec_to_ktime(wall_to_monotonic);
+
+	} while (read_seqretry(&xtime_lock, seq));
+
+	base[CLOCK_REALTIME].softirq_time = xtim;
+	base[CLOCK_MONOTONIC].softirq_time = ktime_add(xtim, tomono);
+}
+
+/*
  * Functions and macros which are different for UP/SMP systems are kept in a
  * single place
  */
@@ -246,7 +266,7 @@
 /*
  * Divide a ktime value by a nanosecond value
  */
-static unsigned long ktime_divns(const ktime_t kt, nsec_t div)
+static unsigned long ktime_divns(const ktime_t kt, s64 div)
 {
 	u64 dclc, inc, dns;
 	int sft = 0;
@@ -281,18 +301,17 @@
  * hrtimer_forward - forward the timer expiry
  *
  * @timer:	hrtimer to forward
+ * @now:	forward past this time
  * @interval:	the interval to forward
  *
  * Forward the timer expiry so it will expire in the future.
  * Returns the number of overruns.
  */
 unsigned long
-hrtimer_forward(struct hrtimer *timer, ktime_t interval)
+hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
 {
 	unsigned long orun = 1;
-	ktime_t delta, now;
-
-	now = timer->base->get_time();
+	ktime_t delta;
 
 	delta = ktime_sub(now, timer->expires);
 
@@ -303,7 +322,7 @@
 		interval.tv64 = timer->base->resolution.tv64;
 
 	if (unlikely(delta.tv64 >= interval.tv64)) {
-		nsec_t incr = ktime_to_ns(interval);
+		s64 incr = ktime_to_ns(interval);
 
 		orun = ktime_divns(delta, incr);
 		timer->expires = ktime_add_ns(timer->expires, incr * orun);
@@ -355,8 +374,6 @@
 	rb_link_node(&timer->node, parent, link);
 	rb_insert_color(&timer->node, &base->active);
 
-	timer->state = HRTIMER_PENDING;
-
 	if (!base->first || timer->expires.tv64 <
 	    rb_entry(base->first, struct hrtimer, node)->expires.tv64)
 		base->first = &timer->node;
@@ -376,6 +393,7 @@
 	if (base->first == &timer->node)
 		base->first = rb_next(&timer->node);
 	rb_erase(&timer->node, &base->active);
+	timer->node.rb_parent = HRTIMER_INACTIVE;
 }
 
 /*
@@ -386,7 +404,6 @@
 {
 	if (hrtimer_active(timer)) {
 		__remove_hrtimer(timer, base);
-		timer->state = HRTIMER_INACTIVE;
 		return 1;
 	}
 	return 0;
@@ -560,6 +577,7 @@
 		clock_id = CLOCK_MONOTONIC;
 
 	timer->base = &bases[clock_id];
+	timer->node.rb_parent = HRTIMER_INACTIVE;
 }
 
 /**
@@ -586,48 +604,38 @@
  */
 static inline void run_hrtimer_queue(struct hrtimer_base *base)
 {
-	ktime_t now = base->get_time();
 	struct rb_node *node;
 
+	if (!base->first)
+		return;
+
+	if (base->get_softirq_time)
+		base->softirq_time = base->get_softirq_time();
+
 	spin_lock_irq(&base->lock);
 
 	while ((node = base->first)) {
 		struct hrtimer *timer;
-		int (*fn)(void *);
+		int (*fn)(struct hrtimer *);
 		int restart;
-		void *data;
 
 		timer = rb_entry(node, struct hrtimer, node);
-		if (now.tv64 <= timer->expires.tv64)
+		if (base->softirq_time.tv64 <= timer->expires.tv64)
 			break;
 
 		fn = timer->function;
-		data = timer->data;
 		set_curr_timer(base, timer);
-		timer->state = HRTIMER_RUNNING;
 		__remove_hrtimer(timer, base);
 		spin_unlock_irq(&base->lock);
 
-		/*
-		 * fn == NULL is special case for the simplest timer
-		 * variant - wake up process and do not restart:
-		 */
-		if (!fn) {
-			wake_up_process(data);
-			restart = HRTIMER_NORESTART;
-		} else
-			restart = fn(data);
+		restart = fn(timer);
 
 		spin_lock_irq(&base->lock);
 
-		/* Another CPU has added back the timer */
-		if (timer->state != HRTIMER_RUNNING)
-			continue;
-
-		if (restart == HRTIMER_RESTART)
+		if (restart != HRTIMER_NORESTART) {
+			BUG_ON(hrtimer_active(timer));
 			enqueue_hrtimer(timer, base);
-		else
-			timer->state = HRTIMER_EXPIRED;
+		}
 	}
 	set_curr_timer(base, NULL);
 	spin_unlock_irq(&base->lock);
@@ -641,6 +649,8 @@
 	struct hrtimer_base *base = __get_cpu_var(hrtimer_bases);
 	int i;
 
+	hrtimer_get_softirq_time(base);
+
 	for (i = 0; i < MAX_HRTIMER_BASES; i++)
 		run_hrtimer_queue(&base[i]);
 }
@@ -648,80 +658,69 @@
 /*
  * Sleep related functions:
  */
-
-/**
- * schedule_hrtimer - sleep until timeout
- *
- * @timer:	hrtimer variable initialized with the correct clock base
- * @mode:	timeout value is abs/rel
- *
- * Make the current task sleep until @timeout is
- * elapsed.
- *
- * You can set the task state as follows -
- *
- * %TASK_UNINTERRUPTIBLE - at least @timeout is guaranteed to
- * pass before the routine returns. The routine will return 0
- *
- * %TASK_INTERRUPTIBLE - the routine may return early if a signal is
- * delivered to the current task. In this case the remaining time
- * will be returned
- *
- * The current task state is guaranteed to be TASK_RUNNING when this
- * routine returns.
- */
-static ktime_t __sched
-schedule_hrtimer(struct hrtimer *timer, const enum hrtimer_mode mode)
+static int hrtimer_wakeup(struct hrtimer *timer)
 {
-	/* fn stays NULL, meaning single-shot wakeup: */
-	timer->data = current;
+	struct hrtimer_sleeper *t =
+		container_of(timer, struct hrtimer_sleeper, timer);
+	struct task_struct *task = t->task;
 
-	hrtimer_start(timer, timer->expires, mode);
+	t->task = NULL;
+	if (task)
+		wake_up_process(task);
 
-	schedule();
-	hrtimer_cancel(timer);
-
-	/* Return the remaining time: */
-	if (timer->state != HRTIMER_EXPIRED)
-		return ktime_sub(timer->expires, timer->base->get_time());
-	else
-		return (ktime_t) {.tv64 = 0 };
+	return HRTIMER_NORESTART;
 }
 
-static inline ktime_t __sched
-schedule_hrtimer_interruptible(struct hrtimer *timer,
-			       const enum hrtimer_mode mode)
+void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, task_t *task)
 {
-	set_current_state(TASK_INTERRUPTIBLE);
+	sl->timer.function = hrtimer_wakeup;
+	sl->task = task;
+}
 
-	return schedule_hrtimer(timer, mode);
+static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)
+{
+	hrtimer_init_sleeper(t, current);
+
+	do {
+		set_current_state(TASK_INTERRUPTIBLE);
+		hrtimer_start(&t->timer, t->timer.expires, mode);
+
+		schedule();
+
+		hrtimer_cancel(&t->timer);
+		mode = HRTIMER_ABS;
+
+	} while (t->task && !signal_pending(current));
+
+	return t->task == NULL;
 }
 
 static long __sched nanosleep_restart(struct restart_block *restart)
 {
+	struct hrtimer_sleeper t;
 	struct timespec __user *rmtp;
 	struct timespec tu;
-	void *rfn_save = restart->fn;
-	struct hrtimer timer;
-	ktime_t rem;
+	ktime_t time;
 
 	restart->fn = do_no_restart_syscall;
 
-	hrtimer_init(&timer, (clockid_t) restart->arg3, HRTIMER_ABS);
+	hrtimer_init(&t.timer, restart->arg3, HRTIMER_ABS);
+	t.timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0;
 
-	timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0;
-
-	rem = schedule_hrtimer_interruptible(&timer, HRTIMER_ABS);
-
-	if (rem.tv64 <= 0)
+	if (do_nanosleep(&t, HRTIMER_ABS))
 		return 0;
 
 	rmtp = (struct timespec __user *) restart->arg2;
-	tu = ktime_to_timespec(rem);
-	if (rmtp && copy_to_user(rmtp, &tu, sizeof(tu)))
-		return -EFAULT;
+	if (rmtp) {
+		time = ktime_sub(t.timer.expires, t.timer.base->get_time());
+		if (time.tv64 <= 0)
+			return 0;
+		tu = ktime_to_timespec(time);
+		if (copy_to_user(rmtp, &tu, sizeof(tu)))
+			return -EFAULT;
+	}
 
-	restart->fn = rfn_save;
+	restart->fn = nanosleep_restart;
 
 	/* The other values in restart are already filled in */
 	return -ERESTART_RESTARTBLOCK;
@@ -731,33 +730,34 @@
 		       const enum hrtimer_mode mode, const clockid_t clockid)
 {
 	struct restart_block *restart;
-	struct hrtimer timer;
+	struct hrtimer_sleeper t;
 	struct timespec tu;
 	ktime_t rem;
 
-	hrtimer_init(&timer, clockid, mode);
-
-	timer.expires = timespec_to_ktime(*rqtp);
-
-	rem = schedule_hrtimer_interruptible(&timer, mode);
-	if (rem.tv64 <= 0)
+	hrtimer_init(&t.timer, clockid, mode);
+	t.timer.expires = timespec_to_ktime(*rqtp);
+	if (do_nanosleep(&t, mode))
 		return 0;
 
 	/* Absolute timers do not update the rmtp value and restart: */
 	if (mode == HRTIMER_ABS)
 		return -ERESTARTNOHAND;
 
-	tu = ktime_to_timespec(rem);
-
-	if (rmtp && copy_to_user(rmtp, &tu, sizeof(tu)))
-		return -EFAULT;
+	if (rmtp) {
+		rem = ktime_sub(t.timer.expires, t.timer.base->get_time());
+		if (rem.tv64 <= 0)
+			return 0;
+		tu = ktime_to_timespec(rem);
+		if (copy_to_user(rmtp, &tu, sizeof(tu)))
+			return -EFAULT;
+	}
 
 	restart = &current_thread_info()->restart_block;
 	restart->fn = nanosleep_restart;
-	restart->arg0 = timer.expires.tv64 & 0xFFFFFFFF;
-	restart->arg1 = timer.expires.tv64 >> 32;
+	restart->arg0 = t.timer.expires.tv64 & 0xFFFFFFFF;
+	restart->arg1 = t.timer.expires.tv64 >> 32;
 	restart->arg2 = (unsigned long) rmtp;
-	restart->arg3 = (unsigned long) timer.base->index;
+	restart->arg3 = (unsigned long) t.timer.base->index;
 
 	return -ERESTART_RESTARTBLOCK;
 }
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 6edfcef..ac766ad 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -271,6 +271,7 @@
 	struct irqaction **p;
 	unsigned long flags;
 
+	WARN_ON(in_interrupt());
 	if (irq >= NR_IRQS)
 		return;
 
diff --git a/kernel/itimer.c b/kernel/itimer.c
index 680e6b7..204ed79 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -128,16 +128,16 @@
 /*
  * The timer is automagically restarted, when interval != 0
  */
-int it_real_fn(void *data)
+int it_real_fn(struct hrtimer *timer)
 {
-	struct task_struct *tsk = (struct task_struct *) data;
+	struct signal_struct *sig =
+	    container_of(timer, struct signal_struct, real_timer);
 
-	send_group_sig_info(SIGALRM, SEND_SIG_PRIV, tsk);
+	send_group_sig_info(SIGALRM, SEND_SIG_PRIV, sig->tsk);
 
-	if (tsk->signal->it_real_incr.tv64 != 0) {
-		hrtimer_forward(&tsk->signal->real_timer,
-			       tsk->signal->it_real_incr);
-
+	if (sig->it_real_incr.tv64 != 0) {
+		hrtimer_forward(timer, timer->base->softirq_time,
+				sig->it_real_incr);
 		return HRTIMER_RESTART;
 	}
 	return HRTIMER_NORESTART;
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 51a8920..20a997c 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -170,7 +170,7 @@
 	sa.sa.sa_handler = SIG_IGN;
 	sa.sa.sa_flags = 0;
 	siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
-	do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
+	do_sigaction(SIGCHLD, &sa, NULL);
 	allow_signal(SIGCHLD);
 
 	pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD);
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 1fb9f75..1156eb0 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -323,10 +323,10 @@
 }
 
 /*
- * This function is called from exit_thread or flush_thread when task tk's
- * stack is being recycled so that we can recycle any function-return probe
- * instances associated with this task. These left over instances represent
- * probed functions that have been called but will never return.
+ * This function is called from finish_task_switch when task tk becomes dead,
+ * so that we can recycle any function-return probe instances associated
+ * with this task. These left over instances represent probed functions
+ * that have been called but will never return.
  */
 void __kprobes kprobe_flush_task(struct task_struct *tk)
 {
@@ -336,7 +336,7 @@
 	unsigned long flags = 0;
 
 	spin_lock_irqsave(&kretprobe_lock, flags);
-        head = kretprobe_inst_table_head(current);
+        head = kretprobe_inst_table_head(tk);
         hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
                 if (ri->task == tk)
                         recycle_rp_inst(ri);
diff --git a/kernel/module.c b/kernel/module.c
index ddfe45a..d24deb0 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -64,26 +64,17 @@
 static DEFINE_MUTEX(module_mutex);
 static LIST_HEAD(modules);
 
-static DEFINE_MUTEX(notify_mutex);
-static struct notifier_block * module_notify_list;
+static BLOCKING_NOTIFIER_HEAD(module_notify_list);
 
 int register_module_notifier(struct notifier_block * nb)
 {
-	int err;
-	mutex_lock(&notify_mutex);
-	err = notifier_chain_register(&module_notify_list, nb);
-	mutex_unlock(&notify_mutex);
-	return err;
+	return blocking_notifier_chain_register(&module_notify_list, nb);
 }
 EXPORT_SYMBOL(register_module_notifier);
 
 int unregister_module_notifier(struct notifier_block * nb)
 {
-	int err;
-	mutex_lock(&notify_mutex);
-	err = notifier_chain_unregister(&module_notify_list, nb);
-	mutex_unlock(&notify_mutex);
-	return err;
+	return blocking_notifier_chain_unregister(&module_notify_list, nb);
 }
 EXPORT_SYMBOL(unregister_module_notifier);
 
@@ -136,7 +127,7 @@
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
 #else
-#define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL)
+#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
 #endif
 
 /* lookup symbol in given range of kernel_symbols */
@@ -1263,6 +1254,7 @@
 		|| strcmp(license, "GPL v2") == 0
 		|| strcmp(license, "GPL and additional rights") == 0
 		|| strcmp(license, "Dual BSD/GPL") == 0
+		|| strcmp(license, "Dual MIT/GPL") == 0
 		|| strcmp(license, "Dual MPL/GPL") == 0);
 }
 
@@ -1816,9 +1808,8 @@
 	/* Drop lock so they can recurse */
 	mutex_unlock(&module_mutex);
 
-	mutex_lock(&notify_mutex);
-	notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod);
-	mutex_unlock(&notify_mutex);
+	blocking_notifier_call_chain(&module_notify_list,
+			MODULE_STATE_COMING, mod);
 
 	/* Start the module */
 	if (mod->init != NULL)
diff --git a/kernel/panic.c b/kernel/panic.c
index acd95ad..f895c7c 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -29,7 +29,7 @@
 int panic_timeout;
 EXPORT_SYMBOL(panic_timeout);
 
-struct notifier_block *panic_notifier_list;
+ATOMIC_NOTIFIER_HEAD(panic_notifier_list);
 
 EXPORT_SYMBOL(panic_notifier_list);
 
@@ -97,7 +97,7 @@
 	smp_send_stop();
 #endif
 
-	notifier_call_chain(&panic_notifier_list, 0, buf);
+	atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
 
 	if (!panic_blink)
 		panic_blink = no_blink;
diff --git a/kernel/params.c b/kernel/params.c
index 9de637a..af43ecd 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -31,7 +31,7 @@
 #define DEBUGP(fmt, a...)
 #endif
 
-static inline int dash2underscore(char c)
+static inline char dash2underscore(char c)
 {
 	if (c == '-')
 		return '_';
diff --git a/kernel/pid.c b/kernel/pid.c
index 1acc072..eeb836b 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -28,8 +28,9 @@
 #include <linux/hash.h>
 
 #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift)
-static struct hlist_head *pid_hash[PIDTYPE_MAX];
+static struct hlist_head *pid_hash;
 static int pidhash_shift;
+static kmem_cache_t *pid_cachep;
 
 int pid_max = PID_MAX_DEFAULT;
 int last_pid;
@@ -60,9 +61,22 @@
 static pidmap_t pidmap_array[PIDMAP_ENTRIES] =
 	 { [ 0 ... PIDMAP_ENTRIES-1 ] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } };
 
+/*
+ * Note: disable interrupts while the pidmap_lock is held as an
+ * interrupt might come in and do read_lock(&tasklist_lock).
+ *
+ * If we don't disable interrupts there is a nasty deadlock between
+ * detach_pid()->free_pid() and another cpu that does
+ * spin_lock(&pidmap_lock) followed by an interrupt routine that does
+ * read_lock(&tasklist_lock);
+ *
+ * After we clean up the tasklist_lock and know there are no
+ * irq handlers that take it we can leave the interrupts enabled.
+ * For now it is easier to be safe than to prove it can't happen.
+ */
 static  __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock);
 
-fastcall void free_pidmap(int pid)
+static fastcall void free_pidmap(int pid)
 {
 	pidmap_t *map = pidmap_array + pid / BITS_PER_PAGE;
 	int offset = pid & BITS_PER_PAGE_MASK;
@@ -71,7 +85,7 @@
 	atomic_inc(&map->nr_free);
 }
 
-int alloc_pidmap(void)
+static int alloc_pidmap(void)
 {
 	int i, offset, max_scan, pid, last = last_pid;
 	pidmap_t *map;
@@ -89,12 +103,12 @@
 			 * Free the page if someone raced with us
 			 * installing it:
 			 */
-			spin_lock(&pidmap_lock);
+			spin_lock_irq(&pidmap_lock);
 			if (map->page)
 				free_page(page);
 			else
 				map->page = (void *)page;
-			spin_unlock(&pidmap_lock);
+			spin_unlock_irq(&pidmap_lock);
 			if (unlikely(!map->page))
 				break;
 		}
@@ -131,13 +145,73 @@
 	return -1;
 }
 
-struct pid * fastcall find_pid(enum pid_type type, int nr)
+fastcall void put_pid(struct pid *pid)
+{
+	if (!pid)
+		return;
+	if ((atomic_read(&pid->count) == 1) ||
+	     atomic_dec_and_test(&pid->count))
+		kmem_cache_free(pid_cachep, pid);
+}
+
+static void delayed_put_pid(struct rcu_head *rhp)
+{
+	struct pid *pid = container_of(rhp, struct pid, rcu);
+	put_pid(pid);
+}
+
+fastcall void free_pid(struct pid *pid)
+{
+	/* We can be called with write_lock_irq(&tasklist_lock) held */
+	unsigned long flags;
+
+	spin_lock_irqsave(&pidmap_lock, flags);
+	hlist_del_rcu(&pid->pid_chain);
+	spin_unlock_irqrestore(&pidmap_lock, flags);
+
+	free_pidmap(pid->nr);
+	call_rcu(&pid->rcu, delayed_put_pid);
+}
+
+struct pid *alloc_pid(void)
+{
+	struct pid *pid;
+	enum pid_type type;
+	int nr = -1;
+
+	pid = kmem_cache_alloc(pid_cachep, GFP_KERNEL);
+	if (!pid)
+		goto out;
+
+	nr = alloc_pidmap();
+	if (nr < 0)
+		goto out_free;
+
+	atomic_set(&pid->count, 1);
+	pid->nr = nr;
+	for (type = 0; type < PIDTYPE_MAX; ++type)
+		INIT_HLIST_HEAD(&pid->tasks[type]);
+
+	spin_lock_irq(&pidmap_lock);
+	hlist_add_head_rcu(&pid->pid_chain, &pid_hash[pid_hashfn(pid->nr)]);
+	spin_unlock_irq(&pidmap_lock);
+
+out:
+	return pid;
+
+out_free:
+	kmem_cache_free(pid_cachep, pid);
+	pid = NULL;
+	goto out;
+}
+
+struct pid * fastcall find_pid(int nr)
 {
 	struct hlist_node *elem;
 	struct pid *pid;
 
 	hlist_for_each_entry_rcu(pid, elem,
-			&pid_hash[type][pid_hashfn(nr)], pid_chain) {
+			&pid_hash[pid_hashfn(nr)], pid_chain) {
 		if (pid->nr == nr)
 			return pid;
 	}
@@ -146,105 +220,80 @@
 
 int fastcall attach_pid(task_t *task, enum pid_type type, int nr)
 {
-	struct pid *pid, *task_pid;
+	struct pid_link *link;
+	struct pid *pid;
 
-	task_pid = &task->pids[type];
-	pid = find_pid(type, nr);
-	task_pid->nr = nr;
-	if (pid == NULL) {
-		INIT_LIST_HEAD(&task_pid->pid_list);
-		hlist_add_head_rcu(&task_pid->pid_chain,
-				   &pid_hash[type][pid_hashfn(nr)]);
-	} else {
-		INIT_HLIST_NODE(&task_pid->pid_chain);
-		list_add_tail_rcu(&task_pid->pid_list, &pid->pid_list);
-	}
+	WARN_ON(!task->pid); /* to be removed soon */
+	WARN_ON(!nr); /* to be removed soon */
+
+	link = &task->pids[type];
+	link->pid = pid = find_pid(nr);
+	hlist_add_head_rcu(&link->node, &pid->tasks[type]);
 
 	return 0;
 }
 
-static fastcall int __detach_pid(task_t *task, enum pid_type type)
-{
-	struct pid *pid, *pid_next;
-	int nr = 0;
-
-	pid = &task->pids[type];
-	if (!hlist_unhashed(&pid->pid_chain)) {
-
-		if (list_empty(&pid->pid_list)) {
-			nr = pid->nr;
-			hlist_del_rcu(&pid->pid_chain);
-		} else {
-			pid_next = list_entry(pid->pid_list.next,
-						struct pid, pid_list);
-			/* insert next pid from pid_list to hash */
-			hlist_replace_rcu(&pid->pid_chain,
-					  &pid_next->pid_chain);
-		}
-	}
-
-	list_del_rcu(&pid->pid_list);
-	pid->nr = 0;
-
-	return nr;
-}
-
 void fastcall detach_pid(task_t *task, enum pid_type type)
 {
-	int tmp, nr;
+	struct pid_link *link;
+	struct pid *pid;
+	int tmp;
 
-	nr = __detach_pid(task, type);
-	if (!nr)
-		return;
+	link = &task->pids[type];
+	pid = link->pid;
+
+	hlist_del_rcu(&link->node);
+	link->pid = NULL;
 
 	for (tmp = PIDTYPE_MAX; --tmp >= 0; )
-		if (tmp != type && find_pid(tmp, nr))
+		if (!hlist_empty(&pid->tasks[tmp]))
 			return;
 
-	free_pidmap(nr);
+	free_pid(pid);
 }
 
+struct task_struct * fastcall pid_task(struct pid *pid, enum pid_type type)
+{
+	struct task_struct *result = NULL;
+	if (pid) {
+		struct hlist_node *first;
+		first = rcu_dereference(pid->tasks[type].first);
+		if (first)
+			result = hlist_entry(first, struct task_struct, pids[(type)].node);
+	}
+	return result;
+}
+
+/*
+ * Must be called under rcu_read_lock() or with tasklist_lock read-held.
+ */
 task_t *find_task_by_pid_type(int type, int nr)
 {
-	struct pid *pid;
-
-	pid = find_pid(type, nr);
-	if (!pid)
-		return NULL;
-
-	return pid_task(&pid->pid_list, type);
+	return pid_task(find_pid(nr), type);
 }
 
 EXPORT_SYMBOL(find_task_by_pid_type);
 
-/*
- * This function switches the PIDs if a non-leader thread calls
- * sys_execve() - this must be done without releasing the PID.
- * (which a detach_pid() would eventually do.)
- */
-void switch_exec_pids(task_t *leader, task_t *thread)
+struct task_struct *fastcall get_pid_task(struct pid *pid, enum pid_type type)
 {
-	__detach_pid(leader, PIDTYPE_PID);
-	__detach_pid(leader, PIDTYPE_TGID);
-	__detach_pid(leader, PIDTYPE_PGID);
-	__detach_pid(leader, PIDTYPE_SID);
+	struct task_struct *result;
+	rcu_read_lock();
+	result = pid_task(pid, type);
+	if (result)
+		get_task_struct(result);
+	rcu_read_unlock();
+	return result;
+}
 
-	__detach_pid(thread, PIDTYPE_PID);
-	__detach_pid(thread, PIDTYPE_TGID);
+struct pid *find_get_pid(pid_t nr)
+{
+	struct pid *pid;
 
-	leader->pid = leader->tgid = thread->pid;
-	thread->pid = thread->tgid;
+	rcu_read_lock();
+	pid = get_pid(find_pid(nr));
+	rcu_read_unlock();
 
-	attach_pid(thread, PIDTYPE_PID, thread->pid);
-	attach_pid(thread, PIDTYPE_TGID, thread->tgid);
-	attach_pid(thread, PIDTYPE_PGID, thread->signal->pgrp);
-	attach_pid(thread, PIDTYPE_SID, thread->signal->session);
-	list_add_tail(&thread->tasks, &init_task.tasks);
-
-	attach_pid(leader, PIDTYPE_PID, leader->pid);
-	attach_pid(leader, PIDTYPE_TGID, leader->tgid);
-	attach_pid(leader, PIDTYPE_PGID, leader->signal->pgrp);
-	attach_pid(leader, PIDTYPE_SID, leader->signal->session);
+	return pid;
 }
 
 /*
@@ -254,7 +303,7 @@
  */
 void __init pidhash_init(void)
 {
-	int i, j, pidhash_size;
+	int i, pidhash_size;
 	unsigned long megabytes = nr_kernel_pages >> (20 - PAGE_SHIFT);
 
 	pidhash_shift = max(4, fls(megabytes * 4));
@@ -263,30 +312,23 @@
 
 	printk("PID hash table entries: %d (order: %d, %Zd bytes)\n",
 		pidhash_size, pidhash_shift,
-		PIDTYPE_MAX * pidhash_size * sizeof(struct hlist_head));
+		pidhash_size * sizeof(struct hlist_head));
 
-	for (i = 0; i < PIDTYPE_MAX; i++) {
-		pid_hash[i] = alloc_bootmem(pidhash_size *
-					sizeof(*(pid_hash[i])));
-		if (!pid_hash[i])
-			panic("Could not alloc pidhash!\n");
-		for (j = 0; j < pidhash_size; j++)
-			INIT_HLIST_HEAD(&pid_hash[i][j]);
-	}
+	pid_hash = alloc_bootmem(pidhash_size *	sizeof(*(pid_hash)));
+	if (!pid_hash)
+		panic("Could not alloc pidhash!\n");
+	for (i = 0; i < pidhash_size; i++)
+		INIT_HLIST_HEAD(&pid_hash[i]);
 }
 
 void __init pidmap_init(void)
 {
-	int i;
-
 	pidmap_array->page = (void *)get_zeroed_page(GFP_KERNEL);
+	/* Reserve PID 0. We never call free_pidmap(0) */
 	set_bit(0, pidmap_array->page);
 	atomic_dec(&pidmap_array->nr_free);
 
-	/*
-	 * Allocate PID 0, and hash it via all PID types:
-	 */
-
-	for (i = 0; i < PIDTYPE_MAX; i++)
-		attach_pid(current, i, 0);
+	pid_cachep = kmem_cache_create("pid", sizeof(struct pid),
+					__alignof__(struct pid),
+					SLAB_PANIC, NULL, NULL);
 }
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 9944379..ac6dc87 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -145,7 +145,7 @@
 			    struct itimerspec *, struct itimerspec *);
 static int common_timer_del(struct k_itimer *timer);
 
-static int posix_timer_fn(void *data);
+static int posix_timer_fn(struct hrtimer *data);
 
 static struct k_itimer *lock_timer(timer_t timer_id, unsigned long *flags);
 
@@ -251,15 +251,18 @@
 
 static void schedule_next_timer(struct k_itimer *timr)
 {
+	struct hrtimer *timer = &timr->it.real.timer;
+
 	if (timr->it.real.interval.tv64 == 0)
 		return;
 
-	timr->it_overrun += hrtimer_forward(&timr->it.real.timer,
+	timr->it_overrun += hrtimer_forward(timer, timer->base->get_time(),
 					    timr->it.real.interval);
+
 	timr->it_overrun_last = timr->it_overrun;
 	timr->it_overrun = -1;
 	++timr->it_requeue_pending;
-	hrtimer_restart(&timr->it.real.timer);
+	hrtimer_restart(timer);
 }
 
 /*
@@ -331,13 +334,14 @@
 
  * This code is for CLOCK_REALTIME* and CLOCK_MONOTONIC* timers.
  */
-static int posix_timer_fn(void *data)
+static int posix_timer_fn(struct hrtimer *timer)
 {
-	struct k_itimer *timr = data;
+	struct k_itimer *timr;
 	unsigned long flags;
 	int si_private = 0;
 	int ret = HRTIMER_NORESTART;
 
+	timr = container_of(timer, struct k_itimer, it.real.timer);
 	spin_lock_irqsave(&timr->it_lock, flags);
 
 	if (timr->it.real.interval.tv64 != 0)
@@ -351,7 +355,8 @@
 		 */
 		if (timr->it.real.interval.tv64 != 0) {
 			timr->it_overrun +=
-				hrtimer_forward(&timr->it.real.timer,
+				hrtimer_forward(timer,
+						timer->base->softirq_time,
 						timr->it.real.interval);
 			ret = HRTIMER_RESTART;
 			++timr->it_requeue_pending;
@@ -603,38 +608,41 @@
 static void
 common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
 {
-	ktime_t remaining;
+	ktime_t now, remaining, iv;
 	struct hrtimer *timer = &timr->it.real.timer;
 
 	memset(cur_setting, 0, sizeof(struct itimerspec));
-	remaining = hrtimer_get_remaining(timer);
 
-	/* Time left ? or timer pending */
-	if (remaining.tv64 > 0 || hrtimer_active(timer))
-		goto calci;
+	iv = timr->it.real.interval;
+
 	/* interval timer ? */
-	if (timr->it.real.interval.tv64 == 0)
+	if (iv.tv64)
+		cur_setting->it_interval = ktime_to_timespec(iv);
+	else if (!hrtimer_active(timer) &&
+		 (timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
 		return;
+
+	now = timer->base->get_time();
+
 	/*
-	 * When a requeue is pending or this is a SIGEV_NONE timer
-	 * move the expiry time forward by intervals, so expiry is >
-	 * now.
+	 * When a requeue is pending or this is a SIGEV_NONE
+	 * timer move the expiry time forward by intervals, so
+	 * expiry is > now.
 	 */
-	if (timr->it_requeue_pending & REQUEUE_PENDING ||
-	    (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE) {
-		timr->it_overrun +=
-			hrtimer_forward(timer, timr->it.real.interval);
-		remaining = hrtimer_get_remaining(timer);
-	}
- calci:
-	/* interval timer ? */
-	if (timr->it.real.interval.tv64 != 0)
-		cur_setting->it_interval =
-			ktime_to_timespec(timr->it.real.interval);
+	if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING ||
+	    (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE))
+		timr->it_overrun += hrtimer_forward(timer, now, iv);
+
+	remaining = ktime_sub(timer->expires, now);
 	/* Return 0 only, when the timer is expired and not pending */
-	if (remaining.tv64 <= 0)
-		cur_setting->it_value.tv_nsec = 1;
-	else
+	if (remaining.tv64 <= 0) {
+		/*
+		 * A single shot SIGEV_NONE timer must return 0, when
+		 * it is expired !
+		 */
+		if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
+			cur_setting->it_value.tv_nsec = 1;
+	} else
 		cur_setting->it_value = ktime_to_timespec(remaining);
 }
 
@@ -717,7 +725,6 @@
 
 	mode = flags & TIMER_ABSTIME ? HRTIMER_ABS : HRTIMER_REL;
 	hrtimer_init(&timr->it.real.timer, timr->it_clock, mode);
-	timr->it.real.timer.data = timr;
 	timr->it.real.timer.function = posix_timer_fn;
 
 	timer->expires = timespec_to_ktime(new_setting->it_value);
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 8ac7c35f..b2a5f67 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -26,8 +26,7 @@
 	    (p->flags & PF_NOFREEZE) ||
 	    (p->exit_state == EXIT_ZOMBIE) ||
 	    (p->exit_state == EXIT_DEAD) ||
-	    (p->state == TASK_STOPPED) ||
-	    (p->state == TASK_TRACED))
+	    (p->state == TASK_STOPPED))
 		return 0;
 	return 1;
 }
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 9177f3f..044b8e0 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -454,10 +454,11 @@
 			nr_pages++;
 		}
 	} while (ret > 0);
-	if (!error)
+	if (!error) {
 		printk("\b\b\b\bdone\n");
-	if (!snapshot_image_loaded(snapshot))
-		error = -ENODATA;
+		if (!snapshot_image_loaded(snapshot))
+			error = -ENODATA;
+	}
 	return error;
 }
 
diff --git a/kernel/profile.c b/kernel/profile.c
index ad81f79..5a730fd 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -87,72 +87,52 @@
  
 #ifdef CONFIG_PROFILING
  
-static DECLARE_RWSEM(profile_rwsem);
-static DEFINE_RWLOCK(handoff_lock);
-static struct notifier_block * task_exit_notifier;
-static struct notifier_block * task_free_notifier;
-static struct notifier_block * munmap_notifier;
+static BLOCKING_NOTIFIER_HEAD(task_exit_notifier);
+static ATOMIC_NOTIFIER_HEAD(task_free_notifier);
+static BLOCKING_NOTIFIER_HEAD(munmap_notifier);
  
 void profile_task_exit(struct task_struct * task)
 {
-	down_read(&profile_rwsem);
-	notifier_call_chain(&task_exit_notifier, 0, task);
-	up_read(&profile_rwsem);
+	blocking_notifier_call_chain(&task_exit_notifier, 0, task);
 }
  
 int profile_handoff_task(struct task_struct * task)
 {
 	int ret;
-	read_lock(&handoff_lock);
-	ret = notifier_call_chain(&task_free_notifier, 0, task);
-	read_unlock(&handoff_lock);
+	ret = atomic_notifier_call_chain(&task_free_notifier, 0, task);
 	return (ret == NOTIFY_OK) ? 1 : 0;
 }
 
 void profile_munmap(unsigned long addr)
 {
-	down_read(&profile_rwsem);
-	notifier_call_chain(&munmap_notifier, 0, (void *)addr);
-	up_read(&profile_rwsem);
+	blocking_notifier_call_chain(&munmap_notifier, 0, (void *)addr);
 }
 
 int task_handoff_register(struct notifier_block * n)
 {
-	int err = -EINVAL;
-
-	write_lock(&handoff_lock);
-	err = notifier_chain_register(&task_free_notifier, n);
-	write_unlock(&handoff_lock);
-	return err;
+	return atomic_notifier_chain_register(&task_free_notifier, n);
 }
 
 int task_handoff_unregister(struct notifier_block * n)
 {
-	int err = -EINVAL;
-
-	write_lock(&handoff_lock);
-	err = notifier_chain_unregister(&task_free_notifier, n);
-	write_unlock(&handoff_lock);
-	return err;
+	return atomic_notifier_chain_unregister(&task_free_notifier, n);
 }
 
 int profile_event_register(enum profile_type type, struct notifier_block * n)
 {
 	int err = -EINVAL;
  
-	down_write(&profile_rwsem);
- 
 	switch (type) {
 		case PROFILE_TASK_EXIT:
-			err = notifier_chain_register(&task_exit_notifier, n);
+			err = blocking_notifier_chain_register(
+					&task_exit_notifier, n);
 			break;
 		case PROFILE_MUNMAP:
-			err = notifier_chain_register(&munmap_notifier, n);
+			err = blocking_notifier_chain_register(
+					&munmap_notifier, n);
 			break;
 	}
  
-	up_write(&profile_rwsem);
- 
 	return err;
 }
 
@@ -161,18 +141,17 @@
 {
 	int err = -EINVAL;
  
-	down_write(&profile_rwsem);
- 
 	switch (type) {
 		case PROFILE_TASK_EXIT:
-			err = notifier_chain_unregister(&task_exit_notifier, n);
+			err = blocking_notifier_chain_unregister(
+					&task_exit_notifier, n);
 			break;
 		case PROFILE_MUNMAP:
-			err = notifier_chain_unregister(&munmap_notifier, n);
+			err = blocking_notifier_chain_unregister(
+					&munmap_notifier, n);
 			break;
 	}
 
-	up_write(&profile_rwsem);
 	return err;
 }
 
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index d95a72c..86a7f6c 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -35,9 +35,9 @@
 	if (child->parent == new_parent)
 		return;
 	list_add(&child->ptrace_list, &child->parent->ptrace_children);
-	REMOVE_LINKS(child);
+	remove_parent(child);
 	child->parent = new_parent;
-	SET_LINKS(child);
+	add_parent(child);
 }
  
 /*
@@ -77,9 +77,9 @@
 	child->ptrace = 0;
 	if (!list_empty(&child->ptrace_list)) {
 		list_del_init(&child->ptrace_list);
-		REMOVE_LINKS(child);
+		remove_parent(child);
 		child->parent = child->real_parent;
-		SET_LINKS(child);
+		add_parent(child);
 	}
 
 	ptrace_untrace(child);
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index b4b362b..8154e75 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -301,7 +301,7 @@
 	long pipesummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
 	long batchsummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
 
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
 			pipesummary[i] += per_cpu(rcu_torture_count, cpu)[i];
 			batchsummary[i] += per_cpu(rcu_torture_batch, cpu)[i];
@@ -535,7 +535,7 @@
 	atomic_set(&n_rcu_torture_error, 0);
 	for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
 		atomic_set(&rcu_torture_wcount[i], 0);
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
 			per_cpu(rcu_torture_count, cpu)[i] = 0;
 			per_cpu(rcu_torture_batch, cpu)[i] = 0;
diff --git a/kernel/sched.c b/kernel/sched.c
index 7ffaabd..dd153d6 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -49,6 +49,7 @@
 #include <linux/syscalls.h>
 #include <linux/times.h>
 #include <linux/acct.h>
+#include <linux/kprobes.h>
 #include <asm/tlb.h>
 
 #include <asm/unistd.h>
@@ -144,7 +145,8 @@
 	(v1) * (v2_max) / (v1_max)
 
 #define DELTA(p) \
-	(SCALE(TASK_NICE(p), 40, MAX_BONUS) + INTERACTIVE_DELTA)
+	(SCALE(TASK_NICE(p) + 20, 40, MAX_BONUS) - 20 * MAX_BONUS / 40 + \
+		INTERACTIVE_DELTA)
 
 #define TASK_INTERACTIVE(p) \
 	((p)->prio <= (p)->static_prio - DELTA(p))
@@ -665,9 +667,13 @@
 /*
  * __activate_task - move a task to the runqueue.
  */
-static inline void __activate_task(task_t *p, runqueue_t *rq)
+static void __activate_task(task_t *p, runqueue_t *rq)
 {
-	enqueue_task(p, rq->active);
+	prio_array_t *target = rq->active;
+
+	if (batch_task(p))
+		target = rq->expired;
+	enqueue_task(p, target);
 	rq->nr_running++;
 }
 
@@ -686,7 +692,7 @@
 	unsigned long long __sleep_time = now - p->timestamp;
 	unsigned long sleep_time;
 
-	if (unlikely(p->policy == SCHED_BATCH))
+	if (batch_task(p))
 		sleep_time = 0;
 	else {
 		if (__sleep_time > NS_MAX_SLEEP_AVG)
@@ -698,21 +704,25 @@
 	if (likely(sleep_time > 0)) {
 		/*
 		 * User tasks that sleep a long time are categorised as
-		 * idle and will get just interactive status to stay active &
-		 * prevent them suddenly becoming cpu hogs and starving
-		 * other processes.
+		 * idle. They will only have their sleep_avg increased to a
+		 * level that makes them just interactive priority to stay
+		 * active yet prevent them suddenly becoming cpu hogs and
+		 * starving other processes.
 		 */
-		if (p->mm && p->activated != -1 &&
-			sleep_time > INTERACTIVE_SLEEP(p)) {
-				p->sleep_avg = JIFFIES_TO_NS(MAX_SLEEP_AVG -
-						DEF_TIMESLICE);
+		if (p->mm && sleep_time > INTERACTIVE_SLEEP(p)) {
+				unsigned long ceiling;
+
+				ceiling = JIFFIES_TO_NS(MAX_SLEEP_AVG -
+					DEF_TIMESLICE);
+				if (p->sleep_avg < ceiling)
+					p->sleep_avg = ceiling;
 		} else {
 			/*
 			 * Tasks waking from uninterruptible sleep are
 			 * limited in their sleep_avg rise as they
 			 * are likely to be waiting on I/O
 			 */
-			if (p->activated == -1 && p->mm) {
+			if (p->sleep_type == SLEEP_NONINTERACTIVE && p->mm) {
 				if (p->sleep_avg >= INTERACTIVE_SLEEP(p))
 					sleep_time = 0;
 				else if (p->sleep_avg + sleep_time >=
@@ -767,7 +777,7 @@
 	 * This checks to make sure it's not an uninterruptible task
 	 * that is now waking up.
 	 */
-	if (!p->activated) {
+	if (p->sleep_type == SLEEP_NORMAL) {
 		/*
 		 * Tasks which were woken up by interrupts (ie. hw events)
 		 * are most likely of interactive nature. So we give them
@@ -776,13 +786,13 @@
 		 * on a CPU, first time around:
 		 */
 		if (in_interrupt())
-			p->activated = 2;
+			p->sleep_type = SLEEP_INTERRUPTED;
 		else {
 			/*
 			 * Normal first-time wakeups get a credit too for
 			 * on-runqueue time, but it will be weighted down:
 			 */
-			p->activated = 1;
+			p->sleep_type = SLEEP_INTERACTIVE;
 		}
 	}
 	p->timestamp = now;
@@ -1270,19 +1280,19 @@
 		 * Tasks on involuntary sleep don't earn
 		 * sleep_avg beyond just interactive state.
 		 */
-		p->activated = -1;
-	}
+		p->sleep_type = SLEEP_NONINTERACTIVE;
+	} else
 
 	/*
 	 * Tasks that have marked their sleep as noninteractive get
-	 * woken up without updating their sleep average. (i.e. their
-	 * sleep is handled in a priority-neutral manner, no priority
-	 * boost and no penalty.)
+	 * woken up with their sleep average not weighted in an
+	 * interactive way.
 	 */
-	if (old_state & TASK_NONINTERACTIVE)
-		__activate_task(p, rq);
-	else
-		activate_task(p, rq, cpu == this_cpu);
+		if (old_state & TASK_NONINTERACTIVE)
+			p->sleep_type = SLEEP_NONINTERACTIVE;
+
+
+	activate_task(p, rq, cpu == this_cpu);
 	/*
 	 * Sync wakeups (i.e. those types of wakeups where the waker
 	 * has indicated that it will leave the CPU in short order)
@@ -1546,8 +1556,14 @@
 	finish_lock_switch(rq, prev);
 	if (mm)
 		mmdrop(mm);
-	if (unlikely(prev_task_flags & PF_DEAD))
+	if (unlikely(prev_task_flags & PF_DEAD)) {
+		/*
+		 * Remove function-return probe instances associated with this
+		 * task and put them back on the free list.
+	 	 */
+		kprobe_flush_task(prev);
 		put_task_struct(prev);
+	}
 }
 
 /**
@@ -1617,7 +1633,7 @@
 {
 	unsigned long i, sum = 0;
 
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 		sum += cpu_rq(i)->nr_uninterruptible;
 
 	/*
@@ -1634,7 +1650,7 @@
 {
 	unsigned long long i, sum = 0;
 
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 		sum += cpu_rq(i)->nr_switches;
 
 	return sum;
@@ -1644,12 +1660,27 @@
 {
 	unsigned long i, sum = 0;
 
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 		sum += atomic_read(&cpu_rq(i)->nr_iowait);
 
 	return sum;
 }
 
+unsigned long nr_active(void)
+{
+	unsigned long i, running = 0, uninterruptible = 0;
+
+	for_each_online_cpu(i) {
+		running += cpu_rq(i)->nr_running;
+		uninterruptible += cpu_rq(i)->nr_uninterruptible;
+	}
+
+	if (unlikely((long)uninterruptible < 0))
+		uninterruptible = 0;
+
+	return running + uninterruptible;
+}
+
 #ifdef CONFIG_SMP
 
 /*
@@ -2852,6 +2883,12 @@
 
 #endif
 
+static inline int interactive_sleep(enum sleep_type sleep_type)
+{
+	return (sleep_type == SLEEP_INTERACTIVE ||
+		sleep_type == SLEEP_INTERRUPTED);
+}
+
 /*
  * schedule() is the main scheduler function.
  */
@@ -2871,13 +2908,11 @@
 	 * schedule() atomically, we ignore that path for now.
 	 * Otherwise, whine if we are scheduling when we should not be.
 	 */
-	if (likely(!current->exit_state)) {
-		if (unlikely(in_atomic())) {
-			printk(KERN_ERR "BUG: scheduling while atomic: "
-				"%s/0x%08x/%d\n",
-				current->comm, preempt_count(), current->pid);
-			dump_stack();
-		}
+	if (unlikely(in_atomic() && !current->exit_state)) {
+		printk(KERN_ERR "BUG: scheduling while atomic: "
+			"%s/0x%08x/%d\n",
+			current->comm, preempt_count(), current->pid);
+		dump_stack();
 	}
 	profile_hit(SCHED_PROFILING, __builtin_return_address(0));
 
@@ -2977,12 +3012,12 @@
 	queue = array->queue + idx;
 	next = list_entry(queue->next, task_t, run_list);
 
-	if (!rt_task(next) && next->activated > 0) {
+	if (!rt_task(next) && interactive_sleep(next->sleep_type)) {
 		unsigned long long delta = now - next->timestamp;
 		if (unlikely((long long)(now - next->timestamp) < 0))
 			delta = 0;
 
-		if (next->activated == 1)
+		if (next->sleep_type == SLEEP_INTERACTIVE)
 			delta = delta * (ON_RUNQUEUE_WEIGHT * 128 / 100) / 128;
 
 		array = next->array;
@@ -2992,10 +3027,9 @@
 			dequeue_task(next, array);
 			next->prio = new_prio;
 			enqueue_task(next, array);
-		} else
-			requeue_task(next, array);
+		}
 	}
-	next->activated = 0;
+	next->sleep_type = SLEEP_NORMAL;
 switch_tasks:
 	if (next == rq->idle)
 		schedstat_inc(rq, sched_goidle);
@@ -5568,11 +5602,31 @@
 }
 #endif
 
+#ifdef CONFIG_SCHED_MC
+static DEFINE_PER_CPU(struct sched_domain, core_domains);
+static struct sched_group sched_group_core[NR_CPUS];
+#endif
+
+#if defined(CONFIG_SCHED_MC) && defined(CONFIG_SCHED_SMT)
+static int cpu_to_core_group(int cpu)
+{
+	return first_cpu(cpu_sibling_map[cpu]);
+}
+#elif defined(CONFIG_SCHED_MC)
+static int cpu_to_core_group(int cpu)
+{
+	return cpu;
+}
+#endif
+
 static DEFINE_PER_CPU(struct sched_domain, phys_domains);
 static struct sched_group sched_group_phys[NR_CPUS];
 static int cpu_to_phys_group(int cpu)
 {
-#ifdef CONFIG_SCHED_SMT
+#if defined(CONFIG_SCHED_MC)
+	cpumask_t mask = cpu_coregroup_map(cpu);
+	return first_cpu(mask);
+#elif defined(CONFIG_SCHED_SMT)
 	return first_cpu(cpu_sibling_map[cpu]);
 #else
 	return cpu;
@@ -5595,6 +5649,32 @@
 {
 	return cpu_to_node(cpu);
 }
+static void init_numa_sched_groups_power(struct sched_group *group_head)
+{
+	struct sched_group *sg = group_head;
+	int j;
+
+	if (!sg)
+		return;
+next_sg:
+	for_each_cpu_mask(j, sg->cpumask) {
+		struct sched_domain *sd;
+
+		sd = &per_cpu(phys_domains, j);
+		if (j != first_cpu(sd->groups->cpumask)) {
+			/*
+			 * Only add "power" once for each
+			 * physical package.
+			 */
+			continue;
+		}
+
+		sg->cpu_power += sd->groups->cpu_power;
+	}
+	sg = sg->next;
+	if (sg != group_head)
+		goto next_sg;
+}
 #endif
 
 /*
@@ -5670,6 +5750,17 @@
 		sd->parent = p;
 		sd->groups = &sched_group_phys[group];
 
+#ifdef CONFIG_SCHED_MC
+		p = sd;
+		sd = &per_cpu(core_domains, i);
+		group = cpu_to_core_group(i);
+		*sd = SD_MC_INIT;
+		sd->span = cpu_coregroup_map(i);
+		cpus_and(sd->span, sd->span, *cpu_map);
+		sd->parent = p;
+		sd->groups = &sched_group_core[group];
+#endif
+
 #ifdef CONFIG_SCHED_SMT
 		p = sd;
 		sd = &per_cpu(cpu_domains, i);
@@ -5695,6 +5786,19 @@
 	}
 #endif
 
+#ifdef CONFIG_SCHED_MC
+	/* Set up multi-core groups */
+	for_each_cpu_mask(i, *cpu_map) {
+		cpumask_t this_core_map = cpu_coregroup_map(i);
+		cpus_and(this_core_map, this_core_map, *cpu_map);
+		if (i != first_cpu(this_core_map))
+			continue;
+		init_sched_build_groups(sched_group_core, this_core_map,
+					&cpu_to_core_group);
+	}
+#endif
+
+
 	/* Set up physical groups */
 	for (i = 0; i < MAX_NUMNODES; i++) {
 		cpumask_t nodemask = node_to_cpumask(i);
@@ -5791,51 +5895,38 @@
 		power = SCHED_LOAD_SCALE;
 		sd->groups->cpu_power = power;
 #endif
+#ifdef CONFIG_SCHED_MC
+		sd = &per_cpu(core_domains, i);
+		power = SCHED_LOAD_SCALE + (cpus_weight(sd->groups->cpumask)-1)
+					    * SCHED_LOAD_SCALE / 10;
+		sd->groups->cpu_power = power;
 
 		sd = &per_cpu(phys_domains, i);
+
+ 		/*
+ 		 * This has to be < 2 * SCHED_LOAD_SCALE
+ 		 * Lets keep it SCHED_LOAD_SCALE, so that
+ 		 * while calculating NUMA group's cpu_power
+ 		 * we can simply do
+ 		 *  numa_group->cpu_power += phys_group->cpu_power;
+ 		 *
+ 		 * See "only add power once for each physical pkg"
+ 		 * comment below
+ 		 */
+ 		sd->groups->cpu_power = SCHED_LOAD_SCALE;
+#else
+		sd = &per_cpu(phys_domains, i);
 		power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
 				(cpus_weight(sd->groups->cpumask)-1) / 10;
 		sd->groups->cpu_power = power;
-
-#ifdef CONFIG_NUMA
-		sd = &per_cpu(allnodes_domains, i);
-		if (sd->groups) {
-			power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
-				(cpus_weight(sd->groups->cpumask)-1) / 10;
-			sd->groups->cpu_power = power;
-		}
 #endif
 	}
 
 #ifdef CONFIG_NUMA
-	for (i = 0; i < MAX_NUMNODES; i++) {
-		struct sched_group *sg = sched_group_nodes[i];
-		int j;
+	for (i = 0; i < MAX_NUMNODES; i++)
+		init_numa_sched_groups_power(sched_group_nodes[i]);
 
-		if (sg == NULL)
-			continue;
-next_sg:
-		for_each_cpu_mask(j, sg->cpumask) {
-			struct sched_domain *sd;
-			int power;
-
-			sd = &per_cpu(phys_domains, j);
-			if (j != first_cpu(sd->groups->cpumask)) {
-				/*
-				 * Only add "power" once for each
-				 * physical package.
-				 */
-				continue;
-			}
-			power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
-				(cpus_weight(sd->groups->cpumask)-1) / 10;
-
-			sg->cpu_power += power;
-		}
-		sg = sg->next;
-		if (sg != sched_group_nodes[i])
-			goto next_sg;
-	}
+	init_numa_sched_groups_power(sched_group_allnodes);
 #endif
 
 	/* Attach the domains */
@@ -5843,6 +5934,8 @@
 		struct sched_domain *sd;
 #ifdef CONFIG_SCHED_SMT
 		sd = &per_cpu(cpu_domains, i);
+#elif defined(CONFIG_SCHED_MC)
+		sd = &per_cpu(core_domains, i);
 #else
 		sd = &per_cpu(phys_domains, i);
 #endif
@@ -6015,7 +6108,7 @@
 	runqueue_t *rq;
 	int i, j, k;
 
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		prio_array_t *array;
 
 		rq = cpu_rq(i);
diff --git a/kernel/signal.c b/kernel/signal.c
index 75f7341..92025b1 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -22,7 +22,6 @@
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/ptrace.h>
-#include <linux/posix-timers.h>
 #include <linux/signal.h>
 #include <linux/audit.h>
 #include <linux/capability.h>
@@ -147,6 +146,8 @@
 #define sig_kernel_stop(sig) \
 		(((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_STOP_MASK))
 
+#define sig_needs_tasklist(sig)	((sig) == SIGCONT)
+
 #define sig_user_defined(t, signr) \
 	(((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) &&	\
 	 ((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_IGN))
@@ -292,7 +293,7 @@
 	kmem_cache_free(sigqueue_cachep, q);
 }
 
-static void flush_sigqueue(struct sigpending *queue)
+void flush_sigqueue(struct sigpending *queue)
 {
 	struct sigqueue *q;
 
@@ -307,9 +308,7 @@
 /*
  * Flush all pending signals for a task.
  */
-
-void
-flush_signals(struct task_struct *t)
+void flush_signals(struct task_struct *t)
 {
 	unsigned long flags;
 
@@ -321,109 +320,6 @@
 }
 
 /*
- * This function expects the tasklist_lock write-locked.
- */
-void __exit_sighand(struct task_struct *tsk)
-{
-	struct sighand_struct * sighand = tsk->sighand;
-
-	/* Ok, we're done with the signal handlers */
-	tsk->sighand = NULL;
-	if (atomic_dec_and_test(&sighand->count))
-		sighand_free(sighand);
-}
-
-void exit_sighand(struct task_struct *tsk)
-{
-	write_lock_irq(&tasklist_lock);
-	rcu_read_lock();
-	if (tsk->sighand != NULL) {
-		struct sighand_struct *sighand = rcu_dereference(tsk->sighand);
-		spin_lock(&sighand->siglock);
-		__exit_sighand(tsk);
-		spin_unlock(&sighand->siglock);
-	}
-	rcu_read_unlock();
-	write_unlock_irq(&tasklist_lock);
-}
-
-/*
- * This function expects the tasklist_lock write-locked.
- */
-void __exit_signal(struct task_struct *tsk)
-{
-	struct signal_struct * sig = tsk->signal;
-	struct sighand_struct * sighand;
-
-	if (!sig)
-		BUG();
-	if (!atomic_read(&sig->count))
-		BUG();
-	rcu_read_lock();
-	sighand = rcu_dereference(tsk->sighand);
-	spin_lock(&sighand->siglock);
-	posix_cpu_timers_exit(tsk);
-	if (atomic_dec_and_test(&sig->count)) {
-		posix_cpu_timers_exit_group(tsk);
-		tsk->signal = NULL;
-		__exit_sighand(tsk);
-		spin_unlock(&sighand->siglock);
-		flush_sigqueue(&sig->shared_pending);
-	} else {
-		/*
-		 * If there is any task waiting for the group exit
-		 * then notify it:
-		 */
-		if (sig->group_exit_task && atomic_read(&sig->count) == sig->notify_count) {
-			wake_up_process(sig->group_exit_task);
-			sig->group_exit_task = NULL;
-		}
-		if (tsk == sig->curr_target)
-			sig->curr_target = next_thread(tsk);
-		tsk->signal = NULL;
-		/*
-		 * Accumulate here the counters for all threads but the
-		 * group leader as they die, so they can be added into
-		 * the process-wide totals when those are taken.
-		 * The group leader stays around as a zombie as long
-		 * as there are other threads.  When it gets reaped,
-		 * the exit.c code will add its counts into these totals.
-		 * We won't ever get here for the group leader, since it
-		 * will have been the last reference on the signal_struct.
-		 */
-		sig->utime = cputime_add(sig->utime, tsk->utime);
-		sig->stime = cputime_add(sig->stime, tsk->stime);
-		sig->min_flt += tsk->min_flt;
-		sig->maj_flt += tsk->maj_flt;
-		sig->nvcsw += tsk->nvcsw;
-		sig->nivcsw += tsk->nivcsw;
-		sig->sched_time += tsk->sched_time;
-		__exit_sighand(tsk);
-		spin_unlock(&sighand->siglock);
-		sig = NULL;	/* Marker for below.  */
-	}
-	rcu_read_unlock();
-	clear_tsk_thread_flag(tsk,TIF_SIGPENDING);
-	flush_sigqueue(&tsk->pending);
-	if (sig) {
-		/*
-		 * We are cleaning up the signal_struct here.
-		 */
-		exit_thread_group_keys(sig);
-		kmem_cache_free(signal_cachep, sig);
-	}
-}
-
-void exit_signal(struct task_struct *tsk)
-{
-	atomic_dec(&tsk->signal->live);
-
-	write_lock_irq(&tasklist_lock);
-	__exit_signal(tsk);
-	write_unlock_irq(&tasklist_lock);
-}
-
-/*
  * Flush all handlers for a task.
  */
 
@@ -695,9 +591,7 @@
 }
 
 /* forward decl */
-static void do_notify_parent_cldstop(struct task_struct *tsk,
-				     int to_self,
-				     int why);
+static void do_notify_parent_cldstop(struct task_struct *tsk, int why);
 
 /*
  * Handle magic process-wide effects of stop/continue signals.
@@ -747,7 +641,7 @@
 			p->signal->group_stop_count = 0;
 			p->signal->flags = SIGNAL_STOP_CONTINUED;
 			spin_unlock(&p->sighand->siglock);
-			do_notify_parent_cldstop(p, (p->ptrace & PT_PTRACED), CLD_STOPPED);
+			do_notify_parent_cldstop(p, CLD_STOPPED);
 			spin_lock(&p->sighand->siglock);
 		}
 		rm_from_queue(SIG_KERNEL_STOP_MASK, &p->signal->shared_pending);
@@ -788,7 +682,7 @@
 			p->signal->flags = SIGNAL_STOP_CONTINUED;
 			p->signal->group_exit_code = 0;
 			spin_unlock(&p->sighand->siglock);
-			do_notify_parent_cldstop(p, (p->ptrace & PT_PTRACED), CLD_CONTINUED);
+			do_notify_parent_cldstop(p, CLD_CONTINUED);
 			spin_lock(&p->sighand->siglock);
 		} else {
 			/*
@@ -1120,27 +1014,37 @@
 /*
  * Must be called under rcu_read_lock() or with tasklist_lock read-held.
  */
+struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long *flags)
+{
+	struct sighand_struct *sighand;
+
+	for (;;) {
+		sighand = rcu_dereference(tsk->sighand);
+		if (unlikely(sighand == NULL))
+			break;
+
+		spin_lock_irqsave(&sighand->siglock, *flags);
+		if (likely(sighand == tsk->sighand))
+			break;
+		spin_unlock_irqrestore(&sighand->siglock, *flags);
+	}
+
+	return sighand;
+}
+
 int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
 {
 	unsigned long flags;
-	struct sighand_struct *sp;
 	int ret;
 
-retry:
 	ret = check_kill_permission(sig, info, p);
-	if (!ret && sig && (sp = rcu_dereference(p->sighand))) {
-		spin_lock_irqsave(&sp->siglock, flags);
-		if (p->sighand != sp) {
-			spin_unlock_irqrestore(&sp->siglock, flags);
-			goto retry;
+
+	if (!ret && sig) {
+		ret = -ESRCH;
+		if (lock_task_sighand(p, &flags)) {
+			ret = __group_send_sig_info(sig, info, p);
+			unlock_task_sighand(p, &flags);
 		}
-		if ((atomic_read(&sp->count) == 0) ||
-				(atomic_read(&p->usage) == 0)) {
-			spin_unlock_irqrestore(&sp->siglock, flags);
-			return -ESRCH;
-		}
-		ret = __group_send_sig_info(sig, info, p);
-		spin_unlock_irqrestore(&sp->siglock, flags);
 	}
 
 	return ret;
@@ -1189,7 +1093,7 @@
 	struct task_struct *p;
 
 	rcu_read_lock();
-	if (unlikely(sig_kernel_stop(sig) || sig == SIGCONT)) {
+	if (unlikely(sig_needs_tasklist(sig))) {
 		read_lock(&tasklist_lock);
 		acquired_tasklist_lock = 1;
 	}
@@ -1405,12 +1309,10 @@
 	__sigqueue_free(q);
 }
 
-int
-send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
+int send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
 {
 	unsigned long flags;
 	int ret = 0;
-	struct sighand_struct *sh;
 
 	BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
 
@@ -1424,48 +1326,17 @@
 	 */
 	rcu_read_lock();
 
-	if (unlikely(p->flags & PF_EXITING)) {
+	if (!likely(lock_task_sighand(p, &flags))) {
 		ret = -1;
 		goto out_err;
 	}
 
-retry:
-	sh = rcu_dereference(p->sighand);
-
-	spin_lock_irqsave(&sh->siglock, flags);
-	if (p->sighand != sh) {
-		/* We raced with exec() in a multithreaded process... */
-		spin_unlock_irqrestore(&sh->siglock, flags);
-		goto retry;
-	}
-
-	/*
-	 * We do the check here again to handle the following scenario:
-	 *
-	 * CPU 0		CPU 1
-	 * send_sigqueue
-	 * check PF_EXITING
-	 * interrupt		exit code running
-	 *			__exit_signal
-	 *			lock sighand->siglock
-	 *			unlock sighand->siglock
-	 * lock sh->siglock
-	 * add(tsk->pending) 	flush_sigqueue(tsk->pending)
-	 *
-	 */
-
-	if (unlikely(p->flags & PF_EXITING)) {
-		ret = -1;
-		goto out;
-	}
-
 	if (unlikely(!list_empty(&q->list))) {
 		/*
 		 * If an SI_TIMER entry is already queue just increment
 		 * the overrun count.
 		 */
-		if (q->info.si_code != SI_TIMER)
-			BUG();
+		BUG_ON(q->info.si_code != SI_TIMER);
 		q->info.si_overrun++;
 		goto out;
 	}
@@ -1481,7 +1352,7 @@
 		signal_wake_up(p, sig == SIGKILL);
 
 out:
-	spin_unlock_irqrestore(&sh->siglock, flags);
+	unlock_task_sighand(p, &flags);
 out_err:
 	rcu_read_unlock();
 
@@ -1613,14 +1484,14 @@
 	spin_unlock_irqrestore(&psig->siglock, flags);
 }
 
-static void do_notify_parent_cldstop(struct task_struct *tsk, int to_self, int why)
+static void do_notify_parent_cldstop(struct task_struct *tsk, int why)
 {
 	struct siginfo info;
 	unsigned long flags;
 	struct task_struct *parent;
 	struct sighand_struct *sighand;
 
-	if (to_self)
+	if (tsk->ptrace & PT_PTRACED)
 		parent = tsk->parent;
 	else {
 		tsk = tsk->group_leader;
@@ -1689,13 +1560,14 @@
 	/* Let the debugger run.  */
 	set_current_state(TASK_TRACED);
 	spin_unlock_irq(&current->sighand->siglock);
+	try_to_freeze();
 	read_lock(&tasklist_lock);
 	if (likely(current->ptrace & PT_PTRACED) &&
 	    likely(current->parent != current->real_parent ||
 		   !(current->ptrace & PT_ATTACHED)) &&
 	    (likely(current->parent->signal != current->signal) ||
 	     !unlikely(current->signal->flags & SIGNAL_GROUP_EXIT))) {
-		do_notify_parent_cldstop(current, 1, CLD_TRAPPED);
+		do_notify_parent_cldstop(current, CLD_TRAPPED);
 		read_unlock(&tasklist_lock);
 		schedule();
 	} else {
@@ -1744,25 +1616,17 @@
 static void
 finish_stop(int stop_count)
 {
-	int to_self;
-
 	/*
 	 * If there are no other threads in the group, or if there is
 	 * a group stop in progress and we are the last to stop,
 	 * report to the parent.  When ptraced, every thread reports itself.
 	 */
-	if (stop_count < 0 || (current->ptrace & PT_PTRACED))
-		to_self = 1;
-	else if (stop_count == 0)
-		to_self = 0;
-	else
-		goto out;
+	if (stop_count == 0 || (current->ptrace & PT_PTRACED)) {
+		read_lock(&tasklist_lock);
+		do_notify_parent_cldstop(current, CLD_STOPPED);
+		read_unlock(&tasklist_lock);
+	}
 
-	read_lock(&tasklist_lock);
-	do_notify_parent_cldstop(current, to_self, CLD_STOPPED);
-	read_unlock(&tasklist_lock);
-
-out:
 	schedule();
 	/*
 	 * Now we don't run again until continued.
@@ -1776,12 +1640,10 @@
  * Returns nonzero if we've actually stopped and released the siglock.
  * Returns zero if we didn't stop and still hold the siglock.
  */
-static int
-do_signal_stop(int signr)
+static int do_signal_stop(int signr)
 {
 	struct signal_struct *sig = current->signal;
-	struct sighand_struct *sighand = current->sighand;
-	int stop_count = -1;
+	int stop_count;
 
 	if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED))
 		return 0;
@@ -1791,86 +1653,37 @@
 		 * There is a group stop in progress.  We don't need to
 		 * start another one.
 		 */
-		signr = sig->group_exit_code;
 		stop_count = --sig->group_stop_count;
-		current->exit_code = signr;
-		set_current_state(TASK_STOPPED);
-		if (stop_count == 0)
-			sig->flags = SIGNAL_STOP_STOPPED;
-		spin_unlock_irq(&sighand->siglock);
-	}
-	else if (thread_group_empty(current)) {
-		/*
-		 * Lock must be held through transition to stopped state.
-		 */
-		current->exit_code = current->signal->group_exit_code = signr;
-		set_current_state(TASK_STOPPED);
-		sig->flags = SIGNAL_STOP_STOPPED;
-		spin_unlock_irq(&sighand->siglock);
-	}
-	else {
+	} else {
 		/*
 		 * There is no group stop already in progress.
-		 * We must initiate one now, but that requires
-		 * dropping siglock to get both the tasklist lock
-		 * and siglock again in the proper order.  Note that
-		 * this allows an intervening SIGCONT to be posted.
-		 * We need to check for that and bail out if necessary.
+		 * We must initiate one now.
 		 */
 		struct task_struct *t;
 
-		spin_unlock_irq(&sighand->siglock);
+		sig->group_exit_code = signr;
 
-		/* signals can be posted during this window */
-
-		read_lock(&tasklist_lock);
-		spin_lock_irq(&sighand->siglock);
-
-		if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED)) {
+		stop_count = 0;
+		for (t = next_thread(current); t != current; t = next_thread(t))
 			/*
-			 * Another stop or continue happened while we
-			 * didn't have the lock.  We can just swallow this
-			 * signal now.  If we raced with a SIGCONT, that
-			 * should have just cleared it now.  If we raced
-			 * with another processor delivering a stop signal,
-			 * then the SIGCONT that wakes us up should clear it.
+			 * Setting state to TASK_STOPPED for a group
+			 * stop is always done with the siglock held,
+			 * so this check has no races.
 			 */
-			read_unlock(&tasklist_lock);
-			return 0;
-		}
-
-		if (sig->group_stop_count == 0) {
-			sig->group_exit_code = signr;
-			stop_count = 0;
-			for (t = next_thread(current); t != current;
-			     t = next_thread(t))
-				/*
-				 * Setting state to TASK_STOPPED for a group
-				 * stop is always done with the siglock held,
-				 * so this check has no races.
-				 */
-				if (!t->exit_state &&
-				    !(t->state & (TASK_STOPPED|TASK_TRACED))) {
-					stop_count++;
-					signal_wake_up(t, 0);
-				}
-			sig->group_stop_count = stop_count;
-		}
-		else {
-			/* A race with another thread while unlocked.  */
-			signr = sig->group_exit_code;
-			stop_count = --sig->group_stop_count;
-		}
-
-		current->exit_code = signr;
-		set_current_state(TASK_STOPPED);
-		if (stop_count == 0)
-			sig->flags = SIGNAL_STOP_STOPPED;
-
-		spin_unlock_irq(&sighand->siglock);
-		read_unlock(&tasklist_lock);
+			if (!t->exit_state &&
+			    !(t->state & (TASK_STOPPED|TASK_TRACED))) {
+				stop_count++;
+				signal_wake_up(t, 0);
+			}
+		sig->group_stop_count = stop_count;
 	}
 
+	if (stop_count == 0)
+		sig->flags = SIGNAL_STOP_STOPPED;
+	current->exit_code = sig->group_exit_code;
+	__set_current_state(TASK_STOPPED);
+
+	spin_unlock_irq(&current->sighand->siglock);
 	finish_stop(stop_count);
 	return 1;
 }
@@ -1990,7 +1803,7 @@
 			continue;
 
 		/* Init gets no signals it doesn't want.  */
-		if (current->pid == 1)
+		if (current == child_reaper)
 			continue;
 
 		if (sig_kernel_stop(signr)) {
@@ -2430,8 +2243,7 @@
 	return kill_proc_info(sig, &info, pid);
 }
 
-int
-do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
+int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
 {
 	struct k_sigaction *k;
 	sigset_t mask;
@@ -2457,6 +2269,7 @@
 	if (act) {
 		sigdelsetmask(&act->sa.sa_mask,
 			      sigmask(SIGKILL) | sigmask(SIGSTOP));
+		*k = *act;
 		/*
 		 * POSIX 3.3.1.3:
 		 *  "Setting a signal action to SIG_IGN for a signal that is
@@ -2469,19 +2282,8 @@
 		 *   be discarded, whether or not it is blocked"
 		 */
 		if (act->sa.sa_handler == SIG_IGN ||
-		    (act->sa.sa_handler == SIG_DFL &&
-		     sig_kernel_ignore(sig))) {
-			/*
-			 * This is a fairly rare case, so we only take the
-			 * tasklist_lock once we're sure we'll need it.
-			 * Now we must do this little unlock and relock
-			 * dance to maintain the lock hierarchy.
-			 */
+		   (act->sa.sa_handler == SIG_DFL && sig_kernel_ignore(sig))) {
 			struct task_struct *t = current;
-			spin_unlock_irq(&t->sighand->siglock);
-			read_lock(&tasklist_lock);
-			spin_lock_irq(&t->sighand->siglock);
-			*k = *act;
 			sigemptyset(&mask);
 			sigaddset(&mask, sig);
 			rm_from_queue_full(&mask, &t->signal->shared_pending);
@@ -2490,12 +2292,7 @@
 				recalc_sigpending_tsk(t);
 				t = next_thread(t);
 			} while (t != current);
-			spin_unlock_irq(&current->sighand->siglock);
-			read_unlock(&tasklist_lock);
-			return 0;
 		}
-
-		*k = *act;
 	}
 
 	spin_unlock_irq(&current->sighand->siglock);
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index d9b3d58..ced91e1 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -152,5 +152,5 @@
 	cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
 	register_cpu_notifier(&cpu_nfb);
 
-	notifier_chain_register(&panic_notifier_list, &panic_block);
+	atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
 }
diff --git a/kernel/sys.c b/kernel/sys.c
index 38bc73e..0b6ec0e 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -95,99 +95,304 @@
  *	and the like. 
  */
 
-static struct notifier_block *reboot_notifier_list;
-static DEFINE_RWLOCK(notifier_lock);
+static BLOCKING_NOTIFIER_HEAD(reboot_notifier_list);
 
-/**
- *	notifier_chain_register	- Add notifier to a notifier chain
- *	@list: Pointer to root list pointer
- *	@n: New entry in notifier chain
- *
- *	Adds a notifier to a notifier chain.
- *
- *	Currently always returns zero.
+/*
+ *	Notifier chain core routines.  The exported routines below
+ *	are layered on top of these, with appropriate locking added.
  */
- 
-int notifier_chain_register(struct notifier_block **list, struct notifier_block *n)
+
+static int notifier_chain_register(struct notifier_block **nl,
+		struct notifier_block *n)
 {
-	write_lock(&notifier_lock);
-	while(*list)
-	{
-		if(n->priority > (*list)->priority)
+	while ((*nl) != NULL) {
+		if (n->priority > (*nl)->priority)
 			break;
-		list= &((*list)->next);
+		nl = &((*nl)->next);
 	}
-	n->next = *list;
-	*list=n;
-	write_unlock(&notifier_lock);
+	n->next = *nl;
+	rcu_assign_pointer(*nl, n);
 	return 0;
 }
 
-EXPORT_SYMBOL(notifier_chain_register);
-
-/**
- *	notifier_chain_unregister - Remove notifier from a notifier chain
- *	@nl: Pointer to root list pointer
- *	@n: New entry in notifier chain
- *
- *	Removes a notifier from a notifier chain.
- *
- *	Returns zero on success, or %-ENOENT on failure.
- */
- 
-int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n)
+static int notifier_chain_unregister(struct notifier_block **nl,
+		struct notifier_block *n)
 {
-	write_lock(&notifier_lock);
-	while((*nl)!=NULL)
-	{
-		if((*nl)==n)
-		{
-			*nl=n->next;
-			write_unlock(&notifier_lock);
+	while ((*nl) != NULL) {
+		if ((*nl) == n) {
+			rcu_assign_pointer(*nl, n->next);
 			return 0;
 		}
-		nl=&((*nl)->next);
+		nl = &((*nl)->next);
 	}
-	write_unlock(&notifier_lock);
 	return -ENOENT;
 }
 
-EXPORT_SYMBOL(notifier_chain_unregister);
-
-/**
- *	notifier_call_chain - Call functions in a notifier chain
- *	@n: Pointer to root pointer of notifier chain
- *	@val: Value passed unmodified to notifier function
- *	@v: Pointer passed unmodified to notifier function
- *
- *	Calls each function in a notifier chain in turn.
- *
- *	If the return value of the notifier can be and'd
- *	with %NOTIFY_STOP_MASK, then notifier_call_chain
- *	will return immediately, with the return value of
- *	the notifier function which halted execution.
- *	Otherwise, the return value is the return value
- *	of the last notifier function called.
- */
- 
-int __kprobes notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
+static int __kprobes notifier_call_chain(struct notifier_block **nl,
+		unsigned long val, void *v)
 {
-	int ret=NOTIFY_DONE;
-	struct notifier_block *nb = *n;
+	int ret = NOTIFY_DONE;
+	struct notifier_block *nb;
 
-	while(nb)
-	{
-		ret=nb->notifier_call(nb,val,v);
-		if(ret&NOTIFY_STOP_MASK)
-		{
-			return ret;
-		}
-		nb=nb->next;
+	nb = rcu_dereference(*nl);
+	while (nb) {
+		ret = nb->notifier_call(nb, val, v);
+		if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
+			break;
+		nb = rcu_dereference(nb->next);
 	}
 	return ret;
 }
 
-EXPORT_SYMBOL(notifier_call_chain);
+/*
+ *	Atomic notifier chain routines.  Registration and unregistration
+ *	use a mutex, and call_chain is synchronized by RCU (no locks).
+ */
+
+/**
+ *	atomic_notifier_chain_register - Add notifier to an atomic notifier chain
+ *	@nh: Pointer to head of the atomic notifier chain
+ *	@n: New entry in notifier chain
+ *
+ *	Adds a notifier to an atomic notifier chain.
+ *
+ *	Currently always returns zero.
+ */
+
+int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
+		struct notifier_block *n)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&nh->lock, flags);
+	ret = notifier_chain_register(&nh->head, n);
+	spin_unlock_irqrestore(&nh->lock, flags);
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(atomic_notifier_chain_register);
+
+/**
+ *	atomic_notifier_chain_unregister - Remove notifier from an atomic notifier chain
+ *	@nh: Pointer to head of the atomic notifier chain
+ *	@n: Entry to remove from notifier chain
+ *
+ *	Removes a notifier from an atomic notifier chain.
+ *
+ *	Returns zero on success or %-ENOENT on failure.
+ */
+int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
+		struct notifier_block *n)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&nh->lock, flags);
+	ret = notifier_chain_unregister(&nh->head, n);
+	spin_unlock_irqrestore(&nh->lock, flags);
+	synchronize_rcu();
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
+
+/**
+ *	atomic_notifier_call_chain - Call functions in an atomic notifier chain
+ *	@nh: Pointer to head of the atomic notifier chain
+ *	@val: Value passed unmodified to notifier function
+ *	@v: Pointer passed unmodified to notifier function
+ *
+ *	Calls each function in a notifier chain in turn.  The functions
+ *	run in an atomic context, so they must not block.
+ *	This routine uses RCU to synchronize with changes to the chain.
+ *
+ *	If the return value of the notifier can be and'ed
+ *	with %NOTIFY_STOP_MASK then atomic_notifier_call_chain
+ *	will return immediately, with the return value of
+ *	the notifier function which halted execution.
+ *	Otherwise the return value is the return value
+ *	of the last notifier function called.
+ */
+ 
+int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+		unsigned long val, void *v)
+{
+	int ret;
+
+	rcu_read_lock();
+	ret = notifier_call_chain(&nh->head, val, v);
+	rcu_read_unlock();
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
+
+/*
+ *	Blocking notifier chain routines.  All access to the chain is
+ *	synchronized by an rwsem.
+ */
+
+/**
+ *	blocking_notifier_chain_register - Add notifier to a blocking notifier chain
+ *	@nh: Pointer to head of the blocking notifier chain
+ *	@n: New entry in notifier chain
+ *
+ *	Adds a notifier to a blocking notifier chain.
+ *	Must be called in process context.
+ *
+ *	Currently always returns zero.
+ */
+ 
+int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
+		struct notifier_block *n)
+{
+	int ret;
+
+	/*
+	 * This code gets used during boot-up, when task switching is
+	 * not yet working and interrupts must remain disabled.  At
+	 * such times we must not call down_write().
+	 */
+	if (unlikely(system_state == SYSTEM_BOOTING))
+		return notifier_chain_register(&nh->head, n);
+
+	down_write(&nh->rwsem);
+	ret = notifier_chain_register(&nh->head, n);
+	up_write(&nh->rwsem);
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(blocking_notifier_chain_register);
+
+/**
+ *	blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain
+ *	@nh: Pointer to head of the blocking notifier chain
+ *	@n: Entry to remove from notifier chain
+ *
+ *	Removes a notifier from a blocking notifier chain.
+ *	Must be called from process context.
+ *
+ *	Returns zero on success or %-ENOENT on failure.
+ */
+int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
+		struct notifier_block *n)
+{
+	int ret;
+
+	/*
+	 * This code gets used during boot-up, when task switching is
+	 * not yet working and interrupts must remain disabled.  At
+	 * such times we must not call down_write().
+	 */
+	if (unlikely(system_state == SYSTEM_BOOTING))
+		return notifier_chain_unregister(&nh->head, n);
+
+	down_write(&nh->rwsem);
+	ret = notifier_chain_unregister(&nh->head, n);
+	up_write(&nh->rwsem);
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
+
+/**
+ *	blocking_notifier_call_chain - Call functions in a blocking notifier chain
+ *	@nh: Pointer to head of the blocking notifier chain
+ *	@val: Value passed unmodified to notifier function
+ *	@v: Pointer passed unmodified to notifier function
+ *
+ *	Calls each function in a notifier chain in turn.  The functions
+ *	run in a process context, so they are allowed to block.
+ *
+ *	If the return value of the notifier can be and'ed
+ *	with %NOTIFY_STOP_MASK then blocking_notifier_call_chain
+ *	will return immediately, with the return value of
+ *	the notifier function which halted execution.
+ *	Otherwise the return value is the return value
+ *	of the last notifier function called.
+ */
+ 
+int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+		unsigned long val, void *v)
+{
+	int ret;
+
+	down_read(&nh->rwsem);
+	ret = notifier_call_chain(&nh->head, val, v);
+	up_read(&nh->rwsem);
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
+
+/*
+ *	Raw notifier chain routines.  There is no protection;
+ *	the caller must provide it.  Use at your own risk!
+ */
+
+/**
+ *	raw_notifier_chain_register - Add notifier to a raw notifier chain
+ *	@nh: Pointer to head of the raw notifier chain
+ *	@n: New entry in notifier chain
+ *
+ *	Adds a notifier to a raw notifier chain.
+ *	All locking must be provided by the caller.
+ *
+ *	Currently always returns zero.
+ */
+
+int raw_notifier_chain_register(struct raw_notifier_head *nh,
+		struct notifier_block *n)
+{
+	return notifier_chain_register(&nh->head, n);
+}
+
+EXPORT_SYMBOL_GPL(raw_notifier_chain_register);
+
+/**
+ *	raw_notifier_chain_unregister - Remove notifier from a raw notifier chain
+ *	@nh: Pointer to head of the raw notifier chain
+ *	@n: Entry to remove from notifier chain
+ *
+ *	Removes a notifier from a raw notifier chain.
+ *	All locking must be provided by the caller.
+ *
+ *	Returns zero on success or %-ENOENT on failure.
+ */
+int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
+		struct notifier_block *n)
+{
+	return notifier_chain_unregister(&nh->head, n);
+}
+
+EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
+
+/**
+ *	raw_notifier_call_chain - Call functions in a raw notifier chain
+ *	@nh: Pointer to head of the raw notifier chain
+ *	@val: Value passed unmodified to notifier function
+ *	@v: Pointer passed unmodified to notifier function
+ *
+ *	Calls each function in a notifier chain in turn.  The functions
+ *	run in an undefined context.
+ *	All locking must be provided by the caller.
+ *
+ *	If the return value of the notifier can be and'ed
+ *	with %NOTIFY_STOP_MASK then raw_notifier_call_chain
+ *	will return immediately, with the return value of
+ *	the notifier function which halted execution.
+ *	Otherwise the return value is the return value
+ *	of the last notifier function called.
+ */
+
+int raw_notifier_call_chain(struct raw_notifier_head *nh,
+		unsigned long val, void *v)
+{
+	return notifier_call_chain(&nh->head, val, v);
+}
+
+EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
 
 /**
  *	register_reboot_notifier - Register function to be called at reboot time
@@ -196,13 +401,13 @@
  *	Registers a function with the list of functions
  *	to be called at reboot time.
  *
- *	Currently always returns zero, as notifier_chain_register
+ *	Currently always returns zero, as blocking_notifier_chain_register
  *	always returns zero.
  */
  
 int register_reboot_notifier(struct notifier_block * nb)
 {
-	return notifier_chain_register(&reboot_notifier_list, nb);
+	return blocking_notifier_chain_register(&reboot_notifier_list, nb);
 }
 
 EXPORT_SYMBOL(register_reboot_notifier);
@@ -219,7 +424,7 @@
  
 int unregister_reboot_notifier(struct notifier_block * nb)
 {
-	return notifier_chain_unregister(&reboot_notifier_list, nb);
+	return blocking_notifier_chain_unregister(&reboot_notifier_list, nb);
 }
 
 EXPORT_SYMBOL(unregister_reboot_notifier);
@@ -380,7 +585,7 @@
 
 void kernel_restart_prepare(char *cmd)
 {
-	notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
+	blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
 	system_state = SYSTEM_RESTART;
 	device_shutdown();
 }
@@ -430,7 +635,7 @@
 
 void kernel_shutdown_prepare(enum system_states state)
 {
-	notifier_call_chain(&reboot_notifier_list,
+	blocking_notifier_call_chain(&reboot_notifier_list,
 		(state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL);
 	system_state = state;
 	device_shutdown();
@@ -997,69 +1202,24 @@
 	 */
 	if (tbuf) {
 		struct tms tmp;
+		struct task_struct *tsk = current;
+		struct task_struct *t;
 		cputime_t utime, stime, cutime, cstime;
 
-#ifdef CONFIG_SMP
-		if (thread_group_empty(current)) {
-			/*
-			 * Single thread case without the use of any locks.
-			 *
-			 * We may race with release_task if two threads are
-			 * executing. However, release task first adds up the
-			 * counters (__exit_signal) before  removing the task
-			 * from the process tasklist (__unhash_process).
-			 * __exit_signal also acquires and releases the
-			 * siglock which results in the proper memory ordering
-			 * so that the list modifications are always visible
-			 * after the counters have been updated.
-			 *
-			 * If the counters have been updated by the second thread
-			 * but the thread has not yet been removed from the list
-			 * then the other branch will be executing which will
-			 * block on tasklist_lock until the exit handling of the
-			 * other task is finished.
-			 *
-			 * This also implies that the sighand->siglock cannot
-			 * be held by another processor. So we can also
-			 * skip acquiring that lock.
-			 */
-			utime = cputime_add(current->signal->utime, current->utime);
-			stime = cputime_add(current->signal->utime, current->stime);
-			cutime = current->signal->cutime;
-			cstime = current->signal->cstime;
-		} else
-#endif
-		{
+		spin_lock_irq(&tsk->sighand->siglock);
+		utime = tsk->signal->utime;
+		stime = tsk->signal->stime;
+		t = tsk;
+		do {
+			utime = cputime_add(utime, t->utime);
+			stime = cputime_add(stime, t->stime);
+			t = next_thread(t);
+		} while (t != tsk);
 
-			/* Process with multiple threads */
-			struct task_struct *tsk = current;
-			struct task_struct *t;
+		cutime = tsk->signal->cutime;
+		cstime = tsk->signal->cstime;
+		spin_unlock_irq(&tsk->sighand->siglock);
 
-			read_lock(&tasklist_lock);
-			utime = tsk->signal->utime;
-			stime = tsk->signal->stime;
-			t = tsk;
-			do {
-				utime = cputime_add(utime, t->utime);
-				stime = cputime_add(stime, t->stime);
-				t = next_thread(t);
-			} while (t != tsk);
-
-			/*
-			 * While we have tasklist_lock read-locked, no dying thread
-			 * can be updating current->signal->[us]time.  Instead,
-			 * we got their counts included in the live thread loop.
-			 * However, another thread can come in right now and
-			 * do a wait call that updates current->signal->c[us]time.
-			 * To make sure we always see that pair updated atomically,
-			 * we take the siglock around fetching them.
-			 */
-			spin_lock_irq(&tsk->sighand->siglock);
-			cutime = tsk->signal->cutime;
-			cstime = tsk->signal->cstime;
-			spin_unlock_irq(&tsk->sighand->siglock);
-			read_unlock(&tasklist_lock);
-		}
 		tmp.tms_utime = cputime_to_clock_t(utime);
 		tmp.tms_stime = cputime_to_clock_t(stime);
 		tmp.tms_cutime = cputime_to_clock_t(cutime);
@@ -1212,18 +1372,29 @@
 asmlinkage long sys_setsid(void)
 {
 	struct task_struct *group_leader = current->group_leader;
-	struct pid *pid;
+	pid_t session;
 	int err = -EPERM;
 
 	mutex_lock(&tty_mutex);
 	write_lock_irq(&tasklist_lock);
 
-	pid = find_pid(PIDTYPE_PGID, group_leader->pid);
-	if (pid)
+	/* Fail if I am already a session leader */
+	if (group_leader->signal->leader)
+		goto out;
+
+	session = group_leader->pid;
+	/* Fail if a process group id already exists that equals the
+	 * proposed session id.
+	 *
+	 * Don't check if session id == 1 because kernel threads use this
+	 * session id and so the check will always fail and make it so
+	 * init cannot successfully call setsid.
+	 */
+	if (session > 1 && find_task_by_pid_type(PIDTYPE_PGID, session))
 		goto out;
 
 	group_leader->signal->leader = 1;
-	__set_special_pids(group_leader->pid, group_leader->pid);
+	__set_special_pids(session, session);
 	group_leader->signal->tty = NULL;
 	group_leader->signal->tty_old_pgrp = 0;
 	err = process_group(group_leader);
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 1067090..d82864c 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -42,6 +42,10 @@
 cond_syscall(sys_socketcall);
 cond_syscall(sys_futex);
 cond_syscall(compat_sys_futex);
+cond_syscall(sys_set_robust_list);
+cond_syscall(compat_sys_set_robust_list);
+cond_syscall(sys_get_robust_list);
+cond_syscall(compat_sys_get_robust_list);
 cond_syscall(sys_epoll_create);
 cond_syscall(sys_epoll_ctl);
 cond_syscall(sys_epoll_wait);
diff --git a/kernel/time.c b/kernel/time.c
index e00a97b..ff8e701 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -610,7 +610,7 @@
  *
  * Returns the timespec representation of the nsec parameter.
  */
-struct timespec ns_to_timespec(const nsec_t nsec)
+struct timespec ns_to_timespec(const s64 nsec)
 {
 	struct timespec ts;
 
@@ -630,7 +630,7 @@
  *
  * Returns the timeval representation of the nsec parameter.
  */
-struct timeval ns_to_timeval(const nsec_t nsec)
+struct timeval ns_to_timeval(const s64 nsec)
 {
 	struct timespec ts = ns_to_timespec(nsec);
 	struct timeval tv;
diff --git a/kernel/timer.c b/kernel/timer.c
index ab189dd..6b812c0 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -54,7 +54,6 @@
 /*
  * per-CPU timer vector definitions:
  */
-
 #define TVN_BITS (CONFIG_BASE_SMALL ? 4 : 6)
 #define TVR_BITS (CONFIG_BASE_SMALL ? 6 : 8)
 #define TVN_SIZE (1 << TVN_BITS)
@@ -62,11 +61,6 @@
 #define TVN_MASK (TVN_SIZE - 1)
 #define TVR_MASK (TVR_SIZE - 1)
 
-struct timer_base_s {
-	spinlock_t lock;
-	struct timer_list *running_timer;
-};
-
 typedef struct tvec_s {
 	struct list_head vec[TVN_SIZE];
 } tvec_t;
@@ -76,7 +70,8 @@
 } tvec_root_t;
 
 struct tvec_t_base_s {
-	struct timer_base_s t_base;
+	spinlock_t lock;
+	struct timer_list *running_timer;
 	unsigned long timer_jiffies;
 	tvec_root_t tv1;
 	tvec_t tv2;
@@ -87,13 +82,14 @@
 
 typedef struct tvec_t_base_s tvec_base_t;
 static DEFINE_PER_CPU(tvec_base_t *, tvec_bases);
-static tvec_base_t boot_tvec_bases;
+tvec_base_t boot_tvec_bases;
+EXPORT_SYMBOL(boot_tvec_bases);
 
 static inline void set_running_timer(tvec_base_t *base,
 					struct timer_list *timer)
 {
 #ifdef CONFIG_SMP
-	base->t_base.running_timer = timer;
+	base->running_timer = timer;
 #endif
 }
 
@@ -139,15 +135,6 @@
 	list_add_tail(&timer->entry, vec);
 }
 
-typedef struct timer_base_s timer_base_t;
-/*
- * Used by TIMER_INITIALIZER, we can't use per_cpu(tvec_bases)
- * at compile time, and we need timer->base to lock the timer.
- */
-timer_base_t __init_timer_base
-	____cacheline_aligned_in_smp = { .lock = SPIN_LOCK_UNLOCKED };
-EXPORT_SYMBOL(__init_timer_base);
-
 /***
  * init_timer - initialize a timer.
  * @timer: the timer to be initialized
@@ -158,7 +145,7 @@
 void fastcall init_timer(struct timer_list *timer)
 {
 	timer->entry.next = NULL;
-	timer->base = &per_cpu(tvec_bases, raw_smp_processor_id())->t_base;
+	timer->base = per_cpu(tvec_bases, raw_smp_processor_id());
 }
 EXPORT_SYMBOL(init_timer);
 
@@ -174,7 +161,7 @@
 }
 
 /*
- * We are using hashed locking: holding per_cpu(tvec_bases).t_base.lock
+ * We are using hashed locking: holding per_cpu(tvec_bases).lock
  * means that all timers which are tied to this base via timer->base are
  * locked, and the base itself is locked too.
  *
@@ -185,10 +172,10 @@
  * possible to set timer->base = NULL and drop the lock: the timer remains
  * locked.
  */
-static timer_base_t *lock_timer_base(struct timer_list *timer,
+static tvec_base_t *lock_timer_base(struct timer_list *timer,
 					unsigned long *flags)
 {
-	timer_base_t *base;
+	tvec_base_t *base;
 
 	for (;;) {
 		base = timer->base;
@@ -205,8 +192,7 @@
 
 int __mod_timer(struct timer_list *timer, unsigned long expires)
 {
-	timer_base_t *base;
-	tvec_base_t *new_base;
+	tvec_base_t *base, *new_base;
 	unsigned long flags;
 	int ret = 0;
 
@@ -221,7 +207,7 @@
 
 	new_base = __get_cpu_var(tvec_bases);
 
-	if (base != &new_base->t_base) {
+	if (base != new_base) {
 		/*
 		 * We are trying to schedule the timer on the local CPU.
 		 * However we can't change timer's base while it is running,
@@ -229,21 +215,19 @@
 		 * handler yet has not finished. This also guarantees that
 		 * the timer is serialized wrt itself.
 		 */
-		if (unlikely(base->running_timer == timer)) {
-			/* The timer remains on a former base */
-			new_base = container_of(base, tvec_base_t, t_base);
-		} else {
+		if (likely(base->running_timer != timer)) {
 			/* See the comment in lock_timer_base() */
 			timer->base = NULL;
 			spin_unlock(&base->lock);
-			spin_lock(&new_base->t_base.lock);
-			timer->base = &new_base->t_base;
+			base = new_base;
+			spin_lock(&base->lock);
+			timer->base = base;
 		}
 	}
 
 	timer->expires = expires;
-	internal_add_timer(new_base, timer);
-	spin_unlock_irqrestore(&new_base->t_base.lock, flags);
+	internal_add_timer(base, timer);
+	spin_unlock_irqrestore(&base->lock, flags);
 
 	return ret;
 }
@@ -263,10 +247,10 @@
   	unsigned long flags;
 
   	BUG_ON(timer_pending(timer) || !timer->function);
-	spin_lock_irqsave(&base->t_base.lock, flags);
-	timer->base = &base->t_base;
+	spin_lock_irqsave(&base->lock, flags);
+	timer->base = base;
 	internal_add_timer(base, timer);
-	spin_unlock_irqrestore(&base->t_base.lock, flags);
+	spin_unlock_irqrestore(&base->lock, flags);
 }
 
 
@@ -319,7 +303,7 @@
  */
 int del_timer(struct timer_list *timer)
 {
-	timer_base_t *base;
+	tvec_base_t *base;
 	unsigned long flags;
 	int ret = 0;
 
@@ -346,7 +330,7 @@
  */
 int try_to_del_timer_sync(struct timer_list *timer)
 {
-	timer_base_t *base;
+	tvec_base_t *base;
 	unsigned long flags;
 	int ret = -1;
 
@@ -410,7 +394,7 @@
 		struct timer_list *tmp;
 
 		tmp = list_entry(curr, struct timer_list, entry);
-		BUG_ON(tmp->base != &base->t_base);
+		BUG_ON(tmp->base != base);
 		curr = curr->next;
 		internal_add_timer(base, tmp);
 	}
@@ -432,7 +416,7 @@
 {
 	struct timer_list *timer;
 
-	spin_lock_irq(&base->t_base.lock);
+	spin_lock_irq(&base->lock);
 	while (time_after_eq(jiffies, base->timer_jiffies)) {
 		struct list_head work_list = LIST_HEAD_INIT(work_list);
 		struct list_head *head = &work_list;
@@ -458,7 +442,7 @@
 
 			set_running_timer(base, timer);
 			detach_timer(timer, 1);
-			spin_unlock_irq(&base->t_base.lock);
+			spin_unlock_irq(&base->lock);
 			{
 				int preempt_count = preempt_count();
 				fn(data);
@@ -471,11 +455,11 @@
 					BUG();
 				}
 			}
-			spin_lock_irq(&base->t_base.lock);
+			spin_lock_irq(&base->lock);
 		}
 	}
 	set_running_timer(base, NULL);
-	spin_unlock_irq(&base->t_base.lock);
+	spin_unlock_irq(&base->lock);
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
@@ -506,7 +490,7 @@
 	hr_expires += jiffies;
 
 	base = __get_cpu_var(tvec_bases);
-	spin_lock(&base->t_base.lock);
+	spin_lock(&base->lock);
 	expires = base->timer_jiffies + (LONG_MAX >> 1);
 	list = NULL;
 
@@ -554,7 +538,7 @@
 				expires = nte->expires;
 		}
 	}
-	spin_unlock(&base->t_base.lock);
+	spin_unlock(&base->lock);
 
 	if (time_before(hr_expires, expires))
 		return hr_expires;
@@ -841,7 +825,7 @@
  */
 static unsigned long count_active_tasks(void)
 {
-	return (nr_running() + nr_uninterruptible()) * FIXED_1;
+	return nr_active() * FIXED_1;
 }
 
 /*
@@ -1262,7 +1246,7 @@
 		}
 		per_cpu(tvec_bases, cpu) = base;
 	}
-	spin_lock_init(&base->t_base.lock);
+	spin_lock_init(&base->lock);
 	for (j = 0; j < TVN_SIZE; j++) {
 		INIT_LIST_HEAD(base->tv5.vec + j);
 		INIT_LIST_HEAD(base->tv4.vec + j);
@@ -1284,7 +1268,7 @@
 	while (!list_empty(head)) {
 		timer = list_entry(head->next, struct timer_list, entry);
 		detach_timer(timer, 0);
-		timer->base = &new_base->t_base;
+		timer->base = new_base;
 		internal_add_timer(new_base, timer);
 	}
 }
@@ -1300,11 +1284,11 @@
 	new_base = get_cpu_var(tvec_bases);
 
 	local_irq_disable();
-	spin_lock(&new_base->t_base.lock);
-	spin_lock(&old_base->t_base.lock);
+	spin_lock(&new_base->lock);
+	spin_lock(&old_base->lock);
 
-	if (old_base->t_base.running_timer)
-		BUG();
+	BUG_ON(old_base->running_timer);
+
 	for (i = 0; i < TVR_SIZE; i++)
 		migrate_timer_list(new_base, old_base->tv1.vec + i);
 	for (i = 0; i < TVN_SIZE; i++) {
@@ -1314,8 +1298,8 @@
 		migrate_timer_list(new_base, old_base->tv5.vec + i);
 	}
 
-	spin_unlock(&old_base->t_base.lock);
-	spin_unlock(&new_base->t_base.lock);
+	spin_unlock(&old_base->lock);
+	spin_unlock(&new_base->lock);
 	local_irq_enable();
 	put_cpu_var(tvec_bases);
 }
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 7e70ab1..d57fd91 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -157,22 +157,9 @@
 
 	  If unsure, say N.
 
-config DEBUG_IOREMAP
-	bool "Enable ioremap() debugging"
-	depends on DEBUG_KERNEL && PARISC
-	help
-	  Enabling this option will cause the kernel to distinguish between
-	  ioremapped and physical addresses.  It will print a backtrace (at
-	  most one every 10 seconds), hopefully allowing you to see which
-	  drivers need work.  Fixing all these problems is a prerequisite
-	  for turning on USE_HPPA_IOREMAP.  The warnings are harmless;
-	  the kernel has enough information to fix the broken drivers
-	  automatically, but we'd like to make it more efficient by not
-	  having to do that.
-
 config DEBUG_FS
 	bool "Debug Filesystem"
-	depends on DEBUG_KERNEL && SYSFS
+	depends on SYSFS
 	help
 	  debugfs is a virtual file system that kernel developers use to put
 	  debugging files into.  Enable this option to be able to read and
diff --git a/lib/Makefile b/lib/Makefile
index f827e3c..b830c9a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -23,6 +23,7 @@
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_SEMAPHORE_SLEEPERS) += semaphore-sleepers.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
+lib-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
 
diff --git a/lib/bitmap.c b/lib/bitmap.c
index 8acab0e..ed2ae3b 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -253,33 +253,18 @@
 }
 EXPORT_SYMBOL(__bitmap_subset);
 
-#if BITS_PER_LONG == 32
 int __bitmap_weight(const unsigned long *bitmap, int bits)
 {
 	int k, w = 0, lim = bits/BITS_PER_LONG;
 
 	for (k = 0; k < lim; k++)
-		w += hweight32(bitmap[k]);
+		w += hweight_long(bitmap[k]);
 
 	if (bits % BITS_PER_LONG)
-		w += hweight32(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));
+		w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));
 
 	return w;
 }
-#else
-int __bitmap_weight(const unsigned long *bitmap, int bits)
-{
-	int k, w = 0, lim = bits/BITS_PER_LONG;
-
-	for (k = 0; k < lim; k++)
-		w += hweight64(bitmap[k]);
-
-	if (bits % BITS_PER_LONG)
-		w += hweight64(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));
-
-	return w;
-}
-#endif
 EXPORT_SYMBOL(__bitmap_weight);
 
 /*
diff --git a/lib/find_next_bit.c b/lib/find_next_bit.c
index c05b4b1..bda0d71 100644
--- a/lib/find_next_bit.c
+++ b/lib/find_next_bit.c
@@ -11,48 +11,171 @@
 
 #include <linux/bitops.h>
 #include <linux/module.h>
+#include <asm/types.h>
+#include <asm/byteorder.h>
 
-int find_next_bit(const unsigned long *addr, int size, int offset)
+#define BITOP_WORD(nr)		((nr) / BITS_PER_LONG)
+
+/**
+ * find_next_bit - find the next set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+		unsigned long offset)
 {
-	const unsigned long *base;
-	const int NBITS = sizeof(*addr) * 8;
+	const unsigned long *p = addr + BITOP_WORD(offset);
+	unsigned long result = offset & ~(BITS_PER_LONG-1);
 	unsigned long tmp;
 
-	base = addr;
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset %= BITS_PER_LONG;
 	if (offset) {
-		int suboffset;
-
-		addr += offset / NBITS;
-
-		suboffset = offset % NBITS;
-		if (suboffset) {
-			tmp = *addr;
-			tmp >>= suboffset;
-			if (tmp)
-				goto finish;
-		}
-
-		addr++;
+		tmp = *(p++);
+		tmp &= (~0UL << offset);
+		if (size < BITS_PER_LONG)
+			goto found_first;
+		if (tmp)
+			goto found_middle;
+		size -= BITS_PER_LONG;
+		result += BITS_PER_LONG;
 	}
-
-	while ((tmp = *addr) == 0)
-		addr++;
-
-	offset = (addr - base) * NBITS;
-
- finish:
-	/* count the remaining bits without using __ffs() since that takes a 32-bit arg */
-	while (!(tmp & 0xff)) {
-		offset += 8;
-		tmp >>= 8;
+	while (size & ~(BITS_PER_LONG-1)) {
+		if ((tmp = *(p++)))
+			goto found_middle;
+		result += BITS_PER_LONG;
+		size -= BITS_PER_LONG;
 	}
+	if (!size)
+		return result;
+	tmp = *p;
 
-	while (!(tmp & 1)) {
-		offset++;
-		tmp >>= 1;
-	}
-
-	return offset;
+found_first:
+	tmp &= (~0UL >> (BITS_PER_LONG - size));
+	if (tmp == 0UL)		/* Are any bits set? */
+		return result + size;	/* Nope. */
+found_middle:
+	return result + __ffs(tmp);
 }
 
 EXPORT_SYMBOL(find_next_bit);
+
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
+		unsigned long offset)
+{
+	const unsigned long *p = addr + BITOP_WORD(offset);
+	unsigned long result = offset & ~(BITS_PER_LONG-1);
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset %= BITS_PER_LONG;
+	if (offset) {
+		tmp = *(p++);
+		tmp |= ~0UL >> (BITS_PER_LONG - offset);
+		if (size < BITS_PER_LONG)
+			goto found_first;
+		if (~tmp)
+			goto found_middle;
+		size -= BITS_PER_LONG;
+		result += BITS_PER_LONG;
+	}
+	while (size & ~(BITS_PER_LONG-1)) {
+		if (~(tmp = *(p++)))
+			goto found_middle;
+		result += BITS_PER_LONG;
+		size -= BITS_PER_LONG;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
+
+found_first:
+	tmp |= ~0UL << size;
+	if (tmp == ~0UL)	/* Are any bits zero? */
+		return result + size;	/* Nope. */
+found_middle:
+	return result + ffz(tmp);
+}
+
+EXPORT_SYMBOL(find_next_zero_bit);
+
+#ifdef __BIG_ENDIAN
+
+/* include/linux/byteorder does not support "unsigned long" type */
+static inline unsigned long ext2_swabp(const unsigned long * x)
+{
+#if BITS_PER_LONG == 64
+	return (unsigned long) __swab64p((u64 *) x);
+#elif BITS_PER_LONG == 32
+	return (unsigned long) __swab32p((u32 *) x);
+#else
+#error BITS_PER_LONG not defined
+#endif
+}
+
+/* include/linux/byteorder doesn't support "unsigned long" type */
+static inline unsigned long ext2_swab(const unsigned long y)
+{
+#if BITS_PER_LONG == 64
+	return (unsigned long) __swab64((u64) y);
+#elif BITS_PER_LONG == 32
+	return (unsigned long) __swab32((u32) y);
+#else
+#error BITS_PER_LONG not defined
+#endif
+}
+
+unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned
+		long size, unsigned long offset)
+{
+	const unsigned long *p = addr + BITOP_WORD(offset);
+	unsigned long result = offset & ~(BITS_PER_LONG - 1);
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset &= (BITS_PER_LONG - 1UL);
+	if (offset) {
+		tmp = ext2_swabp(p++);
+		tmp |= (~0UL >> (BITS_PER_LONG - offset));
+		if (size < BITS_PER_LONG)
+			goto found_first;
+		if (~tmp)
+			goto found_middle;
+		size -= BITS_PER_LONG;
+		result += BITS_PER_LONG;
+	}
+
+	while (size & ~(BITS_PER_LONG - 1)) {
+		if (~(tmp = *(p++)))
+			goto found_middle_swap;
+		result += BITS_PER_LONG;
+		size -= BITS_PER_LONG;
+	}
+	if (!size)
+		return result;
+	tmp = ext2_swabp(p);
+found_first:
+	tmp |= ~0UL << size;
+	if (tmp == ~0UL)	/* Are any bits zero? */
+		return result + size; /* Nope. Skip ffz */
+found_middle:
+	return result + ffz(tmp);
+
+found_middle_swap:
+	return result + ffz(ext2_swab(tmp));
+}
+
+EXPORT_SYMBOL(generic_find_next_zero_le_bit);
+
+#endif /* __BIG_ENDIAN */
diff --git a/lib/hweight.c b/lib/hweight.c
new file mode 100644
index 0000000..4382576
--- /dev/null
+++ b/lib/hweight.c
@@ -0,0 +1,53 @@
+#include <linux/module.h>
+#include <asm/types.h>
+
+/**
+ * hweightN - returns the hamming weight of a N-bit word
+ * @x: the word to weigh
+ *
+ * The Hamming Weight of a number is the total number of bits set in it.
+ */
+
+unsigned int hweight32(unsigned int w)
+{
+	unsigned int res = w - ((w >> 1) & 0x55555555);
+	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+	res = (res + (res >> 4)) & 0x0F0F0F0F;
+	res = res + (res >> 8);
+	return (res + (res >> 16)) & 0x000000FF;
+}
+EXPORT_SYMBOL(hweight32);
+
+unsigned int hweight16(unsigned int w)
+{
+	unsigned int res = w - ((w >> 1) & 0x5555);
+	res = (res & 0x3333) + ((res >> 2) & 0x3333);
+	res = (res + (res >> 4)) & 0x0F0F;
+	return (res + (res >> 8)) & 0x00FF;
+}
+EXPORT_SYMBOL(hweight16);
+
+unsigned int hweight8(unsigned int w)
+{
+	unsigned int res = w - ((w >> 1) & 0x55);
+	res = (res & 0x33) + ((res >> 2) & 0x33);
+	return (res + (res >> 4)) & 0x0F;
+}
+EXPORT_SYMBOL(hweight8);
+
+unsigned long hweight64(__u64 w)
+{
+#if BITS_PER_LONG == 32
+	return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
+#elif BITS_PER_LONG == 64
+	__u64 res = w - ((w >> 1) & 0x5555555555555555ul);
+	res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
+	res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful;
+	res = res + (res >> 8);
+	res = res + (res >> 16);
+	return (res + (res >> 32)) & 0x00000000000000FFul;
+#else
+#error BITS_PER_LONG not defined
+#endif
+}
+EXPORT_SYMBOL(hweight64);
diff --git a/mm/Makefile b/mm/Makefile
index f10c753..0b8f73f 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -10,7 +10,7 @@
 obj-y			:= bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
 			   page_alloc.o page-writeback.o pdflush.o \
 			   readahead.o swap.o truncate.o vmscan.o \
-			   prio_tree.o util.o $(mmu-y)
+			   prio_tree.o util.o mmzone.o $(mmu-y)
 
 obj-$(CONFIG_SWAP)	+= page_io.o swap_state.o swapfile.o thrash.o
 obj-$(CONFIG_HUGETLBFS)	+= hugetlb.o
diff --git a/mm/bootmem.c b/mm/bootmem.c
index b55bd39..d3e3bd2 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -33,6 +33,7 @@
 				 * dma_get_required_mask(), which uses
 				 * it, can be an inline function */
 
+static LIST_HEAD(bdata_list);
 #ifdef CONFIG_CRASH_DUMP
 /*
  * If we have booted due to a crash, max_pfn will be a very low value. We need
@@ -52,6 +53,27 @@
 
 	return mapsize;
 }
+/*
+ * link bdata in order
+ */
+static void link_bootmem(bootmem_data_t *bdata)
+{
+	bootmem_data_t *ent;
+	if (list_empty(&bdata_list)) {
+		list_add(&bdata->list, &bdata_list);
+		return;
+	}
+	/* insert in order */
+	list_for_each_entry(ent, &bdata_list, list) {
+		if (bdata->node_boot_start < ent->node_boot_start) {
+			list_add_tail(&bdata->list, &ent->list);
+			return;
+		}
+	}
+	list_add_tail(&bdata->list, &bdata_list);
+	return;
+}
+
 
 /*
  * Called once to set up the allocator itself.
@@ -62,13 +84,11 @@
 	bootmem_data_t *bdata = pgdat->bdata;
 	unsigned long mapsize = ((end - start)+7)/8;
 
-	pgdat->pgdat_next = pgdat_list;
-	pgdat_list = pgdat;
-
 	mapsize = ALIGN(mapsize, sizeof(long));
 	bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT);
 	bdata->node_boot_start = (start << PAGE_SHIFT);
 	bdata->node_low_pfn = end;
+	link_bootmem(bdata);
 
 	/*
 	 * Initially all pages are reserved - setup_arch() has to
@@ -383,12 +403,11 @@
 
 void * __init __alloc_bootmem(unsigned long size, unsigned long align, unsigned long goal)
 {
-	pg_data_t *pgdat = pgdat_list;
+	bootmem_data_t *bdata;
 	void *ptr;
 
-	for_each_pgdat(pgdat)
-		if ((ptr = __alloc_bootmem_core(pgdat->bdata, size,
-						 align, goal, 0)))
+	list_for_each_entry(bdata, &bdata_list, list)
+		if ((ptr = __alloc_bootmem_core(bdata, size, align, goal, 0)))
 			return(ptr);
 
 	/*
@@ -416,11 +435,11 @@
 
 void * __init __alloc_bootmem_low(unsigned long size, unsigned long align, unsigned long goal)
 {
-	pg_data_t *pgdat = pgdat_list;
+	bootmem_data_t *bdata;
 	void *ptr;
 
-	for_each_pgdat(pgdat)
-		if ((ptr = __alloc_bootmem_core(pgdat->bdata, size,
+	list_for_each_entry(bdata, &bdata_list, list)
+		if ((ptr = __alloc_bootmem_core(bdata, size,
 						 align, goal, LOW32LIMIT)))
 			return(ptr);
 
diff --git a/mm/fadvise.c b/mm/fadvise.c
index 907c392..0a03357 100644
--- a/mm/fadvise.c
+++ b/mm/fadvise.c
@@ -35,17 +35,6 @@
  *
  * LINUX_FADV_ASYNC_WRITE: push some or all of the dirty pages at the disk.
  *
- * LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE: push all of the currently
- * dirty pages at the disk.
- *
- * LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE, LINUX_FADV_WRITE_WAIT: push
- * all of the currently dirty pages at the disk, wait until they have been
- * written.
- *
- * It should be noted that none of these operations write out the file's
- * metadata.  So unless the application is strictly performing overwrites of
- * already-instantiated disk blocks, there are no guarantees here that the data
- * will be available after a crash.
  */
 asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
 {
@@ -129,15 +118,6 @@
 			invalidate_mapping_pages(mapping, start_index,
 						end_index);
 		break;
-	case LINUX_FADV_ASYNC_WRITE:
-		ret = __filemap_fdatawrite_range(mapping, offset, endbyte,
-						WB_SYNC_NONE);
-		break;
-	case LINUX_FADV_WRITE_WAIT:
-		ret = wait_on_page_writeback_range(mapping,
-					offset >> PAGE_CACHE_SHIFT,
-					endbyte >> PAGE_CACHE_SHIFT);
-		break;
 	default:
 		ret = -EINVAL;
 	}
diff --git a/mm/highmem.c b/mm/highmem.c
index d0ea1ee..55885f6 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -31,14 +31,9 @@
 
 static mempool_t *page_pool, *isa_page_pool;
 
-static void *page_pool_alloc_isa(gfp_t gfp_mask, void *data)
+static void *mempool_alloc_pages_isa(gfp_t gfp_mask, void *data)
 {
-	return alloc_page(gfp_mask | GFP_DMA);
-}
-
-static void page_pool_free(void *page, void *data)
-{
-	__free_page(page);
+	return mempool_alloc_pages(gfp_mask | GFP_DMA, data);
 }
 
 /*
@@ -51,11 +46,6 @@
  */
 #ifdef CONFIG_HIGHMEM
 
-static void *page_pool_alloc(gfp_t gfp_mask, void *data)
-{
-	return alloc_page(gfp_mask);
-}
-
 static int pkmap_count[LAST_PKMAP];
 static unsigned int last_pkmap_nr;
 static  __cacheline_aligned_in_smp DEFINE_SPINLOCK(kmap_lock);
@@ -229,7 +219,7 @@
 	if (!i.totalhigh)
 		return 0;
 
-	page_pool = mempool_create(POOL_SIZE, page_pool_alloc, page_pool_free, NULL);
+	page_pool = mempool_create_page_pool(POOL_SIZE, 0);
 	if (!page_pool)
 		BUG();
 	printk("highmem bounce pool size: %d pages\n", POOL_SIZE);
@@ -272,7 +262,8 @@
 	if (isa_page_pool)
 		return 0;
 
-	isa_page_pool = mempool_create(ISA_POOL_SIZE, page_pool_alloc_isa, page_pool_free, NULL);
+	isa_page_pool = mempool_create(ISA_POOL_SIZE, mempool_alloc_pages_isa,
+				       mempool_free_pages, (void *) 0);
 	if (!isa_page_pool)
 		BUG();
 
@@ -337,7 +328,7 @@
 	bio_put(bio);
 }
 
-static int bounce_end_io_write(struct bio *bio, unsigned int bytes_done,int err)
+static int bounce_end_io_write(struct bio *bio, unsigned int bytes_done, int err)
 {
 	if (bio->bi_size)
 		return 1;
@@ -384,7 +375,7 @@
 }
 
 static void __blk_queue_bounce(request_queue_t *q, struct bio **bio_orig,
-			mempool_t *pool)
+			       mempool_t *pool)
 {
 	struct page *page;
 	struct bio *bio = NULL;
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index ebad6bb..832f676 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -334,6 +334,7 @@
 		return nr_huge_pages;
 
 	spin_lock(&hugetlb_lock);
+	count = max(count, reserved_huge_pages);
 	try_to_free_low(count);
 	while (count < nr_huge_pages) {
 		struct page *page = dequeue_huge_page(NULL, 0);
@@ -697,9 +698,10 @@
 		pfn_offset = (vaddr & ~HPAGE_MASK) >> PAGE_SHIFT;
 		page = pte_page(*pte);
 same_page:
-		get_page(page);
-		if (pages)
+		if (pages) {
+			get_page(page);
 			pages[i] = page + pfn_offset;
+		}
 
 		if (vmas)
 			vmas[i] = vma;
diff --git a/mm/memory.c b/mm/memory.c
index e347e10..0ec7bc6 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -87,7 +87,7 @@
 static int __init disable_randmaps(char *s)
 {
 	randomize_va_space = 0;
-	return 0;
+	return 1;
 }
 __setup("norandmaps", disable_randmaps);
 
@@ -1071,6 +1071,8 @@
 			}
 			if (pages) {
 				pages[i] = page;
+
+				flush_anon_page(page, start);
 				flush_dcache_page(page);
 			}
 			if (vmas)
@@ -2352,10 +2354,8 @@
 	if (!vma)
 		return -1;
 	write = (vma->vm_flags & VM_WRITE) != 0;
-	if (addr >= end)
-		BUG();
-	if (end > vma->vm_end)
-		BUG();
+	BUG_ON(addr >= end);
+	BUG_ON(end > vma->vm_end);
 	len = (end+PAGE_SIZE-1)/PAGE_SIZE-addr/PAGE_SIZE;
 	ret = get_user_pages(current, current->mm, addr,
 			len, write, 0, NULL, NULL);
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 4f71cfd..dec8249 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -912,7 +912,7 @@
 	/*
 	 * Check if this process has the right to modify the specified
 	 * process. The right exists if the process has administrative
-	 * capabilities, superuser priviledges or the same
+	 * capabilities, superuser privileges or the same
 	 * userid as the target process.
 	 */
 	if ((current->euid != task->suid) && (current->euid != task->uid) &&
diff --git a/mm/mempool.c b/mm/mempool.c
index f71893e..fe6e052 100644
--- a/mm/mempool.c
+++ b/mm/mempool.c
@@ -183,8 +183,8 @@
  */
 void mempool_destroy(mempool_t *pool)
 {
-	if (pool->curr_nr != pool->min_nr)
-		BUG();		/* There were outstanding elements */
+	/* Check for outstanding elements */
+	BUG_ON(pool->curr_nr != pool->min_nr);
 	free_pool(pool);
 }
 EXPORT_SYMBOL(mempool_destroy);
@@ -289,3 +289,45 @@
 	kmem_cache_free(mem, element);
 }
 EXPORT_SYMBOL(mempool_free_slab);
+
+/*
+ * A commonly used alloc and free fn that kmalloc/kfrees the amount of memory
+ * specfied by pool_data
+ */
+void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data)
+{
+	size_t size = (size_t)(long)pool_data;
+	return kmalloc(size, gfp_mask);
+}
+EXPORT_SYMBOL(mempool_kmalloc);
+
+void *mempool_kzalloc(gfp_t gfp_mask, void *pool_data)
+{
+	size_t size = (size_t) pool_data;
+	return kzalloc(size, gfp_mask);
+}
+EXPORT_SYMBOL(mempool_kzalloc);
+
+void mempool_kfree(void *element, void *pool_data)
+{
+	kfree(element);
+}
+EXPORT_SYMBOL(mempool_kfree);
+
+/*
+ * A simple mempool-backed page allocator that allocates pages
+ * of the order specified by pool_data.
+ */
+void *mempool_alloc_pages(gfp_t gfp_mask, void *pool_data)
+{
+	int order = (int)(long)pool_data;
+	return alloc_pages(gfp_mask, order);
+}
+EXPORT_SYMBOL(mempool_alloc_pages);
+
+void mempool_free_pages(void *element, void *pool_data)
+{
+	int order = (int)(long)pool_data;
+	__free_pages(element, order);
+}
+EXPORT_SYMBOL(mempool_free_pages);
diff --git a/mm/mmzone.c b/mm/mmzone.c
new file mode 100644
index 0000000..b022370
--- /dev/null
+++ b/mm/mmzone.c
@@ -0,0 +1,50 @@
+/*
+ * linux/mm/mmzone.c
+ *
+ * management codes for pgdats and zones.
+ */
+
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/mmzone.h>
+#include <linux/module.h>
+
+struct pglist_data *first_online_pgdat(void)
+{
+	return NODE_DATA(first_online_node);
+}
+
+EXPORT_SYMBOL(first_online_pgdat);
+
+struct pglist_data *next_online_pgdat(struct pglist_data *pgdat)
+{
+	int nid = next_online_node(pgdat->node_id);
+
+	if (nid == MAX_NUMNODES)
+		return NULL;
+	return NODE_DATA(nid);
+}
+EXPORT_SYMBOL(next_online_pgdat);
+
+
+/*
+ * next_zone - helper magic for for_each_zone()
+ */
+struct zone *next_zone(struct zone *zone)
+{
+	pg_data_t *pgdat = zone->zone_pgdat;
+
+	if (zone < pgdat->node_zones + MAX_NR_ZONES - 1)
+		zone++;
+	else {
+		pgdat = next_online_pgdat(pgdat);
+		if (pgdat)
+			zone = pgdat->node_zones;
+		else
+			zone = NULL;
+	}
+	return zone;
+}
+EXPORT_SYMBOL(next_zone);
+
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 338a02b..dc523a1 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -49,7 +49,6 @@
 EXPORT_SYMBOL(node_online_map);
 nodemask_t node_possible_map __read_mostly = NODE_MASK_ALL;
 EXPORT_SYMBOL(node_possible_map);
-struct pglist_data *pgdat_list __read_mostly;
 unsigned long totalram_pages __read_mostly;
 unsigned long totalhigh_pages __read_mostly;
 long nr_swap_pages;
@@ -1201,7 +1200,7 @@
 	pg_data_t *pgdat;
 	unsigned int pages = 0;
 
-	for_each_pgdat(pgdat)
+	for_each_online_pgdat(pgdat)
 		pages += pgdat->node_zones[ZONE_HIGHMEM].free_pages;
 
 	return pages;
@@ -1343,7 +1342,7 @@
 	*active = 0;
 	*inactive = 0;
 	*free = 0;
-	for_each_pgdat(pgdat) {
+	for_each_online_pgdat(pgdat) {
 		unsigned long l, m, n;
 		__get_zone_counts(&l, &m, &n, pgdat);
 		*active += l;
@@ -2042,7 +2041,6 @@
 	zone_wait_table_init(zone, size);
 	pgdat->nr_zones = zone_idx(zone) + 1;
 
-	zone->zone_mem_map = pfn_to_page(zone_start_pfn);
 	zone->zone_start_pfn = zone_start_pfn;
 
 	memmap_init(size, pgdat->node_id, zone_idx(zone), zone_start_pfn);
@@ -2170,8 +2168,9 @@
 {
 	pg_data_t *pgdat;
 	loff_t node = *pos;
-
-	for (pgdat = pgdat_list; pgdat && node; pgdat = pgdat->pgdat_next)
+	for (pgdat = first_online_pgdat();
+	     pgdat && node;
+	     pgdat = next_online_pgdat(pgdat))
 		--node;
 
 	return pgdat;
@@ -2182,7 +2181,7 @@
 	pg_data_t *pgdat = (pg_data_t *)arg;
 
 	(*pos)++;
-	return pgdat->pgdat_next;
+	return next_online_pgdat(pgdat);
 }
 
 static void frag_stop(struct seq_file *m, void *arg)
@@ -2483,7 +2482,7 @@
 	struct pglist_data *pgdat;
 	int j, idx;
 
-	for_each_pgdat(pgdat) {
+	for_each_online_pgdat(pgdat) {
 		for (j = 0; j < MAX_NR_ZONES; j++) {
 			struct zone *zone = pgdat->node_zones + j;
 			unsigned long present_pages = zone->present_pages;
@@ -2745,3 +2744,44 @@
 
 	return table;
 }
+
+#ifdef CONFIG_OUT_OF_LINE_PFN_TO_PAGE
+/*
+ * pfn <-> page translation. out-of-line version.
+ * (see asm-generic/memory_model.h)
+ */
+#if defined(CONFIG_FLATMEM)
+struct page *pfn_to_page(unsigned long pfn)
+{
+	return mem_map + (pfn - ARCH_PFN_OFFSET);
+}
+unsigned long page_to_pfn(struct page *page)
+{
+	return (page - mem_map) + ARCH_PFN_OFFSET;
+}
+#elif defined(CONFIG_DISCONTIGMEM)
+struct page *pfn_to_page(unsigned long pfn)
+{
+	int nid = arch_pfn_to_nid(pfn);
+	return NODE_DATA(nid)->node_mem_map + arch_local_page_offset(pfn,nid);
+}
+unsigned long page_to_pfn(struct page *page)
+{
+	struct pglist_data *pgdat = NODE_DATA(page_to_nid(page));
+	return (page - pgdat->node_mem_map) + pgdat->node_start_pfn;
+}
+#elif defined(CONFIG_SPARSEMEM)
+struct page *pfn_to_page(unsigned long pfn)
+{
+	return __section_mem_map_addr(__pfn_to_section(pfn)) + pfn;
+}
+
+unsigned long page_to_pfn(struct page *page)
+{
+	long section_id = page_to_section(page);
+	return page - __section_mem_map_addr(__nr_to_section(section_id));
+}
+#endif /* CONFIG_FLATMEM/DISCONTIGMME/SPARSEMEM */
+EXPORT_SYMBOL(pfn_to_page);
+EXPORT_SYMBOL(page_to_pfn);
+#endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */
diff --git a/mm/slab.c b/mm/slab.c
index 6818374..4cbf8bb 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3311,7 +3311,7 @@
 	 * and we have no way of figuring out how to fix the array
 	 * that we have allocated then....
 	 */
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		int node = cpu_to_node(i);
 
 		if (node_online(node))
@@ -3398,7 +3398,7 @@
 	/*
 	 * We allocate for all cpus so we cannot use for online cpu here.
 	 */
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 	    kfree(p->ptrs[i]);
 	kfree(p);
 }
diff --git a/mm/swap.c b/mm/swap.c
index 91b7e20..88895c2 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -512,7 +512,7 @@
 
 	spin_lock(&fbc->lock);
 	ret = fbc->count;
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		long *pcount = per_cpu_ptr(fbc->counters, cpu);
 		ret += *pcount;
 	}
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 39aa9d1..e5fd538 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -397,18 +397,24 @@
 
 	p = swap_info_get(entry);
 	if (p) {
-		if (swap_entry_free(p, swp_offset(entry)) == 1)
-			page = find_trylock_page(&swapper_space, entry.val);
+		if (swap_entry_free(p, swp_offset(entry)) == 1) {
+			page = find_get_page(&swapper_space, entry.val);
+			if (page && unlikely(TestSetPageLocked(page))) {
+				page_cache_release(page);
+				page = NULL;
+			}
+		}
 		spin_unlock(&swap_lock);
 	}
 	if (page) {
 		int one_user;
 
 		BUG_ON(PagePrivate(page));
-		page_cache_get(page);
 		one_user = (page_count(page) == 2);
 		/* Only cache user (+us), or swap space full? Free it! */
-		if (!PageWriteback(page) && (one_user || vm_swap_full())) {
+		/* Also recheck PageSwapCache after page is locked (above) */
+		if (PageSwapCache(page) && !PageWriteback(page) &&
+					(one_user || vm_swap_full())) {
 			delete_from_swap_cache(page);
 			SetPageDirty(page);
 		}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 78865c8..acdf001 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1305,7 +1305,7 @@
 
 	current->reclaim_state = &reclaim_state;
 repeat:
-	for_each_pgdat(pgdat) {
+	for_each_online_pgdat(pgdat) {
 		unsigned long freed;
 
 		freed = balance_pgdat(pgdat, nr_to_free, 0);
@@ -1335,7 +1335,7 @@
 	cpumask_t mask;
 
 	if (action == CPU_ONLINE) {
-		for_each_pgdat(pgdat) {
+		for_each_online_pgdat(pgdat) {
 			mask = node_to_cpumask(pgdat->node_id);
 			if (any_online_cpu(mask) != NR_CPUS)
 				/* One of our CPUs online: restore mask */
@@ -1351,7 +1351,7 @@
 	pg_data_t *pgdat;
 
 	swap_setup();
-	for_each_pgdat(pgdat) {
+	for_each_online_pgdat(pgdat) {
 		pid_t pid;
 
 		pid = kernel_thread(kswapd, pgdat, CLONE_KERNEL);
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 697ac55..7b1eb9a 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1819,6 +1819,22 @@
 	return rc;
 }
 
+
+#ifdef CONFIG_COMPAT
+static int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	/*
+	 * All Appletalk ioctls except SIOCATALKDIFADDR are standard.  And
+	 * SIOCATALKDIFADDR is handled by upper layer as well, so there is
+	 * nothing to do.  Eventually SIOCATALKDIFADDR should be moved
+	 * here so there is no generic SIOCPROTOPRIVATE translation in the
+	 * system.
+	 */
+	return -ENOIOCTLCMD;
+}
+#endif
+
+
 static struct net_proto_family atalk_family_ops = {
 	.family		= PF_APPLETALK,
 	.create		= atalk_create,
@@ -1836,6 +1852,9 @@
 	.getname	= atalk_getname,
 	.poll		= datagram_poll,
 	.ioctl		= atalk_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= atalk_compat_ioctl,
+#endif
 	.listen		= sock_no_listen,
 	.shutdown	= sock_no_shutdown,
 	.setsockopt	= sock_no_setsockopt,
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9106354..a49a697 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -73,23 +73,23 @@
 struct hci_proto *hci_proto[HCI_MAX_PROTO];
 
 /* HCI notifiers list */
-static struct notifier_block *hci_notifier;
+static ATOMIC_NOTIFIER_HEAD(hci_notifier);
 
 /* ---- HCI notifications ---- */
 
 int hci_register_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_register(&hci_notifier, nb);
+	return atomic_notifier_chain_register(&hci_notifier, nb);
 }
 
 int hci_unregister_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_unregister(&hci_notifier, nb);
+	return atomic_notifier_chain_unregister(&hci_notifier, nb);
 }
 
 static void hci_notify(struct hci_dev *hdev, int event)
 {
-	notifier_call_chain(&hci_notifier, event, hdev);
+	atomic_notifier_call_chain(&hci_notifier, event, hdev);
 }
 
 /* ---- HCI requests ---- */
diff --git a/net/bridge/netfilter/ebt_802_3.c b/net/bridge/netfilter/ebt_802_3.c
index 468ebdf..d42f63f 100644
--- a/net/bridge/netfilter/ebt_802_3.c
+++ b/net/bridge/netfilter/ebt_802_3.c
@@ -58,16 +58,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_802_3_init(void)
 {
 	return ebt_register_match(&filter_802_3);
 }
 
-static void __exit fini(void)
+static void __exit ebt_802_3_fini(void)
 {
 	ebt_unregister_match(&filter_802_3);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_802_3_init);
+module_exit(ebt_802_3_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c
index 5a1f5e3..a614485 100644
--- a/net/bridge/netfilter/ebt_among.c
+++ b/net/bridge/netfilter/ebt_among.c
@@ -213,16 +213,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_among_init(void)
 {
 	return ebt_register_match(&filter_among);
 }
 
-static void __exit fini(void)
+static void __exit ebt_among_fini(void)
 {
 	ebt_unregister_match(&filter_among);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_among_init);
+module_exit(ebt_among_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c
index b94c48c..a6c81d9 100644
--- a/net/bridge/netfilter/ebt_arp.c
+++ b/net/bridge/netfilter/ebt_arp.c
@@ -125,16 +125,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_arp_init(void)
 {
 	return ebt_register_match(&filter_arp);
 }
 
-static void __exit fini(void)
+static void __exit ebt_arp_fini(void)
 {
 	ebt_unregister_match(&filter_arp);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_arp_init);
+module_exit(ebt_arp_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_arpreply.c b/net/bridge/netfilter/ebt_arpreply.c
index b934de9..d19fc4b 100644
--- a/net/bridge/netfilter/ebt_arpreply.c
+++ b/net/bridge/netfilter/ebt_arpreply.c
@@ -82,16 +82,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_arpreply_init(void)
 {
 	return ebt_register_target(&reply_target);
 }
 
-static void __exit fini(void)
+static void __exit ebt_arpreply_fini(void)
 {
 	ebt_unregister_target(&reply_target);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_arpreply_init);
+module_exit(ebt_arpreply_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c
index f546308..4582659 100644
--- a/net/bridge/netfilter/ebt_dnat.c
+++ b/net/bridge/netfilter/ebt_dnat.c
@@ -61,16 +61,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_dnat_init(void)
 {
 	return ebt_register_target(&dnat);
 }
 
-static void __exit fini(void)
+static void __exit ebt_dnat_fini(void)
 {
 	ebt_unregister_target(&dnat);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_dnat_init);
+module_exit(ebt_dnat_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c
index dc5d0b2..65b665c 100644
--- a/net/bridge/netfilter/ebt_ip.c
+++ b/net/bridge/netfilter/ebt_ip.c
@@ -112,16 +112,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_ip_init(void)
 {
 	return ebt_register_match(&filter_ip);
 }
 
-static void __exit fini(void)
+static void __exit ebt_ip_fini(void)
 {
 	ebt_unregister_match(&filter_ip);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_ip_init);
+module_exit(ebt_ip_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_limit.c b/net/bridge/netfilter/ebt_limit.c
index 637c884..d48fa5c 100644
--- a/net/bridge/netfilter/ebt_limit.c
+++ b/net/bridge/netfilter/ebt_limit.c
@@ -98,16 +98,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_limit_init(void)
 {
 	return ebt_register_match(&ebt_limit_reg);
 }
 
-static void __exit fini(void)
+static void __exit ebt_limit_fini(void)
 {
 	ebt_unregister_match(&ebt_limit_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_limit_init);
+module_exit(ebt_limit_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index 288ff1d..d159c92 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -188,7 +188,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_log_init(void)
 {
 	int ret;
 
@@ -205,12 +205,12 @@
 	return 0;
 }
 
-static void __exit fini(void)
+static void __exit ebt_log_fini(void)
 {
 	nf_log_unregister_logger(&ebt_log_logger);
 	ebt_unregister_watcher(&log);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_log_init);
+module_exit(ebt_log_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c
index c93d35a..770c0df 100644
--- a/net/bridge/netfilter/ebt_mark.c
+++ b/net/bridge/netfilter/ebt_mark.c
@@ -52,16 +52,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_mark_init(void)
 {
 	return ebt_register_target(&mark_target);
 }
 
-static void __exit fini(void)
+static void __exit ebt_mark_fini(void)
 {
 	ebt_unregister_target(&mark_target);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_mark_init);
+module_exit(ebt_mark_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_mark_m.c b/net/bridge/netfilter/ebt_mark_m.c
index 625102d..a6413e4 100644
--- a/net/bridge/netfilter/ebt_mark_m.c
+++ b/net/bridge/netfilter/ebt_mark_m.c
@@ -47,16 +47,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_mark_m_init(void)
 {
 	return ebt_register_match(&filter_mark);
 }
 
-static void __exit fini(void)
+static void __exit ebt_mark_m_fini(void)
 {
 	ebt_unregister_match(&filter_mark);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_mark_m_init);
+module_exit(ebt_mark_m_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_pkttype.c b/net/bridge/netfilter/ebt_pkttype.c
index ecd3b42..4fffd70 100644
--- a/net/bridge/netfilter/ebt_pkttype.c
+++ b/net/bridge/netfilter/ebt_pkttype.c
@@ -44,16 +44,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_pkttype_init(void)
 {
 	return ebt_register_match(&filter_pkttype);
 }
 
-static void __exit fini(void)
+static void __exit ebt_pkttype_fini(void)
 {
 	ebt_unregister_match(&filter_pkttype);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_pkttype_init);
+module_exit(ebt_pkttype_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c
index 1538b43..9f378ea 100644
--- a/net/bridge/netfilter/ebt_redirect.c
+++ b/net/bridge/netfilter/ebt_redirect.c
@@ -66,16 +66,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_redirect_init(void)
 {
 	return ebt_register_target(&redirect_target);
 }
 
-static void __exit fini(void)
+static void __exit ebt_redirect_fini(void)
 {
 	ebt_unregister_target(&redirect_target);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_redirect_init);
+module_exit(ebt_redirect_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c
index 1529bdc..cbb33e2 100644
--- a/net/bridge/netfilter/ebt_snat.c
+++ b/net/bridge/netfilter/ebt_snat.c
@@ -61,16 +61,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_snat_init(void)
 {
 	return ebt_register_target(&snat);
 }
 
-static void __exit fini(void)
+static void __exit ebt_snat_fini(void)
 {
 	ebt_unregister_target(&snat);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_snat_init);
+module_exit(ebt_snat_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c
index 0248c67..a0bed82 100644
--- a/net/bridge/netfilter/ebt_stp.c
+++ b/net/bridge/netfilter/ebt_stp.c
@@ -180,16 +180,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_stp_init(void)
 {
 	return ebt_register_match(&filter_stp);
 }
 
-static void __exit fini(void)
+static void __exit ebt_stp_fini(void)
 {
 	ebt_unregister_match(&filter_stp);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_stp_init);
+module_exit(ebt_stp_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
index 802baf7..ee5a517 100644
--- a/net/bridge/netfilter/ebt_ulog.c
+++ b/net/bridge/netfilter/ebt_ulog.c
@@ -281,7 +281,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_ulog_init(void)
 {
 	int i, ret = 0;
 
@@ -316,7 +316,7 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit ebt_ulog_fini(void)
 {
 	ebt_ulog_buff_t *ub;
 	int i;
@@ -337,8 +337,8 @@
 	sock_release(ebtulognl->sk_socket);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_ulog_init);
+module_exit(ebt_ulog_fini);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
 MODULE_DESCRIPTION("ebtables userspace logging module for bridged Ethernet"
diff --git a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c
index db60d73..a2b4528 100644
--- a/net/bridge/netfilter/ebt_vlan.c
+++ b/net/bridge/netfilter/ebt_vlan.c
@@ -178,7 +178,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ebt_vlan_init(void)
 {
 	DEBUG_MSG("ebtables 802.1Q extension module v"
 		  MODULE_VERS "\n");
@@ -186,10 +186,10 @@
 	return ebt_register_match(&filter_vlan);
 }
 
-static void __exit fini(void)
+static void __exit ebt_vlan_fini(void)
 {
 	ebt_unregister_match(&filter_vlan);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_vlan_init);
+module_exit(ebt_vlan_fini);
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c
index 1767c94..9a6e548 100644
--- a/net/bridge/netfilter/ebtable_broute.c
+++ b/net/bridge/netfilter/ebtable_broute.c
@@ -62,7 +62,7 @@
 	return 0; /* bridge it */
 }
 
-static int __init init(void)
+static int __init ebtable_broute_init(void)
 {
 	int ret;
 
@@ -74,13 +74,13 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit ebtable_broute_fini(void)
 {
 	br_should_route_hook = NULL;
 	synchronize_net();
 	ebt_unregister_table(&broute_table);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebtable_broute_init);
+module_exit(ebtable_broute_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
index c18666e..3d5bd44 100644
--- a/net/bridge/netfilter/ebtable_filter.c
+++ b/net/bridge/netfilter/ebtable_filter.c
@@ -91,7 +91,7 @@
 	},
 };
 
-static int __init init(void)
+static int __init ebtable_filter_init(void)
 {
 	int i, j, ret;
 
@@ -109,7 +109,7 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit ebtable_filter_fini(void)
 {
 	int i;
 
@@ -118,6 +118,6 @@
 	ebt_unregister_table(&frame_filter);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebtable_filter_init);
+module_exit(ebtable_filter_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
index 828cac2..04dd42e 100644
--- a/net/bridge/netfilter/ebtable_nat.c
+++ b/net/bridge/netfilter/ebtable_nat.c
@@ -98,7 +98,7 @@
 	},
 };
 
-static int __init init(void)
+static int __init ebtable_nat_init(void)
 {
 	int i, ret, j;
 
@@ -116,7 +116,7 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit ebtable_nat_fini(void)
 {
 	int i;
 
@@ -125,6 +125,6 @@
 	ebt_unregister_table(&frame_nat);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebtable_nat_init);
+module_exit(ebtable_nat_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 9979533..01eae97 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -1487,7 +1487,7 @@
 	.get		= do_ebt_get_ctl,
 };
 
-static int __init init(void)
+static int __init ebtables_init(void)
 {
 	int ret;
 
@@ -1501,7 +1501,7 @@
 	return 0;
 }
 
-static void __exit fini(void)
+static void __exit ebtables_fini(void)
 {
 	nf_unregister_sockopt(&ebt_sockopts);
 	printk(KERN_NOTICE "Ebtables v2.0 unregistered\n");
@@ -1516,6 +1516,6 @@
 EXPORT_SYMBOL(ebt_register_target);
 EXPORT_SYMBOL(ebt_unregister_target);
 EXPORT_SYMBOL(ebt_do_table);
-module_init(init);
-module_exit(fini);
+module_init(ebtables_init);
+module_exit(ebtables_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/core/dev.c b/net/core/dev.c
index 8e1dc30..434220d 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -193,7 +193,7 @@
  *	Our notifier list
  */
 
-static struct notifier_block *netdev_chain;
+static BLOCKING_NOTIFIER_HEAD(netdev_chain);
 
 /*
  *	Device drivers call our routines to queue packets here. We empty the
@@ -736,7 +736,8 @@
 	if (!err) {
 		hlist_del(&dev->name_hlist);
 		hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
-		notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
+		blocking_notifier_call_chain(&netdev_chain,
+				NETDEV_CHANGENAME, dev);
 	}
 
 	return err;
@@ -750,7 +751,7 @@
  */
 void netdev_features_change(struct net_device *dev)
 {
-	notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev);
+	blocking_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev);
 }
 EXPORT_SYMBOL(netdev_features_change);
 
@@ -765,7 +766,8 @@
 void netdev_state_change(struct net_device *dev)
 {
 	if (dev->flags & IFF_UP) {
-		notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
+		blocking_notifier_call_chain(&netdev_chain,
+				NETDEV_CHANGE, dev);
 		rtmsg_ifinfo(RTM_NEWLINK, dev, 0);
 	}
 }
@@ -862,7 +864,7 @@
 		/*
 		 *	... and announce new interface.
 		 */
-		notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
+		blocking_notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
 	}
 	return ret;
 }
@@ -885,7 +887,7 @@
 	 *	Tell people we are going down, so that they can
 	 *	prepare to death, when device is still operating.
 	 */
-	notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev);
+	blocking_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev);
 
 	dev_deactivate(dev);
 
@@ -922,7 +924,7 @@
 	/*
 	 * Tell people we are down
 	 */
-	notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
+	blocking_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
 
 	return 0;
 }
@@ -953,7 +955,7 @@
 	int err;
 
 	rtnl_lock();
-	err = notifier_chain_register(&netdev_chain, nb);
+	err = blocking_notifier_chain_register(&netdev_chain, nb);
 	if (!err) {
 		for (dev = dev_base; dev; dev = dev->next) {
 			nb->notifier_call(nb, NETDEV_REGISTER, dev);
@@ -981,7 +983,7 @@
 	int err;
 
 	rtnl_lock();
-	err = notifier_chain_unregister(&netdev_chain, nb);
+	err = blocking_notifier_chain_unregister(&netdev_chain, nb);
 	rtnl_unlock();
 	return err;
 }
@@ -992,12 +994,12 @@
  *      @v:   pointer passed unmodified to notifier function
  *
  *	Call all network notifier blocks.  Parameters and return value
- *	are as for notifier_call_chain().
+ *	are as for blocking_notifier_call_chain().
  */
 
 int call_netdevice_notifiers(unsigned long val, void *v)
 {
-	return notifier_call_chain(&netdev_chain, val, v);
+	return blocking_notifier_call_chain(&netdev_chain, val, v);
 }
 
 /* When > 0 there are consumers of rx skb time stamps */
@@ -1078,6 +1080,70 @@
 	rcu_read_unlock();
 }
 
+
+void __netif_schedule(struct net_device *dev)
+{
+	if (!test_and_set_bit(__LINK_STATE_SCHED, &dev->state)) {
+		unsigned long flags;
+		struct softnet_data *sd;
+
+		local_irq_save(flags);
+		sd = &__get_cpu_var(softnet_data);
+		dev->next_sched = sd->output_queue;
+		sd->output_queue = dev;
+		raise_softirq_irqoff(NET_TX_SOFTIRQ);
+		local_irq_restore(flags);
+	}
+}
+EXPORT_SYMBOL(__netif_schedule);
+
+void __netif_rx_schedule(struct net_device *dev)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	dev_hold(dev);
+	list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
+	if (dev->quota < 0)
+		dev->quota += dev->weight;
+	else
+		dev->quota = dev->weight;
+	__raise_softirq_irqoff(NET_RX_SOFTIRQ);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(__netif_rx_schedule);
+
+void dev_kfree_skb_any(struct sk_buff *skb)
+{
+	if (in_irq() || irqs_disabled())
+		dev_kfree_skb_irq(skb);
+	else
+		dev_kfree_skb(skb);
+}
+EXPORT_SYMBOL(dev_kfree_skb_any);
+
+
+/* Hot-plugging. */
+void netif_device_detach(struct net_device *dev)
+{
+	if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) &&
+	    netif_running(dev)) {
+		netif_stop_queue(dev);
+	}
+}
+EXPORT_SYMBOL(netif_device_detach);
+
+void netif_device_attach(struct net_device *dev)
+{
+	if (!test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) &&
+	    netif_running(dev)) {
+		netif_wake_queue(dev);
+ 		__netdev_watchdog_up(dev);
+	}
+}
+EXPORT_SYMBOL(netif_device_attach);
+
+
 /*
  * Invalidate hardware checksum when packet is to be mangled, and
  * complete checksum manually on outgoing path.
@@ -2242,7 +2308,8 @@
 	if (dev->flags & IFF_UP &&
 	    ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI |
 					  IFF_VOLATILE)))
-		notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
+		blocking_notifier_call_chain(&netdev_chain,
+				NETDEV_CHANGE, dev);
 
 	if ((flags ^ dev->gflags) & IFF_PROMISC) {
 		int inc = (flags & IFF_PROMISC) ? +1 : -1;
@@ -2286,8 +2353,8 @@
 	else
 		dev->mtu = new_mtu;
 	if (!err && dev->flags & IFF_UP)
-		notifier_call_chain(&netdev_chain,
-				    NETDEV_CHANGEMTU, dev);
+		blocking_notifier_call_chain(&netdev_chain,
+				NETDEV_CHANGEMTU, dev);
 	return err;
 }
 
@@ -2303,7 +2370,8 @@
 		return -ENODEV;
 	err = dev->set_mac_address(dev, sa);
 	if (!err)
-		notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
+		blocking_notifier_call_chain(&netdev_chain,
+				NETDEV_CHANGEADDR, dev);
 	return err;
 }
 
@@ -2359,7 +2427,7 @@
 				return -EINVAL;
 			memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data,
 			       min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len));
-			notifier_call_chain(&netdev_chain,
+			blocking_notifier_call_chain(&netdev_chain,
 					    NETDEV_CHANGEADDR, dev);
 			return 0;
 
@@ -2813,7 +2881,7 @@
 	write_unlock_bh(&dev_base_lock);
 
 	/* Notify protocols, that a new device appeared. */
-	notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
+	blocking_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
 
 	/* Finish registration after unlock */
 	net_set_todo(dev);
@@ -2892,7 +2960,7 @@
 			rtnl_lock();
 
 			/* Rebroadcast unregister notification */
-			notifier_call_chain(&netdev_chain,
+			blocking_notifier_call_chain(&netdev_chain,
 					    NETDEV_UNREGISTER, dev);
 
 			if (test_bit(__LINK_STATE_LINKWATCH_PENDING,
@@ -3148,7 +3216,7 @@
 	/* Notify protocols, that we are about to destroy
 	   this device. They should clean all the things.
 	*/
-	notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
+	blocking_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
 	
 	/*
 	 *	Flush the multicast chain
diff --git a/net/core/request_sock.c b/net/core/request_sock.c
index 98f0fc9..1e44eda 100644
--- a/net/core/request_sock.c
+++ b/net/core/request_sock.c
@@ -51,7 +51,7 @@
 
 	get_random_bytes(&lopt->hash_rnd, sizeof(lopt->hash_rnd));
 	rwlock_init(&queue->syn_wait_lock);
-	queue->rskq_accept_head = queue->rskq_accept_head = NULL;
+	queue->rskq_accept_head = NULL;
 	lopt->nr_table_entries = nr_table_entries;
 
 	write_lock_bh(&queue->syn_wait_lock);
diff --git a/net/core/sock.c b/net/core/sock.c
index e110b90..ed2afdb 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -187,6 +187,99 @@
 }
 
 
+int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+	int err = 0;
+	int skb_len;
+
+	/* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
+	   number of warnings when compiling with -W --ANK
+	 */
+	if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
+	    (unsigned)sk->sk_rcvbuf) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* It would be deadlock, if sock_queue_rcv_skb is used
+	   with socket lock! We assume that users of this
+	   function are lock free.
+	*/
+	err = sk_filter(sk, skb, 1);
+	if (err)
+		goto out;
+
+	skb->dev = NULL;
+	skb_set_owner_r(skb, sk);
+
+	/* Cache the SKB length before we tack it onto the receive
+	 * queue.  Once it is added it no longer belongs to us and
+	 * may be freed by other threads of control pulling packets
+	 * from the queue.
+	 */
+	skb_len = skb->len;
+
+	skb_queue_tail(&sk->sk_receive_queue, skb);
+
+	if (!sock_flag(sk, SOCK_DEAD))
+		sk->sk_data_ready(sk, skb_len);
+out:
+	return err;
+}
+EXPORT_SYMBOL(sock_queue_rcv_skb);
+
+int sk_receive_skb(struct sock *sk, struct sk_buff *skb)
+{
+	int rc = NET_RX_SUCCESS;
+
+	if (sk_filter(sk, skb, 0))
+		goto discard_and_relse;
+
+	skb->dev = NULL;
+
+	bh_lock_sock(sk);
+	if (!sock_owned_by_user(sk))
+		rc = sk->sk_backlog_rcv(sk, skb);
+	else
+		sk_add_backlog(sk, skb);
+	bh_unlock_sock(sk);
+out:
+	sock_put(sk);
+	return rc;
+discard_and_relse:
+	kfree_skb(skb);
+	goto out;
+}
+EXPORT_SYMBOL(sk_receive_skb);
+
+struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie)
+{
+	struct dst_entry *dst = sk->sk_dst_cache;
+
+	if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) {
+		sk->sk_dst_cache = NULL;
+		dst_release(dst);
+		return NULL;
+	}
+
+	return dst;
+}
+EXPORT_SYMBOL(__sk_dst_check);
+
+struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie)
+{
+	struct dst_entry *dst = sk_dst_get(sk);
+
+	if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) {
+		sk_dst_reset(sk);
+		dst_release(dst);
+		return NULL;
+	}
+
+	return dst;
+}
+EXPORT_SYMBOL(sk_dst_check);
+
 /*
  *	This is meant for all protocols to use and covers goings on
  *	at the socket level. Everything here is generic.
@@ -292,7 +385,21 @@
 				val = sysctl_rmem_max;
 set_rcvbuf:
 			sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
-			/* FIXME: is this lower bound the right one? */
+			/*
+			 * We double it on the way in to account for
+			 * "struct sk_buff" etc. overhead.   Applications
+			 * assume that the SO_RCVBUF setting they make will
+			 * allow that much actual data to be received on that
+			 * socket.
+			 *
+			 * Applications are unaware that "struct sk_buff" and
+			 * other overheads allocate from the receive buffer
+			 * during socket buffer allocation.
+			 *
+			 * And after considering the possible alternatives,
+			 * returning the value we actually used in getsockopt
+			 * is the most desirable behavior.
+			 */
 			if ((val * 2) < SOCK_MIN_RCVBUF)
 				sk->sk_rcvbuf = SOCK_MIN_RCVBUF;
 			else
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index e3dd30d..b39e2a5 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -204,7 +204,7 @@
 	if (rc) {
 		kfree(opt->dccpop_sc->dccpoc_val);
 		kfree(opt->dccpop_sc);
-		opt->dccpop_sc = 0;
+		opt->dccpop_sc = NULL;
 		return rc;
 	}
 
@@ -322,7 +322,7 @@
 	opt->dccpop_type = type == DCCPO_CHANGE_L ? DCCPO_CONFIRM_R :
 						    DCCPO_CONFIRM_L;
 	opt->dccpop_feat = feature;
-	opt->dccpop_val	 = 0;
+	opt->dccpop_val	 = NULL;
 	opt->dccpop_len	 = 0;
 
 	/* change feature */
@@ -523,7 +523,7 @@
 		 * once...
 		 */
 		/* the master socket no longer needs to worry about confirms */
-		opt->dccpop_sc = 0; /* it's not a memleak---new socket has it */
+		opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */
 
 		/* reset state for a new socket */
 		opt->dccpop_conf = 0;
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index cc7b9d9..a26ff9f 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -68,7 +68,7 @@
 
 static DEFINE_RWLOCK(dndev_lock);
 static struct net_device *decnet_default_device;
-static struct notifier_block *dnaddr_chain;
+static BLOCKING_NOTIFIER_HEAD(dnaddr_chain);
 
 static struct dn_dev *dn_dev_create(struct net_device *dev, int *err);
 static void dn_dev_delete(struct net_device *dev);
@@ -446,7 +446,7 @@
 	}
 
 	rtmsg_ifa(RTM_DELADDR, ifa1);
-	notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1);
+	blocking_notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1);
 	if (destroy) {
 		dn_dev_free_ifa(ifa1);
 
@@ -481,7 +481,7 @@
 	dn_db->ifa_list = ifa;
 
 	rtmsg_ifa(RTM_NEWADDR, ifa);
-	notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
+	blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
 
 	return 0;
 }
@@ -620,7 +620,7 @@
 	}
 	write_unlock(&dndev_lock);
 	if (old)
-		dev_put(dev);
+		dev_put(old);
 	return rv;
 }
 
@@ -1285,12 +1285,12 @@
 
 int register_dnaddr_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_register(&dnaddr_chain, nb);
+	return blocking_notifier_chain_register(&dnaddr_chain, nb);
 }
 
 int unregister_dnaddr_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_unregister(&dnaddr_chain, nb);
+	return blocking_notifier_chain_unregister(&dnaddr_chain, nb);
 }
 
 #ifdef CONFIG_PROC_FS
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
index 16a5a31..74133ec 100644
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -133,7 +133,7 @@
 	.priority	= NF_DN_PRI_DNRTMSG,
 };
 
-static int __init init(void)
+static int __init dn_rtmsg_init(void)
 {
 	int rv = 0;
 
@@ -152,7 +152,7 @@
 	return rv;
 }
 
-static void __exit fini(void)
+static void __exit dn_rtmsg_fini(void)
 {
 	nf_unregister_hook(&dnrmg_ops);
 	sock_release(dnrmg->sk_socket);
@@ -164,6 +164,6 @@
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_DNRTMSG);
 
-module_init(init);
-module_exit(fini);
+module_init(dn_rtmsg_init);
+module_exit(dn_rtmsg_fini);
 
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index c792994..8682656 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -42,6 +42,7 @@
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
 #include <linux/bitops.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -49,6 +50,7 @@
 static const struct proto_ops econet_ops;
 static struct hlist_head econet_sklist;
 static DEFINE_RWLOCK(econet_lock);
+static DEFINE_MUTEX(econet_mutex);
 
 /* Since there are only 256 possible network numbers (or fewer, depends
    how you count) it makes sense to use a simple lookup table. */
@@ -124,6 +126,8 @@
 
 	msg->msg_namelen = sizeof(struct sockaddr_ec);
 
+	mutex_lock(&econet_mutex);
+
 	/*
 	 *	Call the generic datagram receiver. This handles all sorts
 	 *	of horrible races and re-entrancy so we can forget about it
@@ -174,6 +178,7 @@
 out_free:
 	skb_free_datagram(sk, skb);
 out:
+	mutex_unlock(&econet_mutex);
 	return err;
 }
 
@@ -184,8 +189,8 @@
 static int econet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
 	struct sockaddr_ec *sec = (struct sockaddr_ec *)uaddr;
-	struct sock *sk=sock->sk;
-	struct econet_sock *eo = ec_sk(sk);
+	struct sock *sk;
+	struct econet_sock *eo;
 	
 	/*
 	 *	Check legality
@@ -195,11 +200,18 @@
 	    sec->sec_family != AF_ECONET)
 		return -EINVAL;
 	
+	mutex_lock(&econet_mutex);
+
+	sk = sock->sk;
+	eo = ec_sk(sk);
+
 	eo->cb	    = sec->cb;
 	eo->port    = sec->port;
 	eo->station = sec->addr.station;
 	eo->net	    = sec->addr.net;
 
+	mutex_unlock(&econet_mutex);
+
 	return 0;
 }
 
@@ -284,6 +296,8 @@
 	 *	Get and verify the address. 
 	 */
 	 
+	mutex_lock(&econet_mutex);
+
 	if (saddr == NULL) {
 		struct econet_sock *eo = ec_sk(sk);
 
@@ -292,8 +306,10 @@
 		port	     = eo->port;
 		cb	     = eo->cb;
 	} else {
-		if (msg->msg_namelen < sizeof(struct sockaddr_ec)) 
+		if (msg->msg_namelen < sizeof(struct sockaddr_ec)) {
+			mutex_unlock(&econet_mutex);
 			return -EINVAL;
+		}
 		addr.station = saddr->addr.station;
 		addr.net = saddr->addr.net;
 		port = saddr->port;
@@ -304,19 +320,21 @@
 	dev = net2dev_map[addr.net];
 
 	/* If not directly reachable, use some default */
-	if (dev == NULL)
-	{
+	if (dev == NULL) {
 		dev = net2dev_map[0];
 		/* No interfaces at all? */
-		if (dev == NULL)
+		if (dev == NULL) {
+			mutex_unlock(&econet_mutex);
 			return -ENETDOWN;
+		}
 	}
 
-	if (len + 15 > dev->mtu)
+	if (len + 15 > dev->mtu) {
+		mutex_unlock(&econet_mutex);
 		return -EMSGSIZE;
+	}
 
-	if (dev->type == ARPHRD_ECONET)
-	{
+	if (dev->type == ARPHRD_ECONET) {
 		/* Real hardware Econet.  We're not worthy etc. */
 #ifdef CONFIG_ECONET_NATIVE
 		unsigned short proto = 0;
@@ -374,6 +392,7 @@
 		
 		dev_queue_xmit(skb);
 		dev_put(dev);
+		mutex_unlock(&econet_mutex);
 		return(len);
 
 	out_free:
@@ -384,14 +403,18 @@
 #else
 		err = -EPROTOTYPE;
 #endif
+		mutex_unlock(&econet_mutex);
+
 		return err;
 	}
 
 #ifdef CONFIG_ECONET_AUNUDP
 	/* AUN virtual Econet. */
 
-	if (udpsock == NULL)
+	if (udpsock == NULL) {
+		mutex_unlock(&econet_mutex);
 		return -ENETDOWN;		/* No socket - can't send */
+	}
 	
 	/* Make up a UDP datagram and hand it off to some higher intellect. */
 
@@ -438,8 +461,10 @@
 		void __user *base = msg->msg_iov[i].iov_base;
 		size_t len = msg->msg_iov[i].iov_len;
 		/* Check it now since we switch to KERNEL_DS later. */
-		if (!access_ok(VERIFY_READ, base, len))
+		if (!access_ok(VERIFY_READ, base, len)) {
+			mutex_unlock(&econet_mutex);
 			return -EFAULT;
+		}
 		iov[i+1].iov_base = base;
 		iov[i+1].iov_len = len;
 		size += len;
@@ -447,8 +472,11 @@
 
 	/* Get a skbuff (no data, just holds our cb information) */
 	if ((skb = sock_alloc_send_skb(sk, 0, 
-			     msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
+				       msg->msg_flags & MSG_DONTWAIT,
+				       &err)) == NULL) {
+		mutex_unlock(&econet_mutex);
 		return err;
+	}
 
 	eb = (struct ec_cb *)&skb->cb;
 
@@ -475,6 +503,8 @@
 #else
 	err = -EPROTOTYPE;
 #endif
+	mutex_unlock(&econet_mutex);
+
 	return err;
 }
 
@@ -485,18 +515,25 @@
 static int econet_getname(struct socket *sock, struct sockaddr *uaddr,
 			  int *uaddr_len, int peer)
 {
-	struct sock *sk = sock->sk;
-	struct econet_sock *eo = ec_sk(sk);
+	struct sock *sk;
+	struct econet_sock *eo;
 	struct sockaddr_ec *sec = (struct sockaddr_ec *)uaddr;
 
 	if (peer)
 		return -EOPNOTSUPP;
 
+	mutex_lock(&econet_mutex);
+
+	sk = sock->sk;
+	eo = ec_sk(sk);
+
 	sec->sec_family	  = AF_ECONET;
 	sec->port	  = eo->port;
 	sec->addr.station = eo->station;
 	sec->addr.net	  = eo->net;
 
+	mutex_unlock(&econet_mutex);
+
 	*uaddr_len = sizeof(*sec);
 	return 0;
 }
@@ -522,10 +559,13 @@
 
 static int econet_release(struct socket *sock)
 {
-	struct sock *sk = sock->sk;
+	struct sock *sk;
 
+	mutex_lock(&econet_mutex);
+
+	sk = sock->sk;
 	if (!sk)
-		return 0;
+		goto out_unlock;
 
 	econet_remove_socket(&econet_sklist, sk);
 
@@ -549,10 +589,14 @@
 		sk->sk_timer.expires  = jiffies + HZ;
 		sk->sk_timer.function = econet_destroy_timer;
 		add_timer(&sk->sk_timer);
-		return 0;
+
+		goto out_unlock;
 	}
 
 	sk_free(sk);
+
+out_unlock:
+	mutex_unlock(&econet_mutex);
 	return 0;
 }
 
@@ -608,6 +652,7 @@
 	struct ec_device *edev;
 	struct net_device *dev;
 	struct sockaddr_ec *sec;
+	int err;
 
 	/*
 	 *	Fetch the caller's info block into kernel space
@@ -621,38 +666,35 @@
 
 	sec = (struct sockaddr_ec *)&ifr.ifr_addr;
 
-	switch (cmd)
-	{
+	mutex_lock(&econet_mutex);
+
+	err = 0;
+	switch (cmd) {
 	case SIOCSIFADDR:
 		edev = dev->ec_ptr;
-		if (edev == NULL)
-		{
+		if (edev == NULL) {
 			/* Magic up a new one. */
 			edev = kmalloc(sizeof(struct ec_device), GFP_KERNEL);
 			if (edev == NULL) {
-				printk("af_ec: memory squeeze.\n");
-				dev_put(dev);
-				return -ENOMEM;
+				err = -ENOMEM;
+				break;
 			}
 			memset(edev, 0, sizeof(struct ec_device));
 			dev->ec_ptr = edev;
-		}
-		else
+		} else
 			net2dev_map[edev->net] = NULL;
 		edev->station = sec->addr.station;
 		edev->net = sec->addr.net;
 		net2dev_map[sec->addr.net] = dev;
 		if (!net2dev_map[0])
 			net2dev_map[0] = dev;
-		dev_put(dev);
-		return 0;
+		break;
 
 	case SIOCGIFADDR:
 		edev = dev->ec_ptr;
-		if (edev == NULL)
-		{
-			dev_put(dev);
-			return -ENODEV;
+		if (edev == NULL) {
+			err = -ENODEV;
+			break;
 		}
 		memset(sec, 0, sizeof(struct sockaddr_ec));
 		sec->addr.station = edev->station;
@@ -660,12 +702,19 @@
 		sec->sec_family = AF_ECONET;
 		dev_put(dev);
 		if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
-			return -EFAULT;
-		return 0;
+			err = -EFAULT;
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
 	}
 
+	mutex_unlock(&econet_mutex);
+
 	dev_put(dev);
-	return -EINVAL;
+
+	return err;
 }
 
 /*
@@ -699,7 +748,7 @@
 	.owner	=	THIS_MODULE,
 };
 
-static const struct proto_ops SOCKOPS_WRAPPED(econet_ops) = {
+static const struct proto_ops econet_ops = {
 	.family =	PF_ECONET,
 	.owner =	THIS_MODULE,
 	.release =	econet_release,
@@ -720,9 +769,6 @@
 	.sendpage =	sock_no_sendpage,
 };
 
-#include <linux/smp_lock.h>
-SOCKOPS_WRAP(econet, PF_ECONET);
-
 #if defined(CONFIG_ECONET_AUNUDP) || defined(CONFIG_ECONET_NATIVE)
 /*
  *	Find the listening socket, if any, for the given data.
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index af7f9bb..b885fd1 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -42,7 +42,7 @@
 };
 
 #define MAX_CUSTOM_LEN 64
-static char *ipw2100_translate_scan(struct ieee80211_device *ieee,
+static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
 					   char *start, char *stop,
 					   struct ieee80211_network *network)
 {
@@ -274,7 +274,7 @@
 
 		if (ieee->scan_age == 0 ||
 		    time_after(network->last_scanned + ieee->scan_age, jiffies))
-			ev = ipw2100_translate_scan(ieee, ev, stop, network);
+			ev = ieee80211_translate_scan(ieee, ev, stop, network);
 		else
 			IEEE80211_DEBUG_SCAN("Not showing network '%s ("
 					     MAC_FMT ")' due to age (%dms).\n",
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
index 6f99f78..60f06a31 100644
--- a/net/ieee80211/softmac/ieee80211softmac_module.c
+++ b/net/ieee80211/softmac/ieee80211softmac_module.c
@@ -183,16 +183,21 @@
 	 */
 	if (mac->txrates_change)
 		oldrates = mac->txrates;
-	if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
-		mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB;
-		change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
-		mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB;
-		change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
-	} else if (ieee->modulation & IEEE80211_CCK_MODULATION) {
+	/* FIXME: We don't correctly handle backing down to lower
+	   rates, so 801.11g devices start off at 11M for now. People
+	   can manually change it if they really need to, but 11M is
+	   more reliable. Note similar logic in
+	   ieee80211softmac_wx_set_rate() */	 
+	if (ieee->modulation & IEEE80211_CCK_MODULATION) {
 		mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB;
 		change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
 		mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB;
 		change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
+	} else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
+		mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB;
+		change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
+		mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB;
+		change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
 	} else
 		assert(0);
 	if (mac->txrates_change)
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h
index 9ba7dbd..65d9816 100644
--- a/net/ieee80211/softmac/ieee80211softmac_priv.h
+++ b/net/ieee80211/softmac/ieee80211softmac_priv.h
@@ -167,7 +167,7 @@
 		) || ieee80211softmac_scan_handlers_check_self(sm);
 }
 
-#define IEEE80211SOFTMAC_PROBE_DELAY		HZ/2
+#define IEEE80211SOFTMAC_PROBE_DELAY		HZ/50
 #define IEEE80211SOFTMAC_WORKQUEUE_NAME_LEN	(17 + IFNAMSIZ)
 
 struct ieee80211softmac_network {
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index e1a9bc6..b559aa9 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -135,11 +135,15 @@
 	int err = -EINVAL;
 
 	if (in_rate == -1) {
-		/* automatic detect */
-		if (ieee->modulation & IEEE80211_OFDM_MODULATION)
-			in_rate = 54000000;
-		else
+		/* FIXME: We don't correctly handle backing down to lower
+		   rates, so 801.11g devices start off at 11M for now. People
+		   can manually change it if they really need to, but 11M is
+		   more reliable. Note similar logic in
+		   ieee80211softmac_wx_set_rate() */	 
+		if (ieee->modulation & IEEE80211_CCK_MODULATION)
 			in_rate = 11000000;
+		else
+			in_rate = 54000000;
 	}
 
 	switch (in_rate) {
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 011cca7..e40f753 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -235,6 +235,7 @@
 #   bool '    IP: ARP support' CONFIG_IP_PNP_ARP		
 config NET_IPIP
 	tristate "IP: tunneling"
+	select INET_TUNNEL
 	---help---
 	  Tunneling means encapsulating data of one protocol type within
 	  another protocol and sending it over a channel that understands the
@@ -395,7 +396,7 @@
 config INET_IPCOMP
 	tristate "IP: IPComp transformation"
 	select XFRM
-	select INET_TUNNEL
+	select INET_XFRM_TUNNEL
 	select CRYPTO
 	select CRYPTO_DEFLATE
 	---help---
@@ -404,14 +405,14 @@
 	  
 	  If unsure, say Y.
 
+config INET_XFRM_TUNNEL
+	tristate
+	select INET_TUNNEL
+	default n
+
 config INET_TUNNEL
-	tristate "IP: tunnel transformation"
-	select XFRM
-	---help---
-	  Support for generic IP tunnel transformation, which is required by
-	  the IP tunneling module as well as tunnel mode IPComp.
-	  
-	  If unsure, say Y.
+	tristate
+	default n
 
 config INET_DIAG
 	tristate "INET: socket monitoring interface"
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 35e5f59..9ef50a0 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -22,7 +22,8 @@
 obj-$(CONFIG_INET_AH) += ah4.o
 obj-$(CONFIG_INET_ESP) += esp4.o
 obj-$(CONFIG_INET_IPCOMP) += ipcomp.o
-obj-$(CONFIG_INET_TUNNEL) += xfrm4_tunnel.o 
+obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o
+obj-$(CONFIG_INET_TUNNEL) += tunnel4.o
 obj-$(CONFIG_IP_PNP) += ipconfig.o
 obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o
 obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 44fdf14..81c2f78 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -81,7 +81,7 @@
 
 static void rtmsg_ifa(int event, struct in_ifaddr *);
 
-static struct notifier_block *inetaddr_chain;
+static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
 static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
 			 int destroy);
 #ifdef CONFIG_SYSCTL
@@ -267,7 +267,8 @@
 				*ifap1 = ifa->ifa_next;
 
 				rtmsg_ifa(RTM_DELADDR, ifa);
-				notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);
+				blocking_notifier_call_chain(&inetaddr_chain,
+						NETDEV_DOWN, ifa);
 				inet_free_ifa(ifa);
 			} else {
 				promote = ifa;
@@ -291,7 +292,7 @@
 	   So that, this order is correct.
 	 */
 	rtmsg_ifa(RTM_DELADDR, ifa1);
-	notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
+	blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
 
 	if (promote) {
 
@@ -303,7 +304,8 @@
 
 		promote->ifa_flags &= ~IFA_F_SECONDARY;
 		rtmsg_ifa(RTM_NEWADDR, promote);
-		notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote);
+		blocking_notifier_call_chain(&inetaddr_chain,
+				NETDEV_UP, promote);
 		for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) {
 			if (ifa1->ifa_mask != ifa->ifa_mask ||
 			    !inet_ifa_match(ifa1->ifa_address, ifa))
@@ -366,7 +368,7 @@
 	   Notifier will trigger FIB update, so that
 	   listeners of netlink will know about new ifaddr */
 	rtmsg_ifa(RTM_NEWADDR, ifa);
-	notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
+	blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
 
 	return 0;
 }
@@ -938,12 +940,12 @@
 
 int register_inetaddr_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_register(&inetaddr_chain, nb);
+	return blocking_notifier_chain_register(&inetaddr_chain, nb);
 }
 
 int unregister_inetaddr_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_unregister(&inetaddr_chain, nb);
+	return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
 }
 
 /* Rename ifa_labels for a device name change. Make some effort to preserve existing
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 03d1374..eef07b0 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -114,7 +114,6 @@
 #include <net/sock.h>
 #include <net/ip.h>
 #include <net/icmp.h>
-#include <net/protocol.h>
 #include <net/ipip.h>
 #include <net/inet_ecn.h>
 #include <net/xfrm.h>
@@ -274,7 +273,7 @@
 	dev_put(dev);
 }
 
-static void ipip_err(struct sk_buff *skb, u32 info)
+static int ipip_err(struct sk_buff *skb, u32 info)
 {
 #ifndef I_WISH_WORLD_WERE_PERFECT
 
@@ -286,21 +285,22 @@
 	int type = skb->h.icmph->type;
 	int code = skb->h.icmph->code;
 	struct ip_tunnel *t;
+	int err;
 
 	switch (type) {
 	default:
 	case ICMP_PARAMETERPROB:
-		return;
+		return 0;
 
 	case ICMP_DEST_UNREACH:
 		switch (code) {
 		case ICMP_SR_FAILED:
 		case ICMP_PORT_UNREACH:
 			/* Impossible event. */
-			return;
+			return 0;
 		case ICMP_FRAG_NEEDED:
 			/* Soft state for pmtu is maintained by IP core. */
-			return;
+			return 0;
 		default:
 			/* All others are translated to HOST_UNREACH.
 			   rfc2003 contains "deep thoughts" about NET_UNREACH,
@@ -311,14 +311,18 @@
 		break;
 	case ICMP_TIME_EXCEEDED:
 		if (code != ICMP_EXC_TTL)
-			return;
+			return 0;
 		break;
 	}
 
+	err = -ENOENT;
+
 	read_lock(&ipip_lock);
 	t = ipip_tunnel_lookup(iph->daddr, iph->saddr);
 	if (t == NULL || t->parms.iph.daddr == 0)
 		goto out;
+
+	err = 0;
 	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
 		goto out;
 
@@ -329,7 +333,7 @@
 	t->err_time = jiffies;
 out:
 	read_unlock(&ipip_lock);
-	return;
+	return err;
 #else
 	struct iphdr *iph = (struct iphdr*)dp;
 	int hlen = iph->ihl<<2;
@@ -344,15 +348,15 @@
 	struct rtable *rt;
 
 	if (len < hlen + sizeof(struct iphdr))
-		return;
+		return 0;
 	eiph = (struct iphdr*)(dp + hlen);
 
 	switch (type) {
 	default:
-		return;
+		return 0;
 	case ICMP_PARAMETERPROB:
 		if (skb->h.icmph->un.gateway < hlen)
-			return;
+			return 0;
 
 		/* So... This guy found something strange INSIDE encapsulated
 		   packet. Well, he is fool, but what can we do ?
@@ -366,16 +370,16 @@
 		case ICMP_SR_FAILED:
 		case ICMP_PORT_UNREACH:
 			/* Impossible event. */
-			return;
+			return 0;
 		case ICMP_FRAG_NEEDED:
 			/* And it is the only really necessary thing :-) */
 			rel_info = ntohs(skb->h.icmph->un.frag.mtu);
 			if (rel_info < hlen+68)
-				return;
+				return 0;
 			rel_info -= hlen;
 			/* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */
 			if (rel_info > ntohs(eiph->tot_len))
-				return;
+				return 0;
 			break;
 		default:
 			/* All others are translated to HOST_UNREACH.
@@ -389,14 +393,14 @@
 		break;
 	case ICMP_TIME_EXCEEDED:
 		if (code != ICMP_EXC_TTL)
-			return;
+			return 0;
 		break;
 	}
 
 	/* Prepare fake skb to feed it to icmp_send */
 	skb2 = skb_clone(skb, GFP_ATOMIC);
 	if (skb2 == NULL)
-		return;
+		return 0;
 	dst_release(skb2->dst);
 	skb2->dst = NULL;
 	skb_pull(skb2, skb->data - (u8*)eiph);
@@ -409,7 +413,7 @@
 	fl.proto = IPPROTO_IPIP;
 	if (ip_route_output_key(&rt, &key)) {
 		kfree_skb(skb2);
-		return;
+		return 0;
 	}
 	skb2->dev = rt->u.dst.dev;
 
@@ -424,14 +428,14 @@
 		    rt->u.dst.dev->type != ARPHRD_TUNNEL) {
 			ip_rt_put(rt);
 			kfree_skb(skb2);
-			return;
+			return 0;
 		}
 	} else {
 		ip_rt_put(rt);
 		if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) ||
 		    skb2->dst->dev->type != ARPHRD_TUNNEL) {
 			kfree_skb(skb2);
-			return;
+			return 0;
 		}
 	}
 
@@ -439,7 +443,7 @@
 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
 		if (rel_info > dst_mtu(skb2->dst)) {
 			kfree_skb(skb2);
-			return;
+			return 0;
 		}
 		skb2->dst->ops->update_pmtu(skb2->dst, rel_info);
 		rel_info = htonl(rel_info);
@@ -453,7 +457,7 @@
 
 	icmp_send(skb2, rel_type, rel_code, rel_info);
 	kfree_skb(skb2);
-	return;
+	return 0;
 #endif
 }
 
@@ -855,39 +859,12 @@
 	return 0;
 }
 
-#ifdef CONFIG_INET_TUNNEL
 static struct xfrm_tunnel ipip_handler = {
 	.handler	=	ipip_rcv,
 	.err_handler	=	ipip_err,
+	.priority	=	1,
 };
 
-static inline int ipip_register(void)
-{
-	return xfrm4_tunnel_register(&ipip_handler);
-}
-
-static inline int ipip_unregister(void)
-{
-	return xfrm4_tunnel_deregister(&ipip_handler);
-}
-#else
-static struct net_protocol ipip_protocol = {
-	.handler	=	ipip_rcv,
-	.err_handler	=	ipip_err,
-	.no_policy	=	1,
-};
-
-static inline int ipip_register(void)
-{
-	return inet_add_protocol(&ipip_protocol, IPPROTO_IPIP);
-}
-
-static inline int ipip_unregister(void)
-{
-	return inet_del_protocol(&ipip_protocol, IPPROTO_IPIP);
-}
-#endif
-
 static char banner[] __initdata =
 	KERN_INFO "IPv4 over IPv4 tunneling driver\n";
 
@@ -897,7 +874,7 @@
 
 	printk(banner);
 
-	if (ipip_register() < 0) {
+	if (xfrm4_tunnel_register(&ipip_handler)) {
 		printk(KERN_INFO "ipip init: can't register tunnel\n");
 		return -EAGAIN;
 	}
@@ -919,7 +896,7 @@
  err2:
 	free_netdev(ipip_fb_tunnel_dev);
  err1:
-	ipip_unregister();
+	xfrm4_tunnel_deregister(&ipip_handler);
 	goto out;
 }
 
@@ -939,7 +916,7 @@
 
 static void __exit ipip_fini(void)
 {
-	if (ipip_unregister() < 0)
+	if (xfrm4_tunnel_deregister(&ipip_handler))
 		printk(KERN_INFO "ipip close: can't deregister tunnel\n");
 
 	rtnl_lock();
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 7f0288b..f28ec68 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -34,6 +34,7 @@
 
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/mutex.h>
 
 #include <net/ip.h>
 #include <net/route.h>
@@ -44,7 +45,7 @@
 #include <net/ip_vs.h>
 
 /* semaphore for IPVS sockopts. And, [gs]etsockopt may sleep. */
-static DECLARE_MUTEX(__ip_vs_mutex);
+static DEFINE_MUTEX(__ip_vs_mutex);
 
 /* lock for service table */
 static DEFINE_RWLOCK(__ip_vs_svc_lock);
@@ -1950,7 +1951,7 @@
 	/* increase the module use count */
 	ip_vs_use_count_inc();
 
-	if (down_interruptible(&__ip_vs_mutex)) {
+	if (mutex_lock_interruptible(&__ip_vs_mutex)) {
 		ret = -ERESTARTSYS;
 		goto out_dec;
 	}
@@ -2041,7 +2042,7 @@
 		ip_vs_service_put(svc);
 
   out_unlock:
-	up(&__ip_vs_mutex);
+	mutex_unlock(&__ip_vs_mutex);
   out_dec:
 	/* decrease the module use count */
 	ip_vs_use_count_dec();
@@ -2211,7 +2212,7 @@
 	if (copy_from_user(arg, user, get_arglen[GET_CMDID(cmd)]) != 0)
 		return -EFAULT;
 
-	if (down_interruptible(&__ip_vs_mutex))
+	if (mutex_lock_interruptible(&__ip_vs_mutex))
 		return -ERESTARTSYS;
 
 	switch (cmd) {
@@ -2330,7 +2331,7 @@
 	}
 
   out:
-	up(&__ip_vs_mutex);
+	mutex_unlock(&__ip_vs_mutex);
 	return ret;
 }
 
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index ed42cdc..b5ad9ac 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -167,15 +167,15 @@
 	.reroute	= queue_reroute,
 };
 
-static int init(void)
+static int ipv4_netfilter_init(void)
 {
 	return nf_register_queue_rerouter(PF_INET, &ip_reroute);
 }
 
-static void fini(void)
+static void ipv4_netfilter_fini(void)
 {
 	nf_unregister_queue_rerouter(PF_INET);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipv4_netfilter_init);
+module_exit(ipv4_netfilter_fini);
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index ff0c594..a44a5d7 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -1166,7 +1166,7 @@
 	.get		= do_arpt_get_ctl,
 };
 
-static int __init init(void)
+static int __init arp_tables_init(void)
 {
 	int ret;
 
@@ -1187,7 +1187,7 @@
 	return 0;
 }
 
-static void __exit fini(void)
+static void __exit arp_tables_fini(void)
 {
 	nf_unregister_sockopt(&arpt_sockopts);
 	xt_proto_fini(NF_ARP);
@@ -1197,5 +1197,5 @@
 EXPORT_SYMBOL(arpt_unregister_table);
 EXPORT_SYMBOL(arpt_do_table);
 
-module_init(init);
-module_exit(fini);
+module_init(arp_tables_init);
+module_exit(arp_tables_fini);
diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c
index 0f2a953..a58325c 100644
--- a/net/ipv4/netfilter/arpt_mangle.c
+++ b/net/ipv4/netfilter/arpt_mangle.c
@@ -89,7 +89,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init arpt_mangle_init(void)
 {
 	if (arpt_register_target(&arpt_mangle_reg))
 		return -EINVAL;
@@ -97,10 +97,10 @@
 	return 0;
 }
 
-static void __exit fini(void)
+static void __exit arpt_mangle_fini(void)
 {
 	arpt_unregister_target(&arpt_mangle_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(arpt_mangle_init);
+module_exit(arpt_mangle_fini);
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index f6ab45f..d0d379c 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -179,7 +179,7 @@
 	},
 };
 
-static int __init init(void)
+static int __init arptable_filter_init(void)
 {
 	int ret, i;
 
@@ -201,7 +201,7 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit arptable_filter_fini(void)
 {
 	unsigned int i;
 
@@ -211,5 +211,5 @@
 	arpt_unregister_table(&packet_filter);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(arptable_filter_init);
+module_exit(arptable_filter_fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c
index 84e4f79..a604b1c 100644
--- a/net/ipv4/netfilter/ip_conntrack_amanda.c
+++ b/net/ipv4/netfilter/ip_conntrack_amanda.c
@@ -153,13 +153,13 @@
 	},
 };
 
-static void __exit fini(void)
+static void __exit ip_conntrack_amanda_fini(void)
 {
 	ip_conntrack_helper_unregister(&amanda_helper);
 	kfree(amanda_buffer);
 }
 
-static int __init init(void)
+static int __init ip_conntrack_amanda_init(void)
 {
 	int ret;
 
@@ -177,5 +177,5 @@
 
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip_conntrack_amanda_init);
+module_exit(ip_conntrack_amanda_fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
index 9e34034..ceaabc1 100644
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -80,8 +80,8 @@
 static unsigned int ip_conntrack_next_id;
 static unsigned int ip_conntrack_expect_next_id;
 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-struct notifier_block *ip_conntrack_chain;
-struct notifier_block *ip_conntrack_expect_chain;
+ATOMIC_NOTIFIER_HEAD(ip_conntrack_chain);
+ATOMIC_NOTIFIER_HEAD(ip_conntrack_expect_chain);
 
 DEFINE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache);
 
@@ -92,7 +92,7 @@
 {
 	DEBUGP("ecache: delivering events for %p\n", ecache->ct);
 	if (is_confirmed(ecache->ct) && !is_dying(ecache->ct) && ecache->events)
-		notifier_call_chain(&ip_conntrack_chain, ecache->events,
+		atomic_notifier_call_chain(&ip_conntrack_chain, ecache->events,
 				    ecache->ct);
 	ecache->events = 0;
 	ip_conntrack_put(ecache->ct);
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
index e627e58..3e542bf 100644
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c
@@ -453,7 +453,7 @@
 static char ftp_names[MAX_PORTS][sizeof("ftp-65535")];
 
 /* Not __exit: called from init() */
-static void fini(void)
+static void ip_conntrack_ftp_fini(void)
 {
 	int i;
 	for (i = 0; i < ports_c; i++) {
@@ -465,7 +465,7 @@
 	kfree(ftp_buffer);
 }
 
-static int __init init(void)
+static int __init ip_conntrack_ftp_init(void)
 {
 	int i, ret;
 	char *tmpname;
@@ -499,12 +499,12 @@
 		ret = ip_conntrack_helper_register(&ftp[i]);
 
 		if (ret) {
-			fini();
+			ip_conntrack_ftp_fini();
 			return ret;
 		}
 	}
 	return 0;
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip_conntrack_ftp_init);
+module_exit(ip_conntrack_ftp_fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
index d716bba..7d3ba43 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
@@ -766,7 +766,7 @@
 extern int __init ip_ct_proto_gre_init(void);
 
 /* ip_conntrack_pptp initialization */
-static int __init init(void)
+static int __init ip_conntrack_helper_pptp_init(void)
 {
 	int retcode;
  
@@ -786,15 +786,15 @@
 	return 0;
 }
 
-static void __exit fini(void)
+static void __exit ip_conntrack_helper_pptp_fini(void)
 {
 	ip_conntrack_helper_unregister(&pptp);
 	ip_ct_proto_gre_fini();
 	printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip_conntrack_helper_pptp_init);
+module_exit(ip_conntrack_helper_pptp_fini);
 
 EXPORT_SYMBOL(ip_nat_pptp_hook_outbound);
 EXPORT_SYMBOL(ip_nat_pptp_hook_inbound);
diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c
index c51a2cf..a2ac5ce 100644
--- a/net/ipv4/netfilter/ip_conntrack_irc.c
+++ b/net/ipv4/netfilter/ip_conntrack_irc.c
@@ -242,9 +242,9 @@
 static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
 static char irc_names[MAX_PORTS][sizeof("irc-65535")];
 
-static void fini(void);
+static void ip_conntrack_irc_fini(void);
 
-static int __init init(void)
+static int __init ip_conntrack_irc_init(void)
 {
 	int i, ret;
 	struct ip_conntrack_helper *hlpr;
@@ -288,7 +288,7 @@
 		if (ret) {
 			printk("ip_conntrack_irc: ERROR registering port %d\n",
 				ports[i]);
-			fini();
+			ip_conntrack_irc_fini();
 			return -EBUSY;
 		}
 	}
@@ -297,7 +297,7 @@
 
 /* This function is intentionally _NOT_ defined as __exit, because 
  * it is needed by the init function */
-static void fini(void)
+static void ip_conntrack_irc_fini(void)
 {
 	int i;
 	for (i = 0; i < ports_c; i++) {
@@ -308,5 +308,5 @@
 	kfree(irc_buffer);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip_conntrack_irc_init);
+module_exit(ip_conntrack_irc_fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
index 4e68e16..a566a81 100644
--- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
+++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
@@ -127,16 +127,16 @@
 	.help			= help,
 };
 
-static int __init init(void)
+static int __init ip_conntrack_netbios_ns_init(void)
 {
 	helper.timeout = timeout;
 	return ip_conntrack_helper_register(&helper);
 }
 
-static void __exit fini(void)
+static void __exit ip_conntrack_netbios_ns_fini(void)
 {
 	ip_conntrack_helper_unregister(&helper);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip_conntrack_netbios_ns_init);
+module_exit(ip_conntrack_netbios_ns_fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
index be602e8..5259abd 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
@@ -609,7 +609,7 @@
 static struct ctl_table_header *ip_ct_sysctl_header;
 #endif
 
-static int __init init(void)
+static int __init ip_conntrack_proto_sctp_init(void)
 {
 	int ret;
 
@@ -640,7 +640,7 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit ip_conntrack_proto_sctp_fini(void)
 {
 	ip_conntrack_protocol_unregister(&ip_conntrack_protocol_sctp);
 #ifdef CONFIG_SYSCTL
@@ -649,8 +649,8 @@
 	DEBUGP("SCTP conntrack module unloaded\n");
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip_conntrack_proto_sctp_init);
+module_exit(ip_conntrack_proto_sctp_fini);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Kiran Kumar Immidi");
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index 833fcb4..5207602 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -929,18 +929,18 @@
 	ip_ct_iterate_cleanup(kill_proto, &proto->proto);
 }
 
-static int __init init(void)
+static int __init ip_conntrack_standalone_init(void)
 {
 	return init_or_cleanup(1);
 }
 
-static void __exit fini(void)
+static void __exit ip_conntrack_standalone_fini(void)
 {
 	init_or_cleanup(0);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip_conntrack_standalone_init);
+module_exit(ip_conntrack_standalone_fini);
 
 /* Some modules need us, but don't depend directly on any symbol.
    They should call this. */
diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c
index 4ba4463..7e33d3b 100644
--- a/net/ipv4/netfilter/ip_conntrack_tftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_tftp.c
@@ -103,7 +103,7 @@
 static struct ip_conntrack_helper tftp[MAX_PORTS];
 static char tftp_names[MAX_PORTS][sizeof("tftp-65535")];
 
-static void fini(void)
+static void ip_conntrack_tftp_fini(void)
 {
 	int i;
 
@@ -114,7 +114,7 @@
 	} 
 }
 
-static int __init init(void)
+static int __init ip_conntrack_tftp_init(void)
 {
 	int i, ret;
 	char *tmpname;
@@ -148,12 +148,12 @@
 		if (ret) {
 			printk("ERROR registering helper for port %d\n",
 				ports[i]);
-			fini();
+			ip_conntrack_tftp_fini();
 			return(ret);
 		}
 	}
 	return(0);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip_conntrack_tftp_init);
+module_exit(ip_conntrack_tftp_fini);
diff --git a/net/ipv4/netfilter/ip_nat_amanda.c b/net/ipv4/netfilter/ip_nat_amanda.c
index 706c807..3a88871 100644
--- a/net/ipv4/netfilter/ip_nat_amanda.c
+++ b/net/ipv4/netfilter/ip_nat_amanda.c
@@ -68,19 +68,19 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit ip_nat_amanda_fini(void)
 {
 	ip_nat_amanda_hook = NULL;
 	/* Make sure noone calls it, meanwhile. */
 	synchronize_net();
 }
 
-static int __init init(void)
+static int __init ip_nat_amanda_init(void)
 {
 	BUG_ON(ip_nat_amanda_hook);
 	ip_nat_amanda_hook = help;
 	return 0;
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip_nat_amanda_init);
+module_exit(ip_nat_amanda_fini);
diff --git a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c
index b8daab3..3328fc5 100644
--- a/net/ipv4/netfilter/ip_nat_ftp.c
+++ b/net/ipv4/netfilter/ip_nat_ftp.c
@@ -154,14 +154,14 @@
 	return NF_ACCEPT;
 }
 
-static void __exit fini(void)
+static void __exit ip_nat_ftp_fini(void)
 {
 	ip_nat_ftp_hook = NULL;
 	/* Make sure noone calls it, meanwhile. */
 	synchronize_net();
 }
 
-static int __init init(void)
+static int __init ip_nat_ftp_init(void)
 {
 	BUG_ON(ip_nat_ftp_hook);
 	ip_nat_ftp_hook = ip_nat_ftp;
@@ -177,5 +177,5 @@
 }
 module_param_call(ports, warn_set, NULL, NULL, 0);
 
-module_init(init);
-module_exit(fini);
+module_init(ip_nat_ftp_init);
+module_exit(ip_nat_ftp_fini);
diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c
index b9c016c..f397772 100644
--- a/net/ipv4/netfilter/ip_nat_helper_pptp.c
+++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c
@@ -370,7 +370,7 @@
 extern int __init ip_nat_proto_gre_init(void);
 extern void __exit ip_nat_proto_gre_fini(void);
 
-static int __init init(void)
+static int __init ip_nat_helper_pptp_init(void)
 {
 	int ret;
 
@@ -396,7 +396,7 @@
 	return 0;
 }
 
-static void __exit fini(void)
+static void __exit ip_nat_helper_pptp_fini(void)
 {
 	DEBUGP("cleanup_module\n" );
 
@@ -412,5 +412,5 @@
 	printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip_nat_helper_pptp_init);
+module_exit(ip_nat_helper_pptp_fini);
diff --git a/net/ipv4/netfilter/ip_nat_irc.c b/net/ipv4/netfilter/ip_nat_irc.c
index 461c833..a767123 100644
--- a/net/ipv4/netfilter/ip_nat_irc.c
+++ b/net/ipv4/netfilter/ip_nat_irc.c
@@ -96,14 +96,14 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit ip_nat_irc_fini(void)
 {
 	ip_nat_irc_hook = NULL;
 	/* Make sure noone calls it, meanwhile. */
 	synchronize_net();
 }
 
-static int __init init(void)
+static int __init ip_nat_irc_init(void)
 {
 	BUG_ON(ip_nat_irc_hook);
 	ip_nat_irc_hook = help;
@@ -119,5 +119,5 @@
 }
 module_param_call(ports, warn_set, NULL, NULL, 0);
 
-module_init(init);
-module_exit(fini);
+module_init(ip_nat_irc_init);
+module_exit(ip_nat_irc_fini);
diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c
index f029da2..c622538 100644
--- a/net/ipv4/netfilter/ip_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c
@@ -1324,7 +1324,7 @@
  *
  *****************************************************************************/
  
-static int __init init(void)
+static int __init ip_nat_snmp_basic_init(void)
 {
 	int ret = 0;
 
@@ -1339,13 +1339,13 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit ip_nat_snmp_basic_fini(void)
 {
 	ip_conntrack_helper_unregister(&snmp_helper);
 	ip_conntrack_helper_unregister(&snmp_trap_helper);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip_nat_snmp_basic_init);
+module_exit(ip_nat_snmp_basic_fini);
 
 module_param(debug, bool, 0600);
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 380aef3..3505b0d 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -425,17 +425,17 @@
 	return ret;
 }
 
-static int __init init(void)
+static int __init ip_nat_standalone_init(void)
 {
 	return init_or_cleanup(1);
 }
 
-static void __exit fini(void)
+static void __exit ip_nat_standalone_fini(void)
 {
 	init_or_cleanup(0);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip_nat_standalone_init);
+module_exit(ip_nat_standalone_fini);
 
 MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/ip_nat_tftp.c b/net/ipv4/netfilter/ip_nat_tftp.c
index 43c3bd7..94a7801 100644
--- a/net/ipv4/netfilter/ip_nat_tftp.c
+++ b/net/ipv4/netfilter/ip_nat_tftp.c
@@ -53,19 +53,19 @@
 	return NF_ACCEPT;
 }
 
-static void __exit fini(void)
+static void __exit ip_nat_tftp_fini(void)
 {
 	ip_nat_tftp_hook = NULL;
 	/* Make sure noone calls it, meanwhile. */
 	synchronize_net();
 }
 
-static int __init init(void)
+static int __init ip_nat_tftp_init(void)
 {
 	BUG_ON(ip_nat_tftp_hook);
 	ip_nat_tftp_hook = help;
 	return 0;
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip_nat_tftp_init);
+module_exit(ip_nat_tftp_fini);
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 1655866..896a244 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -717,13 +717,13 @@
 	return status;
 }
 
-static int __init init(void)
+static int __init ip_queue_init(void)
 {
 	
 	return init_or_cleanup(1);
 }
 
-static void __exit fini(void)
+static void __exit ip_queue_fini(void)
 {
 	init_or_cleanup(0);
 }
@@ -732,5 +732,5 @@
 MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
 MODULE_LICENSE("GPL");
 
-module_init(init);
-module_exit(fini);
+module_init(ip_queue_init);
+module_exit(ip_queue_fini);
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index a7b194c..460fd90 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1364,7 +1364,7 @@
 	.checkentry	= icmp_checkentry,
 };
 
-static int __init init(void)
+static int __init ip_tables_init(void)
 {
 	int ret;
 
@@ -1386,7 +1386,7 @@
 	return 0;
 }
 
-static void __exit fini(void)
+static void __exit ip_tables_fini(void)
 {
 	nf_unregister_sockopt(&ipt_sockopts);
 
@@ -1400,5 +1400,5 @@
 EXPORT_SYMBOL(ipt_register_table);
 EXPORT_SYMBOL(ipt_unregister_table);
 EXPORT_SYMBOL(ipt_do_table);
-module_init(init);
-module_exit(fini);
+module_init(ip_tables_init);
+module_exit(ip_tables_fini);
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 61e11ed..e4768a3 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -770,15 +770,15 @@
 	return -EINVAL;
 }
 
-static int __init init(void)
+static int __init ipt_clusterip_init(void)
 {
 	return init_or_cleanup(0);
 }
 
-static void __exit fini(void)
+static void __exit ipt_clusterip_fini(void)
 {
 	init_or_cleanup(1);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_clusterip_init);
+module_exit(ipt_clusterip_fini);
diff --git a/net/ipv4/netfilter/ipt_DSCP.c b/net/ipv4/netfilter/ipt_DSCP.c
index cfb0b90..c8e9712 100644
--- a/net/ipv4/netfilter/ipt_DSCP.c
+++ b/net/ipv4/netfilter/ipt_DSCP.c
@@ -82,15 +82,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_dscp_init(void)
 {
 	return ipt_register_target(&ipt_dscp_reg);
 }
 
-static void __exit fini(void)
+static void __exit ipt_dscp_fini(void)
 {
 	ipt_unregister_target(&ipt_dscp_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_dscp_init);
+module_exit(ipt_dscp_fini);
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index b9b80f9..4adf5c9 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -151,15 +151,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_ecn_init(void)
 {
 	return ipt_register_target(&ipt_ecn_reg);
 }
 
-static void __exit fini(void)
+static void __exit ipt_ecn_fini(void)
 {
 	ipt_unregister_target(&ipt_ecn_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_ecn_init);
+module_exit(ipt_ecn_fini);
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index 750d322..39fd4c2 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -471,7 +471,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_log_init(void)
 {
 	if (ipt_register_target(&ipt_log_reg))
 		return -EINVAL;
@@ -485,11 +485,11 @@
 	return 0;
 }
 
-static void __exit fini(void)
+static void __exit ipt_log_fini(void)
 {
 	nf_log_unregister_logger(&ipt_log_logger);
 	ipt_unregister_target(&ipt_log_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_log_init);
+module_exit(ipt_log_fini);
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index e0c321c..8b3e7f9 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -175,7 +175,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_masquerade_init(void)
 {
 	int ret;
 
@@ -191,12 +191,12 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit ipt_masquerade_fini(void)
 {
 	ipt_unregister_target(&masquerade);
 	unregister_netdevice_notifier(&masq_dev_notifier);
 	unregister_inetaddr_notifier(&masq_inet_notifier);	
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_masquerade_init);
+module_exit(ipt_masquerade_fini);
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index fba181c..2fcf107 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -98,15 +98,15 @@
     	.me 		= THIS_MODULE 
 };
 
-static int __init init(void)
+static int __init ipt_netmap_init(void)
 {
 	return ipt_register_target(&target_module);
 }
 
-static void __exit fini(void)
+static void __exit ipt_netmap_fini(void)
 {
 	ipt_unregister_target(&target_module);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_netmap_init);
+module_exit(ipt_netmap_fini);
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
index be3da7c..f290463 100644
--- a/net/ipv4/netfilter/ipt_REDIRECT.c
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -112,15 +112,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_redirect_init(void)
 {
 	return ipt_register_target(&redirect_reg);
 }
 
-static void __exit fini(void)
+static void __exit ipt_redirect_fini(void)
 {
 	ipt_unregister_target(&redirect_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_redirect_init);
+module_exit(ipt_redirect_fini);
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index 9d3b357..4269a54 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -313,15 +313,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_reject_init(void)
 {
 	return ipt_register_target(&ipt_reject_reg);
 }
 
-static void __exit fini(void)
+static void __exit ipt_reject_fini(void)
 {
 	ipt_unregister_target(&ipt_reject_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_reject_init);
+module_exit(ipt_reject_fini);
diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c
index 7e2ebc9..7169b09 100644
--- a/net/ipv4/netfilter/ipt_SAME.c
+++ b/net/ipv4/netfilter/ipt_SAME.c
@@ -189,16 +189,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_same_init(void)
 {
 	return ipt_register_target(&same_reg);
 }
 
-static void __exit fini(void)
+static void __exit ipt_same_fini(void)
 {
 	ipt_unregister_target(&same_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_same_init);
+module_exit(ipt_same_fini);
 
diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c
index c4fc50e..ef2fe5b 100644
--- a/net/ipv4/netfilter/ipt_TCPMSS.c
+++ b/net/ipv4/netfilter/ipt_TCPMSS.c
@@ -243,15 +243,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_tcpmss_init(void)
 {
 	return ipt_register_target(&ipt_tcpmss_reg);
 }
 
-static void __exit fini(void)
+static void __exit ipt_tcpmss_fini(void)
 {
 	ipt_unregister_target(&ipt_tcpmss_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_tcpmss_init);
+module_exit(ipt_tcpmss_fini);
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c
index 9aa7817..1c7a5ca 100644
--- a/net/ipv4/netfilter/ipt_TOS.c
+++ b/net/ipv4/netfilter/ipt_TOS.c
@@ -81,15 +81,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_tos_init(void)
 {
 	return ipt_register_target(&ipt_tos_reg);
 }
 
-static void __exit fini(void)
+static void __exit ipt_tos_fini(void)
 {
 	ipt_unregister_target(&ipt_tos_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_tos_init);
+module_exit(ipt_tos_fini);
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c
index 5009a00..f48892a 100644
--- a/net/ipv4/netfilter/ipt_TTL.c
+++ b/net/ipv4/netfilter/ipt_TTL.c
@@ -94,15 +94,15 @@
 	.me 		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_ttl_init(void)
 {
 	return ipt_register_target(&ipt_TTL);
 }
 
-static void __exit fini(void)
+static void __exit ipt_ttl_fini(void)
 {
 	ipt_unregister_target(&ipt_TTL);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_ttl_init);
+module_exit(ipt_ttl_fini);
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index a82a32e..c84cc03 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -374,7 +374,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_ulog_init(void)
 {
 	int i;
 
@@ -407,7 +407,7 @@
 	return 0;
 }
 
-static void __exit fini(void)
+static void __exit ipt_ulog_fini(void)
 {
 	ulog_buff_t *ub;
 	int i;
@@ -435,5 +435,5 @@
 
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_ulog_init);
+module_exit(ipt_ulog_fini);
diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c
index 5fdf85d..893dae2 100644
--- a/net/ipv4/netfilter/ipt_addrtype.c
+++ b/net/ipv4/netfilter/ipt_addrtype.c
@@ -51,15 +51,15 @@
 	.me		= THIS_MODULE
 };
 
-static int __init init(void)
+static int __init ipt_addrtype_init(void)
 {
 	return ipt_register_match(&addrtype_match);
 }
 
-static void __exit fini(void)
+static void __exit ipt_addrtype_fini(void)
 {
 	ipt_unregister_match(&addrtype_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_addrtype_init);
+module_exit(ipt_addrtype_fini);
diff --git a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c
index 35a21fb..2927135 100644
--- a/net/ipv4/netfilter/ipt_ah.c
+++ b/net/ipv4/netfilter/ipt_ah.c
@@ -96,15 +96,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_ah_init(void)
 {
 	return ipt_register_match(&ah_match);
 }
 
-static void __exit cleanup(void)
+static void __exit ipt_ah_fini(void)
 {
 	ipt_unregister_match(&ah_match);
 }
 
-module_init(init);
-module_exit(cleanup);
+module_init(ipt_ah_init);
+module_exit(ipt_ah_fini);
diff --git a/net/ipv4/netfilter/ipt_dscp.c b/net/ipv4/netfilter/ipt_dscp.c
index 11963c3..4717759 100644
--- a/net/ipv4/netfilter/ipt_dscp.c
+++ b/net/ipv4/netfilter/ipt_dscp.c
@@ -39,16 +39,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_dscp_init(void)
 {
 	return ipt_register_match(&dscp_match);
 }
 
-static void __exit fini(void)
+static void __exit ipt_dscp_fini(void)
 {
 	ipt_unregister_match(&dscp_match);
 
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_dscp_init);
+module_exit(ipt_dscp_fini);
diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c
index d7e29f6..b282504 100644
--- a/net/ipv4/netfilter/ipt_ecn.c
+++ b/net/ipv4/netfilter/ipt_ecn.c
@@ -118,15 +118,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_ecn_init(void)
 {
 	return ipt_register_match(&ecn_match);
 }
 
-static void __exit fini(void)
+static void __exit ipt_ecn_fini(void)
 {
 	ipt_unregister_match(&ecn_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_ecn_init);
+module_exit(ipt_ecn_fini);
diff --git a/net/ipv4/netfilter/ipt_esp.c b/net/ipv4/netfilter/ipt_esp.c
index af0d5ec..3840b41 100644
--- a/net/ipv4/netfilter/ipt_esp.c
+++ b/net/ipv4/netfilter/ipt_esp.c
@@ -97,15 +97,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_esp_init(void)
 {
 	return ipt_register_match(&esp_match);
 }
 
-static void __exit cleanup(void)
+static void __exit ipt_esp_fini(void)
 {
 	ipt_unregister_match(&esp_match);
 }
 
-module_init(init);
-module_exit(cleanup);
+module_init(ipt_esp_init);
+module_exit(ipt_esp_fini);
diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c
index dc1521c..7c6836c 100644
--- a/net/ipv4/netfilter/ipt_hashlimit.c
+++ b/net/ipv4/netfilter/ipt_hashlimit.c
@@ -40,6 +40,7 @@
 
 /* FIXME: this is just for IP_NF_ASSERRT */
 #include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/mutex.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
@@ -92,7 +93,7 @@
 };
 
 static DEFINE_SPINLOCK(hashlimit_lock);	/* protects htables list */
-static DECLARE_MUTEX(hlimit_mutex);	/* additional checkentry protection */
+static DEFINE_MUTEX(hlimit_mutex);	/* additional checkentry protection */
 static HLIST_HEAD(hashlimit_htables);
 static kmem_cache_t *hashlimit_cachep __read_mostly;
 
@@ -542,13 +543,13 @@
 	 * call vmalloc, and that can sleep.  And we cannot just re-search
 	 * the list of htable's in htable_create(), since then we would
 	 * create duplicate proc files. -HW */
-	down(&hlimit_mutex);
+	mutex_lock(&hlimit_mutex);
 	r->hinfo = htable_find_get(r->name);
 	if (!r->hinfo && (htable_create(r) != 0)) {
-		up(&hlimit_mutex);
+		mutex_unlock(&hlimit_mutex);
 		return 0;
 	}
-	up(&hlimit_mutex);
+	mutex_unlock(&hlimit_mutex);
 
 	/* Ugly hack: For SMP, we only want to use one set */
 	r->u.master = r;
@@ -718,15 +719,15 @@
 	
 }
 
-static int __init init(void)
+static int __init ipt_hashlimit_init(void)
 {
 	return init_or_fini(0);
 }
 
-static void __exit fini(void)
+static void __exit ipt_hashlimit_fini(void)
 {
 	init_or_fini(1);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_hashlimit_init);
+module_exit(ipt_hashlimit_fini);
diff --git a/net/ipv4/netfilter/ipt_iprange.c b/net/ipv4/netfilter/ipt_iprange.c
index ae70112..5202edd 100644
--- a/net/ipv4/netfilter/ipt_iprange.c
+++ b/net/ipv4/netfilter/ipt_iprange.c
@@ -71,15 +71,15 @@
 	.me		= THIS_MODULE
 };
 
-static int __init init(void)
+static int __init ipt_iprange_init(void)
 {
 	return ipt_register_match(&iprange_match);
 }
 
-static void __exit fini(void)
+static void __exit ipt_iprange_fini(void)
 {
 	ipt_unregister_match(&iprange_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_iprange_init);
+module_exit(ipt_iprange_fini);
diff --git a/net/ipv4/netfilter/ipt_multiport.c b/net/ipv4/netfilter/ipt_multiport.c
index bd07f7c..ac95d83 100644
--- a/net/ipv4/netfilter/ipt_multiport.c
+++ b/net/ipv4/netfilter/ipt_multiport.c
@@ -171,7 +171,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_multiport_init(void)
 {
 	int err;
 
@@ -185,11 +185,11 @@
 	return err;
 }
 
-static void __exit fini(void)
+static void __exit ipt_multiport_fini(void)
 {
 	ipt_unregister_match(&multiport_match);
 	ipt_unregister_match(&multiport_match_v1);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_multiport_init);
+module_exit(ipt_multiport_fini);
diff --git a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c
index 3900428..5ac6ac0 100644
--- a/net/ipv4/netfilter/ipt_owner.c
+++ b/net/ipv4/netfilter/ipt_owner.c
@@ -78,15 +78,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_owner_init(void)
 {
 	return ipt_register_match(&owner_match);
 }
 
-static void __exit fini(void)
+static void __exit ipt_owner_fini(void)
 {
 	ipt_unregister_match(&owner_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_owner_init);
+module_exit(ipt_owner_fini);
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
index 06792ea..1438432 100644
--- a/net/ipv4/netfilter/ipt_recent.c
+++ b/net/ipv4/netfilter/ipt_recent.c
@@ -962,7 +962,7 @@
 };
 
 /* Kernel module initialization. */
-static int __init init(void)
+static int __init ipt_recent_init(void)
 {
 	int err, count;
 
@@ -995,7 +995,7 @@
 }
 
 /* Kernel module destruction. */
-static void __exit fini(void)
+static void __exit ipt_recent_fini(void)
 {
 	ipt_unregister_match(&recent_match);
 
@@ -1003,5 +1003,5 @@
 }
 
 /* Register our module with the kernel. */
-module_init(init);
-module_exit(fini);
+module_init(ipt_recent_init);
+module_exit(ipt_recent_fini);
diff --git a/net/ipv4/netfilter/ipt_tos.c b/net/ipv4/netfilter/ipt_tos.c
index e404e92d..5549c39 100644
--- a/net/ipv4/netfilter/ipt_tos.c
+++ b/net/ipv4/netfilter/ipt_tos.c
@@ -39,15 +39,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_multiport_init(void)
 {
 	return ipt_register_match(&tos_match);
 }
 
-static void __exit fini(void)
+static void __exit ipt_multiport_fini(void)
 {
 	ipt_unregister_match(&tos_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_multiport_init);
+module_exit(ipt_multiport_fini);
diff --git a/net/ipv4/netfilter/ipt_ttl.c b/net/ipv4/netfilter/ipt_ttl.c
index ae7ce4d..a5243bd 100644
--- a/net/ipv4/netfilter/ipt_ttl.c
+++ b/net/ipv4/netfilter/ipt_ttl.c
@@ -55,16 +55,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_ttl_init(void)
 {
 	return ipt_register_match(&ttl_match);
 }
 
-static void __exit fini(void)
+static void __exit ipt_ttl_fini(void)
 {
 	ipt_unregister_match(&ttl_match);
 
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_ttl_init);
+module_exit(ipt_ttl_fini);
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index 212a307..3d80aef 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -139,7 +139,7 @@
 static int forward = NF_ACCEPT;
 module_param(forward, bool, 0000);
 
-static int __init init(void)
+static int __init iptable_filter_init(void)
 {
 	int ret;
 
@@ -181,7 +181,7 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit iptable_filter_fini(void)
 {
 	unsigned int i;
 
@@ -191,5 +191,5 @@
 	ipt_unregister_table(&packet_filter);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(iptable_filter_init);
+module_exit(iptable_filter_fini);
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 3212a5c..412fc96 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -201,7 +201,7 @@
 	},
 };
 
-static int __init init(void)
+static int __init iptable_mangle_init(void)
 {
 	int ret;
 
@@ -247,7 +247,7 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit iptable_mangle_fini(void)
 {
 	unsigned int i;
 
@@ -257,5 +257,5 @@
 	ipt_unregister_table(&packet_mangler);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(iptable_mangle_init);
+module_exit(iptable_mangle_fini);
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index fdb9e9c..03cc79a 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -116,7 +116,7 @@
 	},
 };
 
-static int __init init(void)
+static int __init iptable_raw_init(void)
 {
 	int ret;
 
@@ -144,7 +144,7 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit iptable_raw_fini(void)
 {
 	unsigned int i;
 
@@ -154,6 +154,6 @@
 	ipt_unregister_table(&packet_raw);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(iptable_raw_init);
+module_exit(iptable_raw_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index c8abc9d..4afbc69 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -571,18 +571,18 @@
 MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
 MODULE_LICENSE("GPL");
 
-static int __init init(void)
+static int __init nf_conntrack_l3proto_ipv4_init(void)
 {
 	need_conntrack();
 	return init_or_cleanup(1);
 }
 
-static void __exit fini(void)
+static void __exit nf_conntrack_l3proto_ipv4_fini(void)
 {
 	init_or_cleanup(0);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(nf_conntrack_l3proto_ipv4_init);
+module_exit(nf_conntrack_l3proto_ipv4_fini);
 
 EXPORT_SYMBOL(nf_ct_ipv4_gather_frags);
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index e688c68..91c2f41 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -223,7 +223,7 @@
 
  	/* In dangerous area, increase slowly. */
 	else if (sysctl_tcp_abc) {
- 		/* RFC3465: Apppriate Byte Count
+ 		/* RFC3465: Appropriate Byte Count
  		 * increase once for each full cwnd acked
  		 */
  		if (tp->bytes_acked >= tp->snd_cwnd*tp->mss_cache) {
diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c
new file mode 100644
index 0000000..0d7d386
--- /dev/null
+++ b/net/ipv4/tunnel4.c
@@ -0,0 +1,113 @@
+/* tunnel4.c: Generic IP tunnel transformer.
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/protocol.h>
+#include <net/xfrm.h>
+
+static struct xfrm_tunnel *tunnel4_handlers;
+static DEFINE_MUTEX(tunnel4_mutex);
+
+int xfrm4_tunnel_register(struct xfrm_tunnel *handler)
+{
+	struct xfrm_tunnel **pprev;
+	int ret = -EEXIST;
+	int priority = handler->priority;
+
+	mutex_lock(&tunnel4_mutex);
+
+	for (pprev = &tunnel4_handlers; *pprev; pprev = &(*pprev)->next) {
+		if ((*pprev)->priority > priority)
+			break;
+		if ((*pprev)->priority == priority)
+			goto err;
+	}
+
+	handler->next = *pprev;
+	*pprev = handler;
+
+	ret = 0;
+
+err:
+	mutex_unlock(&tunnel4_mutex);
+
+	return ret;
+}
+
+EXPORT_SYMBOL(xfrm4_tunnel_register);
+
+int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler)
+{
+	struct xfrm_tunnel **pprev;
+	int ret = -ENOENT;
+
+	mutex_lock(&tunnel4_mutex);
+
+	for (pprev = &tunnel4_handlers; *pprev; pprev = &(*pprev)->next) {
+		if (*pprev == handler) {
+			*pprev = handler->next;
+			ret = 0;
+			break;
+		}
+	}
+
+	mutex_unlock(&tunnel4_mutex);
+
+	synchronize_net();
+
+	return ret;
+}
+
+EXPORT_SYMBOL(xfrm4_tunnel_deregister);
+
+static int tunnel4_rcv(struct sk_buff *skb)
+{
+	struct xfrm_tunnel *handler;
+
+	for (handler = tunnel4_handlers; handler; handler = handler->next)
+		if (!handler->handler(skb))
+			return 0;
+
+	kfree_skb(skb);
+	return 0;
+}
+
+static void tunnel4_err(struct sk_buff *skb, u32 info)
+{
+	struct xfrm_tunnel *handler;
+
+	for (handler = tunnel4_handlers; handler; handler = handler->next)
+		if (!handler->err_handler(skb, info))
+			break;
+}
+
+static struct net_protocol tunnel4_protocol = {
+	.handler	=	tunnel4_rcv,
+	.err_handler	=	tunnel4_err,
+	.no_policy	=	1,
+};
+
+static int __init tunnel4_init(void)
+{
+	if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) {
+		printk(KERN_ERR "tunnel4 init: can't add protocol\n");
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+static void __exit tunnel4_fini(void)
+{
+	if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP))
+		printk(KERN_ERR "tunnel4 close: can't remove protocol\n");
+}
+
+module_init(tunnel4_init);
+module_exit(tunnel4_fini);
+MODULE_LICENSE("GPL");
diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
index b08d56b..2d67093 100644
--- a/net/ipv4/xfrm4_tunnel.c
+++ b/net/ipv4/xfrm4_tunnel.c
@@ -26,64 +26,6 @@
 	return 0;
 }
 
-static struct xfrm_tunnel *ipip_handler;
-static DEFINE_MUTEX(xfrm4_tunnel_mutex);
-
-int xfrm4_tunnel_register(struct xfrm_tunnel *handler)
-{
-	int ret;
-
-	mutex_lock(&xfrm4_tunnel_mutex);
-	ret = 0;
-	if (ipip_handler != NULL)
-		ret = -EINVAL;
-	if (!ret)
-		ipip_handler = handler;
-	mutex_unlock(&xfrm4_tunnel_mutex);
-
-	return ret;
-}
-
-EXPORT_SYMBOL(xfrm4_tunnel_register);
-
-int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler)
-{
-	int ret;
-
-	mutex_lock(&xfrm4_tunnel_mutex);
-	ret = 0;
-	if (ipip_handler != handler)
-		ret = -EINVAL;
-	if (!ret)
-		ipip_handler = NULL;
-	mutex_unlock(&xfrm4_tunnel_mutex);
-
-	synchronize_net();
-
-	return ret;
-}
-
-EXPORT_SYMBOL(xfrm4_tunnel_deregister);
-
-static int ipip_rcv(struct sk_buff *skb)
-{
-	struct xfrm_tunnel *handler = ipip_handler;
-
-	/* Tunnel devices take precedence.  */
-	if (handler && handler->handler(skb) == 0)
-		return 0;
-
-	return xfrm4_rcv(skb);
-}
-
-static void ipip_err(struct sk_buff *skb, u32 info)
-{
-	struct xfrm_tunnel *handler = ipip_handler;
-
-	if (handler)
-		handler->err_handler(skb, info);
-}
-
 static int ipip_init_state(struct xfrm_state *x)
 {
 	if (!x->props.mode)
@@ -111,10 +53,15 @@
 	.output		= ipip_output
 };
 
-static struct net_protocol ipip_protocol = {
-	.handler	=	ipip_rcv,
-	.err_handler	=	ipip_err,
-	.no_policy	=	1,
+static int xfrm_tunnel_err(struct sk_buff *skb, u32 info)
+{
+	return -ENOENT;
+}
+
+static struct xfrm_tunnel xfrm_tunnel_handler = {
+	.handler	=	xfrm4_rcv,
+	.err_handler	=	xfrm_tunnel_err,
+	.priority	=	2,
 };
 
 static int __init ipip_init(void)
@@ -123,8 +70,8 @@
 		printk(KERN_INFO "ipip init: can't add xfrm type\n");
 		return -EAGAIN;
 	}
-	if (inet_add_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) {
-		printk(KERN_INFO "ipip init: can't add protocol\n");
+	if (xfrm4_tunnel_register(&xfrm_tunnel_handler)) {
+		printk(KERN_INFO "ipip init: can't add xfrm handler\n");
 		xfrm_unregister_type(&ipip_type, AF_INET);
 		return -EAGAIN;
 	}
@@ -133,8 +80,8 @@
 
 static void __exit ipip_fini(void)
 {
-	if (inet_del_protocol(&ipip_protocol, IPPROTO_IPIP) < 0)
-		printk(KERN_INFO "ipip close: can't remove protocol\n");
+	if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler))
+		printk(KERN_INFO "ipip close: can't remove xfrm handler\n");
 	if (xfrm_unregister_type(&ipip_type, AF_INET) < 0)
 		printk(KERN_INFO "ipip close: can't remove xfrm type\n");
 }
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index e6f83b6..f8a107a 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -88,7 +88,7 @@
 	tristate "IPv6: IPComp transformation"
 	depends on IPV6
 	select XFRM
-	select INET6_TUNNEL
+	select INET6_XFRM_TUNNEL
 	select CRYPTO
 	select CRYPTO_DEFLATE
 	---help---
@@ -97,19 +97,18 @@
 
 	  If unsure, say Y.
 
+config INET6_XFRM_TUNNEL
+	tristate
+	select INET6_TUNNEL
+	default n
+
 config INET6_TUNNEL
-	tristate "IPv6: tunnel transformation"
-	depends on IPV6
-	select XFRM
-	---help---
-	  Support for generic IPv6-in-IPv6 tunnel transformation, which is
-	  required by the IPv6-in-IPv6 tunneling module as well as tunnel mode
-	  IPComp.
-	  
-	  If unsure, say Y.
+	tristate
+	default n
 
 config IPV6_TUNNEL
 	tristate "IPv6: IPv6-in-IPv6 tunnel"
+	select INET6_TUNNEL
 	depends on IPV6
 	---help---
 	  Support for IPv6-in-IPv6 tunnels described in RFC 2473.
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 41877ab..a760b09 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -18,7 +18,8 @@
 obj-$(CONFIG_INET6_AH) += ah6.o
 obj-$(CONFIG_INET6_ESP) += esp6.o
 obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
-obj-$(CONFIG_INET6_TUNNEL) += xfrm6_tunnel.o 
+obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o
+obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o
 obj-$(CONFIG_NETFILTER)	+= netfilter/
 
 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 01c62a0..445006e 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -143,7 +143,7 @@
 				struct prefix_info *pinfo);
 static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev);
 
-static struct notifier_block *inet6addr_chain;
+static ATOMIC_NOTIFIER_HEAD(inet6addr_chain);
 
 struct ipv6_devconf ipv6_devconf = {
 	.forwarding		= 0,
@@ -593,7 +593,7 @@
 	read_unlock_bh(&addrconf_lock);
 
 	if (likely(err == 0))
-		notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);
+		atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);
 	else {
 		kfree(ifa);
 		ifa = ERR_PTR(err);
@@ -688,7 +688,7 @@
 
 	ipv6_ifa_notify(RTM_DELADDR, ifp);
 
-	notifier_call_chain(&inet6addr_chain,NETDEV_DOWN,ifp);
+	atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifp);
 
 	addrconf_del_timer(ifp);
 
@@ -3767,12 +3767,12 @@
 
 int register_inet6addr_notifier(struct notifier_block *nb)
 {
-        return notifier_chain_register(&inet6addr_chain, nb);
+        return atomic_notifier_chain_register(&inet6addr_chain, nb);
 }
 
 int unregister_inet6addr_notifier(struct notifier_block *nb)
 {
-        return notifier_chain_unregister(&inet6addr_chain,nb);
+        return atomic_notifier_chain_unregister(&inet6addr_chain,nb);
 }
 
 /*
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 4859753..ff9040c 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -44,7 +44,6 @@
 
 #include <net/ip.h>
 #include <net/ipv6.h>
-#include <net/protocol.h>
 #include <net/ip6_route.h>
 #include <net/addrconf.h>
 #include <net/ip6_tunnel.h>
@@ -391,7 +390,7 @@
  *   to the specifications in RFC 2473.
  **/
 
-static void 
+static int
 ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 	   int type, int code, int offset, __u32 info)
 {
@@ -402,6 +401,7 @@
 	int rel_code = ICMPV6_ADDR_UNREACH;
 	__u32 rel_info = 0;
 	__u16 len;
+	int err = -ENOENT;
 
 	/* If the packet doesn't contain the original IPv6 header we are 
 	   in trouble since we might need the source address for further 
@@ -411,6 +411,8 @@
 	if ((t = ip6ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL)
 		goto out;
 
+	err = 0;
+
 	switch (type) {
 		__u32 teli;
 		struct ipv6_tlv_tnl_enc_lim *tel;
@@ -492,6 +494,7 @@
 	}
 out:
 	read_unlock(&ip6ip6_lock);
+	return err;
 }
 
 static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph,
@@ -511,9 +514,8 @@
  **/
 
 static int 
-ip6ip6_rcv(struct sk_buff **pskb)
+ip6ip6_rcv(struct sk_buff *skb)
 {
-	struct sk_buff *skb = *pskb;
 	struct ipv6hdr *ipv6h;
 	struct ip6_tnl *t;
 
@@ -1112,39 +1114,12 @@
 	return 0;
 }
 
-#ifdef CONFIG_INET6_TUNNEL
 static struct xfrm6_tunnel ip6ip6_handler = {
 	.handler	= ip6ip6_rcv,
 	.err_handler	= ip6ip6_err,
+	.priority	=	1,
 };
 
-static inline int ip6ip6_register(void)
-{
-	return xfrm6_tunnel_register(&ip6ip6_handler);
-}
-
-static inline int ip6ip6_unregister(void)
-{
-	return xfrm6_tunnel_deregister(&ip6ip6_handler);
-}
-#else
-static struct inet6_protocol xfrm6_tunnel_protocol = {
-	.handler	= ip6ip6_rcv,
-	.err_handler	= ip6ip6_err,
-	.flags		= INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
-};
-
-static inline int ip6ip6_register(void)
-{
-	return inet6_add_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6);
-}
-
-static inline int ip6ip6_unregister(void)
-{
-	return inet6_del_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6);
-}
-#endif
-
 /**
  * ip6_tunnel_init - register protocol and reserve needed resources
  *
@@ -1155,7 +1130,7 @@
 {
 	int  err;
 
-	if (ip6ip6_register() < 0) {
+	if (xfrm6_tunnel_register(&ip6ip6_handler)) {
 		printk(KERN_ERR "ip6ip6 init: can't register tunnel\n");
 		return -EAGAIN;
 	}
@@ -1174,7 +1149,7 @@
 	}
 	return 0;
 fail:
-	ip6ip6_unregister();
+	xfrm6_tunnel_deregister(&ip6ip6_handler);
 	return err;
 }
 
@@ -1184,7 +1159,7 @@
 
 static void __exit ip6_tunnel_cleanup(void)
 {
-	if (ip6ip6_unregister() < 0)
+	if (xfrm6_tunnel_deregister(&ip6ip6_handler))
 		printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n");
 
 	unregister_netdev(ip6ip6_fb_tnl_dev);
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index 028b636..d4cfec3 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -228,6 +228,9 @@
 
 	t->id.proto = IPPROTO_IPV6;
 	t->id.spi = xfrm6_tunnel_alloc_spi((xfrm_address_t *)&x->props.saddr);
+	if (!t->id.spi)
+		goto error;
+
 	memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr));
 	memcpy(&t->sel, &x->sel, sizeof(t->sel));
 	t->props.family = AF_INET6;
@@ -243,7 +246,9 @@
 	return t;
 
 error:
+	t->km.state = XFRM_STATE_DEAD;
 	xfrm_state_put(t);
+	t = NULL;
 	goto out;
 }
 
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 344eab3..e81c6a9 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -713,13 +713,13 @@
 	return status;
 }
 
-static int __init init(void)
+static int __init ip6_queue_init(void)
 {
 	
 	return init_or_cleanup(1);
 }
 
-static void __exit fini(void)
+static void __exit ip6_queue_fini(void)
 {
 	init_or_cleanup(0);
 }
@@ -727,5 +727,5 @@
 MODULE_DESCRIPTION("IPv6 packet queue handler");
 MODULE_LICENSE("GPL");
 
-module_init(init);
-module_exit(fini);
+module_init(ip6_queue_init);
+module_exit(ip6_queue_fini);
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index db3c9ae..3ecf2db 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1406,7 +1406,7 @@
 	.family		= AF_INET6,
 };
 
-static int __init init(void)
+static int __init ip6_tables_init(void)
 {
 	int ret;
 
@@ -1429,7 +1429,7 @@
 	return 0;
 }
 
-static void __exit fini(void)
+static void __exit ip6_tables_fini(void)
 {
 	nf_unregister_sockopt(&ip6t_sockopts);
 	xt_unregister_match(&icmp6_matchstruct);
@@ -1517,5 +1517,5 @@
 EXPORT_SYMBOL(ip6t_ext_hdr);
 EXPORT_SYMBOL(ipv6_find_hdr);
 
-module_init(init);
-module_exit(fini);
+module_init(ip6_tables_init);
+module_exit(ip6_tables_fini);
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c
index da14c6d..b8eff8e 100644
--- a/net/ipv6/netfilter/ip6t_HL.c
+++ b/net/ipv6/netfilter/ip6t_HL.c
@@ -93,15 +93,15 @@
 	.me		= THIS_MODULE
 };
 
-static int __init init(void)
+static int __init ip6t_hl_init(void)
 {
 	return ip6t_register_target(&ip6t_HL);
 }
 
-static void __exit fini(void)
+static void __exit ip6t_hl_fini(void)
 {
 	ip6t_unregister_target(&ip6t_HL);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip6t_hl_init);
+module_exit(ip6t_hl_fini);
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index 07c6bcb..a96c0de 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -483,7 +483,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ip6t_log_init(void)
 {
 	if (ip6t_register_target(&ip6t_log_reg))
 		return -EINVAL;
@@ -497,11 +497,11 @@
 	return 0;
 }
 
-static void __exit fini(void)
+static void __exit ip6t_log_fini(void)
 {
 	nf_log_unregister_logger(&ip6t_logger);
 	ip6t_unregister_target(&ip6t_log_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip6t_log_init);
+module_exit(ip6t_log_fini);
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index ddfa385..de1175c 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -255,17 +255,17 @@
 	.me		= THIS_MODULE
 };
 
-static int __init init(void)
+static int __init ip6t_reject_init(void)
 {
 	if (ip6t_register_target(&ip6t_reject_reg))
 		return -EINVAL;
 	return 0;
 }
 
-static void __exit fini(void)
+static void __exit ip6t_reject_fini(void)
 {
 	ip6t_unregister_target(&ip6t_reject_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip6t_reject_init);
+module_exit(ip6t_reject_fini);
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c
index 178f6fb..2f7bb20 100644
--- a/net/ipv6/netfilter/ip6t_ah.c
+++ b/net/ipv6/netfilter/ip6t_ah.c
@@ -122,15 +122,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ip6t_ah_init(void)
 {
 	return ip6t_register_match(&ah_match);
 }
 
-static void __exit cleanup(void)
+static void __exit ip6t_ah_fini(void)
 {
 	ip6t_unregister_match(&ah_match);
 }
 
-module_init(init);
-module_exit(cleanup);
+module_init(ip6t_ah_init);
+module_exit(ip6t_ah_fini);
diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c
index e97a702..9422413 100644
--- a/net/ipv6/netfilter/ip6t_dst.c
+++ b/net/ipv6/netfilter/ip6t_dst.c
@@ -206,15 +206,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ip6t_dst_init(void)
 {
 	return ip6t_register_match(&opts_match);
 }
 
-static void __exit cleanup(void)
+static void __exit ip6t_dst_fini(void)
 {
 	ip6t_unregister_match(&opts_match);
 }
 
-module_init(init);
-module_exit(cleanup);
+module_init(ip6t_dst_init);
+module_exit(ip6t_dst_fini);
diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c
index 540b8bf..36bedad 100644
--- a/net/ipv6/netfilter/ip6t_esp.c
+++ b/net/ipv6/netfilter/ip6t_esp.c
@@ -101,15 +101,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ip6t_esp_init(void)
 {
 	return ip6t_register_match(&esp_match);
 }
 
-static void __exit cleanup(void)
+static void __exit ip6t_esp_fini(void)
 {
 	ip6t_unregister_match(&esp_match);
 }
 
-module_init(init);
-module_exit(cleanup);
+module_init(ip6t_esp_init);
+module_exit(ip6t_esp_fini);
diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c
index d4b0bad..94dbdb8 100644
--- a/net/ipv6/netfilter/ip6t_eui64.c
+++ b/net/ipv6/netfilter/ip6t_eui64.c
@@ -70,15 +70,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ip6t_eui64_init(void)
 {
 	return ip6t_register_match(&eui64_match);
 }
 
-static void __exit fini(void)
+static void __exit ip6t_eui64_fini(void)
 {
 	ip6t_unregister_match(&eui64_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip6t_eui64_init);
+module_exit(ip6t_eui64_fini);
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c
index 4c41e14..06768c8 100644
--- a/net/ipv6/netfilter/ip6t_frag.c
+++ b/net/ipv6/netfilter/ip6t_frag.c
@@ -139,15 +139,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ip6t_frag_init(void)
 {
 	return ip6t_register_match(&frag_match);
 }
 
-static void __exit cleanup(void)
+static void __exit ip6t_frag_fini(void)
 {
 	ip6t_unregister_match(&frag_match);
 }
 
-module_init(init);
-module_exit(cleanup);
+module_init(ip6t_frag_init);
+module_exit(ip6t_frag_fini);
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c
index b4a1fdf..374f1be 100644
--- a/net/ipv6/netfilter/ip6t_hbh.c
+++ b/net/ipv6/netfilter/ip6t_hbh.c
@@ -206,15 +206,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ip6t_hbh_init(void)
 {
 	return ip6t_register_match(&opts_match);
 }
 
-static void __exit cleanup(void)
+static void __exit ip6t_hbh_fini(void)
 {
 	ip6t_unregister_match(&opts_match);
 }
 
-module_init(init);
-module_exit(cleanup);
+module_init(ip6t_hbh_init);
+module_exit(ip6t_hbh_fini);
diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c
index 3740557..44a729e 100644
--- a/net/ipv6/netfilter/ip6t_hl.c
+++ b/net/ipv6/netfilter/ip6t_hl.c
@@ -55,16 +55,16 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ip6t_hl_init(void)
 {
 	return ip6t_register_match(&hl_match);
 }
 
-static void __exit fini(void)
+static void __exit ip6t_hl_fini(void)
 {
 	ip6t_unregister_match(&hl_match);
 
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip6t_hl_init);
+module_exit(ip6t_hl_fini);
diff --git a/net/ipv6/netfilter/ip6t_multiport.c b/net/ipv6/netfilter/ip6t_multiport.c
index 752b65d..10c48ba 100644
--- a/net/ipv6/netfilter/ip6t_multiport.c
+++ b/net/ipv6/netfilter/ip6t_multiport.c
@@ -111,15 +111,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ip6t_multiport_init(void)
 {
 	return ip6t_register_match(&multiport_match);
 }
 
-static void __exit fini(void)
+static void __exit ip6t_multiport_fini(void)
 {
 	ip6t_unregister_match(&multiport_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip6t_multiport_init);
+module_exit(ip6t_multiport_fini);
diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c
index e2cee3b..5d04799 100644
--- a/net/ipv6/netfilter/ip6t_owner.c
+++ b/net/ipv6/netfilter/ip6t_owner.c
@@ -79,15 +79,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ip6t_owner_init(void)
 {
 	return ip6t_register_match(&owner_match);
 }
 
-static void __exit fini(void)
+static void __exit ip6t_owner_fini(void)
 {
 	ip6t_unregister_match(&owner_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip6t_owner_init);
+module_exit(ip6t_owner_fini);
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
index 4c6b55b..fbb0184 100644
--- a/net/ipv6/netfilter/ip6t_rt.c
+++ b/net/ipv6/netfilter/ip6t_rt.c
@@ -225,15 +225,15 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ip6t_rt_init(void)
 {
 	return ip6t_register_match(&rt_match);
 }
 
-static void __exit cleanup(void)
+static void __exit ip6t_rt_fini(void)
 {
 	ip6t_unregister_match(&rt_match);
 }
 
-module_init(init);
-module_exit(cleanup);
+module_init(ip6t_rt_init);
+module_exit(ip6t_rt_fini);
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index ce4a968..e5e724d 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -159,7 +159,7 @@
 static int forward = NF_ACCEPT;
 module_param(forward, bool, 0000);
 
-static int __init init(void)
+static int __init ip6table_filter_init(void)
 {
 	int ret;
 
@@ -201,7 +201,7 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit ip6table_filter_fini(void)
 {
 	unsigned int i;
 
@@ -211,5 +211,5 @@
 	ip6t_unregister_table(&packet_filter);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip6table_filter_init);
+module_exit(ip6table_filter_fini);
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index 30a4627..e1f0f6a 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -228,7 +228,7 @@
 	},
 };
 
-static int __init init(void)
+static int __init ip6table_mangle_init(void)
 {
 	int ret;
 
@@ -274,7 +274,7 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit ip6table_mangle_fini(void)
 {
 	unsigned int i;
 
@@ -284,5 +284,5 @@
 	ip6t_unregister_table(&packet_mangler);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip6table_mangle_init);
+module_exit(ip6table_mangle_fini);
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index db28ba3..54d1fff 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -142,7 +142,7 @@
 	},
 };
 
-static int __init init(void)
+static int __init ip6table_raw_init(void)
 {
 	int ret;
 
@@ -170,7 +170,7 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit ip6table_raw_fini(void)
 {
 	unsigned int i;
 
@@ -180,6 +180,6 @@
 	ip6t_unregister_table(&packet_raw);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ip6table_raw_init);
+module_exit(ip6table_raw_fini);
 MODULE_LICENSE("GPL");
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index c16f629..c8b5a96 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -588,16 +588,16 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
 
-static int __init init(void)
+static int __init nf_conntrack_l3proto_ipv6_init(void)
 {
 	need_conntrack();
 	return init_or_cleanup(1);
 }
 
-static void __exit fini(void)
+static void __exit nf_conntrack_l3proto_ipv6_fini(void)
 {
 	init_or_cleanup(0);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(nf_conntrack_l3proto_ipv6_init);
+module_exit(nf_conntrack_l3proto_ipv6_fini);
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c
new file mode 100644
index 0000000..5659b52
--- /dev/null
+++ b/net/ipv6/tunnel6.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C)2003,2004 USAGI/WIDE Project
+ *
+ * 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
+ *
+ * Authors	Mitsuru KANDA  <mk@linux-ipv6.org>
+ * 		YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/protocol.h>
+#include <net/xfrm.h>
+
+static struct xfrm6_tunnel *tunnel6_handlers;
+static DEFINE_MUTEX(tunnel6_mutex);
+
+int xfrm6_tunnel_register(struct xfrm6_tunnel *handler)
+{
+	struct xfrm6_tunnel **pprev;
+	int ret = -EEXIST;
+	int priority = handler->priority;
+
+	mutex_lock(&tunnel6_mutex);
+
+	for (pprev = &tunnel6_handlers; *pprev; pprev = &(*pprev)->next) {
+		if ((*pprev)->priority > priority)
+			break;
+		if ((*pprev)->priority == priority)
+			goto err;
+	}
+
+	handler->next = *pprev;
+	*pprev = handler;
+
+	ret = 0;
+
+err:
+	mutex_unlock(&tunnel6_mutex);
+
+	return ret;
+}
+
+EXPORT_SYMBOL(xfrm6_tunnel_register);
+
+int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler)
+{
+	struct xfrm6_tunnel **pprev;
+	int ret = -ENOENT;
+
+	mutex_lock(&tunnel6_mutex);
+
+	for (pprev = &tunnel6_handlers; *pprev; pprev = &(*pprev)->next) {
+		if (*pprev == handler) {
+			*pprev = handler->next;
+			ret = 0;
+			break;
+		}
+	}
+
+	mutex_unlock(&tunnel6_mutex);
+
+	synchronize_net();
+
+	return ret;
+}
+
+EXPORT_SYMBOL(xfrm6_tunnel_deregister);
+
+static int tunnel6_rcv(struct sk_buff **pskb)
+{
+	struct sk_buff *skb = *pskb;
+	struct xfrm6_tunnel *handler;
+
+	for (handler = tunnel6_handlers; handler; handler = handler->next)
+		if (!handler->handler(skb))
+			return 0;
+
+	kfree_skb(skb);
+	return 0;
+}
+
+static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+			int type, int code, int offset, __u32 info)
+{
+	struct xfrm6_tunnel *handler;
+
+	for (handler = tunnel6_handlers; handler; handler = handler->next)
+		if (!handler->err_handler(skb, opt, type, code, offset, info))
+			break;
+}
+
+static struct inet6_protocol tunnel6_protocol = {
+	.handler	= tunnel6_rcv,
+	.err_handler	= tunnel6_err,
+	.flags          = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
+};
+
+static int __init tunnel6_init(void)
+{
+	if (inet6_add_protocol(&tunnel6_protocol, IPPROTO_IPV6)) {
+		printk(KERN_ERR "tunnel6 init(): can't add protocol\n");
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+static void __exit tunnel6_fini(void)
+{
+	if (inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6))
+		printk(KERN_ERR "tunnel6 close: can't remove protocol\n");
+}
+
+module_init(tunnel6_init);
+module_exit(tunnel6_fini);
+MODULE_LICENSE("GPL");
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index 1ca2da6..cccf8b7 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -28,9 +28,8 @@
 		IP6_ECN_set_ce(inner_iph);
 }
 
-int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi)
+int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
 {
-	struct sk_buff *skb = *pskb;
 	int err;
 	u32 seq;
 	struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH];
@@ -159,5 +158,5 @@
 
 int xfrm6_rcv(struct sk_buff **pskb)
 {
-	return xfrm6_rcv_spi(pskb, 0);
+	return xfrm6_rcv_spi(*pskb, 0);
 }
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 08f9abb..a8f6776 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -28,7 +28,6 @@
 #include <net/ip.h>
 #include <net/xfrm.h>
 #include <net/ipv6.h>
-#include <net/protocol.h>
 #include <linux/ipv6.h>
 #include <linux/icmpv6.h>
 #include <linux/mutex.h>
@@ -357,71 +356,18 @@
 	return 0;
 }
 
-static struct xfrm6_tunnel *xfrm6_tunnel_handler;
-static DEFINE_MUTEX(xfrm6_tunnel_mutex);
-
-int xfrm6_tunnel_register(struct xfrm6_tunnel *handler)
+static int xfrm6_tunnel_rcv(struct sk_buff *skb)
 {
-	int ret;
-
-	mutex_lock(&xfrm6_tunnel_mutex);
-	ret = 0;
-	if (xfrm6_tunnel_handler != NULL)
-		ret = -EINVAL;
-	if (!ret)
-		xfrm6_tunnel_handler = handler;
-	mutex_unlock(&xfrm6_tunnel_mutex);
-
-	return ret;
-}
-
-EXPORT_SYMBOL(xfrm6_tunnel_register);
-
-int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler)
-{
-	int ret;
-
-	mutex_lock(&xfrm6_tunnel_mutex);
-	ret = 0;
-	if (xfrm6_tunnel_handler != handler)
-		ret = -EINVAL;
-	if (!ret)
-		xfrm6_tunnel_handler = NULL;
-	mutex_unlock(&xfrm6_tunnel_mutex);
-
-	synchronize_net();
-
-	return ret;
-}
-
-EXPORT_SYMBOL(xfrm6_tunnel_deregister);
-
-static int xfrm6_tunnel_rcv(struct sk_buff **pskb)
-{
-	struct sk_buff *skb = *pskb;
-	struct xfrm6_tunnel *handler = xfrm6_tunnel_handler;
 	struct ipv6hdr *iph = skb->nh.ipv6h;
 	u32 spi;
 
-	/* device-like_ip6ip6_handler() */
-	if (handler && handler->handler(pskb) == 0)
-		return 0;
-
 	spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
-	return xfrm6_rcv_spi(pskb, spi);
+	return xfrm6_rcv_spi(skb, spi);
 }
 
-static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-			     int type, int code, int offset, __u32 info)
+static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+			    int type, int code, int offset, __u32 info)
 {
-	struct xfrm6_tunnel *handler = xfrm6_tunnel_handler;
-
-	/* call here first for device-like ip6ip6 err handling */
-	if (handler) {
-		handler->err_handler(skb, opt, type, code, offset, info);
-		return;
-	}
-
 	/* xfrm6_tunnel native err handling */
 	switch (type) {
 	case ICMPV6_DEST_UNREACH: 
@@ -462,7 +408,8 @@
 	default:
 		break;
 	}
-	return;
+
+	return 0;
 }
 
 static int xfrm6_tunnel_init_state(struct xfrm_state *x)
@@ -493,10 +440,10 @@
 	.output		= xfrm6_tunnel_output,
 };
 
-static struct inet6_protocol xfrm6_tunnel_protocol = {
+static struct xfrm6_tunnel xfrm6_tunnel_handler = {
 	.handler	= xfrm6_tunnel_rcv,
-	.err_handler	= xfrm6_tunnel_err, 
-	.flags          = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
+	.err_handler	= xfrm6_tunnel_err,
+	.priority	= 2,
 };
 
 static int __init xfrm6_tunnel_init(void)
@@ -508,16 +455,16 @@
 			   "xfrm6_tunnel init: can't add xfrm type\n");
 		return -EAGAIN;
 	}
-	if (inet6_add_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6) < 0) {
+	if (xfrm6_tunnel_register(&xfrm6_tunnel_handler)) {
 		X6TPRINTK1(KERN_ERR
-			   "xfrm6_tunnel init(): can't add protocol\n");
+			   "xfrm6_tunnel init(): can't add handler\n");
 		xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
 		return -EAGAIN;
 	}
 	if (xfrm6_tunnel_spi_init() < 0) {
 		X6TPRINTK1(KERN_ERR
 			   "xfrm6_tunnel init: failed to initialize spi\n");
-		inet6_del_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6);
+		xfrm6_tunnel_deregister(&xfrm6_tunnel_handler);
 		xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
 		return -EAGAIN;
 	}
@@ -529,9 +476,9 @@
 	X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__);
 
 	xfrm6_tunnel_spi_fini();
-	if (inet6_del_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6) < 0)
+	if (xfrm6_tunnel_deregister(&xfrm6_tunnel_handler))
 		X6TPRINTK1(KERN_ERR 
-			   "xfrm6_tunnel close: can't remove protocol\n");
+			   "xfrm6_tunnel close: can't remove handler\n");
 	if (xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6) < 0)
 		X6TPRINTK1(KERN_ERR
 			   "xfrm6_tunnel close: can't remove xfrm type\n");
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index 0fb513a..2dbf134 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -1892,6 +1892,29 @@
 	return rc;
 }
 
+
+#ifdef CONFIG_COMPAT
+static int ipx_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	/*
+	 * These 4 commands use same structure on 32bit and 64bit.  Rest of IPX
+	 * commands is handled by generic ioctl code.  As these commands are
+	 * SIOCPROTOPRIVATE..SIOCPROTOPRIVATE+3, they cannot be handled by generic
+	 * code.
+	 */
+	switch (cmd) {
+	case SIOCAIPXITFCRT:
+	case SIOCAIPXPRISLT:
+	case SIOCIPXCFGDATA:
+	case SIOCIPXNCPCONN:
+		return ipx_ioctl(sock, cmd, arg);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+#endif
+
+
 /*
  * Socket family declarations
  */
@@ -1913,6 +1936,9 @@
 	.getname	= ipx_getname,
 	.poll		= datagram_poll,
 	.ioctl		= ipx_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= ipx_compat_ioctl,
+#endif
 	.listen		= sock_no_listen,
 	.shutdown	= sock_no_shutdown, /* FIXME: support shutdown */
 	.setsockopt	= ipx_setsockopt,
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index 7594456..2f37c9f 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -1302,7 +1302,7 @@
 	if (sk->sk_state != TCP_ESTABLISHED)
 		return -ENOTCONN;
 
-	/* Check that we don't send out to big frames */
+	/* Check that we don't send out too big frames */
 	if (len > self->max_data_size) {
 		IRDA_DEBUG(2, "%s(), Chopping frame from %zd to %d bytes!\n",
 			   __FUNCTION__, len, self->max_data_size);
@@ -1546,7 +1546,7 @@
 	IRDA_ASSERT(self != NULL, return -1;);
 
 	/*
-	 * Check that we don't send out to big frames. This is an unreliable
+	 * Check that we don't send out too big frames. This is an unreliable
 	 * service, so we have no fragmentation and no coalescence
 	 */
 	if (len > self->max_data_size) {
@@ -1642,7 +1642,7 @@
 	}
 
 	/*
-	 * Check that we don't send out to big frames. This is an unreliable
+	 * Check that we don't send out too big frames. This is an unreliable
 	 * service, so we have no fragmentation and no coalescence
 	 */
 	if (len > self->max_data_size) {
@@ -1830,6 +1830,19 @@
 	return 0;
 }
 
+#ifdef CONFIG_COMPAT
+/*
+ * Function irda_ioctl (sock, cmd, arg)
+ */
+static int irda_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	/*
+	 * All IRDA's ioctl are standard ones.
+	 */
+	return -ENOIOCTLCMD;
+}
+#endif
+
 /*
  * Function irda_setsockopt (sock, level, optname, optval, optlen)
  *
@@ -2476,6 +2489,9 @@
 	.getname =	irda_getname,
 	.poll =		irda_poll,
 	.ioctl =	irda_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl =	irda_compat_ioctl,
+#endif
 	.listen =	irda_listen,
 	.shutdown =	irda_shutdown,
 	.setsockopt =	irda_setsockopt,
@@ -2497,6 +2513,9 @@
 	.getname =	irda_getname,
 	.poll =		datagram_poll,
 	.ioctl =	irda_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl =	irda_compat_ioctl,
+#endif
 	.listen =	irda_listen,
 	.shutdown =	irda_shutdown,
 	.setsockopt =	irda_setsockopt,
@@ -2518,6 +2537,9 @@
 	.getname =	irda_getname,
 	.poll =		datagram_poll,
 	.ioctl =	irda_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl =	irda_compat_ioctl,
+#endif
 	.listen =	irda_listen,
 	.shutdown =	irda_shutdown,
 	.setsockopt =	irda_setsockopt,
@@ -2540,6 +2562,9 @@
 	.getname =	irda_getname,
 	.poll =		datagram_poll,
 	.ioctl =	irda_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl =	irda_compat_ioctl,
+#endif
 	.listen =	sock_no_listen,
 	.shutdown =	irda_shutdown,
 	.setsockopt =	irda_setsockopt,
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 0ae281d..56389c8 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -90,8 +90,8 @@
 static unsigned int nf_conntrack_next_id;
 static unsigned int nf_conntrack_expect_next_id;
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
-struct notifier_block *nf_conntrack_chain;
-struct notifier_block *nf_conntrack_expect_chain;
+ATOMIC_NOTIFIER_HEAD(nf_conntrack_chain);
+ATOMIC_NOTIFIER_HEAD(nf_conntrack_expect_chain);
 
 DEFINE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache);
 
@@ -103,7 +103,7 @@
 	DEBUGP("ecache: delivering events for %p\n", ecache->ct);
 	if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct)
 	    && ecache->events)
-		notifier_call_chain(&nf_conntrack_chain, ecache->events,
+		atomic_notifier_call_chain(&nf_conntrack_chain, ecache->events,
 				    ecache->ct);
 
 	ecache->events = 0;
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index cd191b0..e38a4b5 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -624,7 +624,7 @@
 static char ftp_names[MAX_PORTS][2][sizeof("ftp-65535")];
 
 /* don't make this __exit, since it's called from __init ! */
-static void fini(void)
+static void nf_conntrack_ftp_fini(void)
 {
 	int i, j;
 	for (i = 0; i < ports_c; i++) {
@@ -642,7 +642,7 @@
 	kfree(ftp_buffer);
 }
 
-static int __init init(void)
+static int __init nf_conntrack_ftp_init(void)
 {
 	int i, j = -1, ret = 0;
 	char *tmpname;
@@ -683,7 +683,7 @@
 				printk("nf_ct_ftp: failed to register helper "
 				       " for pf: %d port: %d\n",
 					ftp[i][j].tuple.src.l3num, ports[i]);
-				fini();
+				nf_conntrack_ftp_fini();
 				return ret;
 			}
 		}
@@ -692,5 +692,5 @@
 	return 0;
 }
 
-module_init(init);
-module_exit(fini);
+module_init(nf_conntrack_ftp_init);
+module_exit(nf_conntrack_ftp_fini);
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index cf798e6..9cccc32 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -615,7 +615,7 @@
 static struct ctl_table_header *nf_ct_sysctl_header;
 #endif
 
-int __init init(void)
+int __init nf_conntrack_proto_sctp_init(void)
 {
 	int ret;
 
@@ -652,7 +652,7 @@
 	return ret;
 }
 
-void __exit fini(void)
+void __exit nf_conntrack_proto_sctp_fini(void)
 {
 	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp6);
 	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp4);
@@ -662,8 +662,8 @@
 	DEBUGP("SCTP conntrack module unloaded\n");
 }
 
-module_init(init);
-module_exit(fini);
+module_init(nf_conntrack_proto_sctp_init);
+module_exit(nf_conntrack_proto_sctp_fini);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Kiran Kumar Immidi");
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 75577e1..c72aa3c 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -806,18 +806,18 @@
 	nf_ct_iterate_cleanup(kill_proto, proto);
 }
 
-static int __init init(void)
+static int __init nf_conntrack_standalone_init(void)
 {
 	return init_or_cleanup(1);
 }
 
-static void __exit fini(void)
+static void __exit nf_conntrack_standalone_fini(void)
 {
 	init_or_cleanup(0);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(nf_conntrack_standalone_init);
+module_exit(nf_conntrack_standalone_fini);
 
 /* Some modules need us, but don't depend directly on any symbol.
    They should call this. */
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 54cbbaa..3e3f544 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -1081,13 +1081,13 @@
 	return status;
 }
 
-static int __init init(void)
+static int __init nfnetlink_log_init(void)
 {
 	
 	return init_or_cleanup(1);
 }
 
-static void __exit fini(void)
+static void __exit nfnetlink_log_fini(void)
 {
 	init_or_cleanup(0);
 }
@@ -1097,5 +1097,5 @@
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ULOG);
 
-module_init(init);
-module_exit(fini);
+module_init(nfnetlink_log_init);
+module_exit(nfnetlink_log_fini);
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index b570166..d0e62f6 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1117,13 +1117,13 @@
 	return status;
 }
 
-static int __init init(void)
+static int __init nfnetlink_queue_init(void)
 {
 	
 	return init_or_cleanup(1);
 }
 
-static void __exit fini(void)
+static void __exit nfnetlink_queue_fini(void)
 {
 	init_or_cleanup(0);
 }
@@ -1133,5 +1133,5 @@
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_QUEUE);
 
-module_init(init);
-module_exit(fini);
+module_init(nfnetlink_queue_init);
+module_exit(nfnetlink_queue_fini);
diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c
index 3cd2ac9..e54e577 100644
--- a/net/netfilter/xt_CLASSIFY.c
+++ b/net/netfilter/xt_CLASSIFY.c
@@ -62,7 +62,7 @@
 };
 
 
-static int __init init(void)
+static int __init xt_classify_init(void)
 {
 	int ret;
 
@@ -77,11 +77,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_classify_fini(void)
 {
 	xt_unregister_target(&classify_reg);
 	xt_unregister_target(&classify6_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_classify_init);
+module_exit(xt_classify_fini);
diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c
index 35448b8..60c375d 100644
--- a/net/netfilter/xt_CONNMARK.c
+++ b/net/netfilter/xt_CONNMARK.c
@@ -115,7 +115,7 @@
 	.me		= THIS_MODULE
 };
 
-static int __init init(void)
+static int __init xt_connmark_init(void)
 {
 	int ret;
 
@@ -132,11 +132,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_connmark_fini(void)
 {
 	xt_unregister_target(&connmark_reg);
 	xt_unregister_target(&connmark6_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_connmark_init);
+module_exit(xt_connmark_fini);
diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c
index 73bdd5c..ee9c34e 100644
--- a/net/netfilter/xt_MARK.c
+++ b/net/netfilter/xt_MARK.c
@@ -145,7 +145,7 @@
 	.revision	= 0,
 };
 
-static int __init init(void)
+static int __init xt_mark_init(void)
 {
 	int err;
 
@@ -166,12 +166,12 @@
 	return err;
 }
 
-static void __exit fini(void)
+static void __exit xt_mark_fini(void)
 {
 	xt_unregister_target(&ipt_mark_reg_v0);
 	xt_unregister_target(&ipt_mark_reg_v1);
 	xt_unregister_target(&ip6t_mark_reg_v0);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_mark_init);
+module_exit(xt_mark_fini);
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
index 2873e1c..86ccceb 100644
--- a/net/netfilter/xt_NFQUEUE.c
+++ b/net/netfilter/xt_NFQUEUE.c
@@ -61,7 +61,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init xt_nfqueue_init(void)
 {
 	int ret;
 	ret = xt_register_target(&ipt_NFQ_reg);
@@ -83,12 +83,12 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_nfqueue_fini(void)
 {
 	xt_unregister_target(&arpt_NFQ_reg);
 	xt_unregister_target(&ip6t_NFQ_reg);
 	xt_unregister_target(&ipt_NFQ_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_nfqueue_init);
+module_exit(xt_nfqueue_fini);
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c
index cf2ebd7..98f4b53 100644
--- a/net/netfilter/xt_NOTRACK.c
+++ b/net/netfilter/xt_NOTRACK.c
@@ -52,7 +52,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init xt_notrack_init(void)
 {
 	int ret;
 
@@ -67,11 +67,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_notrack_fini(void)
 {
 	xt_unregister_target(&notrack6_reg);
 	xt_unregister_target(&notrack_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_notrack_init);
+module_exit(xt_notrack_fini);
diff --git a/net/netfilter/xt_comment.c b/net/netfilter/xt_comment.c
index 2637724..197609c 100644
--- a/net/netfilter/xt_comment.c
+++ b/net/netfilter/xt_comment.c
@@ -45,7 +45,7 @@
 	.me		= THIS_MODULE
 };
 
-static int __init init(void)
+static int __init xt_comment_init(void)
 {
 	int ret;
 
@@ -60,11 +60,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_comment_fini(void)
 {
 	xt_unregister_match(&comment_match);
 	xt_unregister_match(&comment6_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_comment_init);
+module_exit(xt_comment_fini);
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
index 4985f5e..1396fe2 100644
--- a/net/netfilter/xt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -160,7 +160,7 @@
 	.me		= THIS_MODULE
 };
 
-static int __init init(void)
+static int __init xt_connbytes_init(void)
 {
 	int ret;
 	ret = xt_register_match(&connbytes_match);
@@ -173,11 +173,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_connbytes_fini(void)
 {
 	xt_unregister_match(&connbytes_match);
 	xt_unregister_match(&connbytes6_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_connbytes_init);
+module_exit(xt_connbytes_fini);
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
index 7b16f1e..dc26a27 100644
--- a/net/netfilter/xt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -102,7 +102,7 @@
 	.me		= THIS_MODULE
 };
 
-static int __init init(void)
+static int __init xt_connmark_init(void)
 {
 	int ret;
 
@@ -118,11 +118,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_connmark_fini(void)
 {
 	xt_unregister_match(&connmark6_match);
 	xt_unregister_match(&connmark_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_connmark_init);
+module_exit(xt_connmark_fini);
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index 65a8480..145489a 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -239,7 +239,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init xt_conntrack_init(void)
 {
 	int ret;
 	need_conntrack();
@@ -248,10 +248,10 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_conntrack_fini(void)
 {
 	xt_unregister_match(&conntrack_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_conntrack_init);
+module_exit(xt_conntrack_fini);
diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c
index 2f331de..dfb10b6 100644
--- a/net/netfilter/xt_dccp.c
+++ b/net/netfilter/xt_dccp.c
@@ -164,7 +164,7 @@
 };
 
 
-static int __init init(void)
+static int __init xt_dccp_init(void)
 {
 	int ret;
 
@@ -191,12 +191,12 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_dccp_fini(void)
 {
 	xt_unregister_match(&dccp6_match);
 	xt_unregister_match(&dccp_match);
 	kfree(dccp_optbuf);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_dccp_init);
+module_exit(xt_dccp_fini);
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c
index 101f000..799c2a4 100644
--- a/net/netfilter/xt_helper.c
+++ b/net/netfilter/xt_helper.c
@@ -182,7 +182,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init xt_helper_init(void)
 {
 	int ret;
 	need_conntrack();
@@ -198,12 +198,12 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_helper_fini(void)
 {
 	xt_unregister_match(&helper_match);
 	xt_unregister_match(&helper6_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_helper_init);
+module_exit(xt_helper_fini);
 
diff --git a/net/netfilter/xt_length.c b/net/netfilter/xt_length.c
index 38560ca..109132c 100644
--- a/net/netfilter/xt_length.c
+++ b/net/netfilter/xt_length.c
@@ -68,7 +68,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init xt_length_init(void)
 {
 	int ret;
 	ret = xt_register_match(&length_match);
@@ -81,11 +81,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_length_fini(void)
 {
 	xt_unregister_match(&length_match);
 	xt_unregister_match(&length6_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_length_init);
+module_exit(xt_length_fini);
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
index e91c1a4..ce7fdb7 100644
--- a/net/netfilter/xt_limit.c
+++ b/net/netfilter/xt_limit.c
@@ -153,7 +153,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init xt_limit_init(void)
 {
 	int ret;
 	
@@ -168,11 +168,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_limit_fini(void)
 {
 	xt_unregister_match(&ipt_limit_reg);
 	xt_unregister_match(&limit6_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_limit_init);
+module_exit(xt_limit_fini);
diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c
index f4defa2..356290f 100644
--- a/net/netfilter/xt_mac.c
+++ b/net/netfilter/xt_mac.c
@@ -62,7 +62,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init xt_mac_init(void)
 {
 	int ret;
 	ret = xt_register_match(&mac_match);
@@ -76,11 +76,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_mac_fini(void)
 {
 	xt_unregister_match(&mac_match);
 	xt_unregister_match(&mac6_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_mac_init);
+module_exit(xt_mac_fini);
diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c
index ce0badf..8b385a3 100644
--- a/net/netfilter/xt_mark.c
+++ b/net/netfilter/xt_mark.c
@@ -69,7 +69,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init xt_mark_init(void)
 {
 	int ret;
 	ret = xt_register_match(&mark_match);
@@ -83,11 +83,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_mark_fini(void)
 {
 	xt_unregister_match(&mark_match);
 	xt_unregister_match(&mark6_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_mark_init);
+module_exit(xt_mark_fini);
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c
index 089f4f7..5fe4c9d 100644
--- a/net/netfilter/xt_physdev.c
+++ b/net/netfilter/xt_physdev.c
@@ -134,7 +134,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init xt_physdev_init(void)
 {
 	int ret;
 
@@ -149,11 +149,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_physdev_fini(void)
 {
 	xt_unregister_match(&physdev_match);
 	xt_unregister_match(&physdev6_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_physdev_init);
+module_exit(xt_physdev_fini);
diff --git a/net/netfilter/xt_pkttype.c b/net/netfilter/xt_pkttype.c
index 8b8bca9..3ac703b 100644
--- a/net/netfilter/xt_pkttype.c
+++ b/net/netfilter/xt_pkttype.c
@@ -49,7 +49,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init xt_pkttype_init(void)
 {
 	int ret;
 	ret = xt_register_match(&pkttype_match);
@@ -63,11 +63,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_pkttype_fini(void)
 {
 	xt_unregister_match(&pkttype_match);
 	xt_unregister_match(&pkttype6_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_pkttype_init);
+module_exit(xt_pkttype_fini);
diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c
index 5e31a4a..a80b7d13 100644
--- a/net/netfilter/xt_realm.c
+++ b/net/netfilter/xt_realm.c
@@ -49,15 +49,15 @@
 	.me		= THIS_MODULE
 };
 
-static int __init init(void)
+static int __init xt_realm_init(void)
 {
 	return xt_register_match(&realm_match);
 }
 
-static void __exit fini(void)
+static void __exit xt_realm_fini(void)
 {
 	xt_unregister_match(&realm_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_realm_init);
+module_exit(xt_realm_fini);
diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c
index c6eb24a..34bd872 100644
--- a/net/netfilter/xt_sctp.c
+++ b/net/netfilter/xt_sctp.c
@@ -200,7 +200,7 @@
 	.me		= THIS_MODULE
 };
 
-static int __init init(void)
+static int __init xt_sctp_init(void)
 {
 	int ret;
 	ret = xt_register_match(&sctp_match);
@@ -214,11 +214,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_sctp_fini(void)
 {
 	xt_unregister_match(&sctp6_match);
 	xt_unregister_match(&sctp_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_sctp_init);
+module_exit(xt_sctp_fini);
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c
index e6c0be9..f9e304d 100644
--- a/net/netfilter/xt_state.c
+++ b/net/netfilter/xt_state.c
@@ -89,7 +89,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init xt_state_init(void)
 {
 	int ret;
 
@@ -106,11 +106,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_state_fini(void)
 {
 	xt_unregister_match(&state_match);
 	xt_unregister_match(&state6_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_state_init);
+module_exit(xt_state_fini);
diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c
index 703d80f..79d9ea6 100644
--- a/net/netfilter/xt_string.c
+++ b/net/netfilter/xt_string.c
@@ -91,7 +91,7 @@
 	.me 		= THIS_MODULE
 };
 
-static int __init init(void)
+static int __init xt_string_init(void)
 {
 	int ret;
 
@@ -105,11 +105,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_string_fini(void)
 {
 	xt_unregister_match(&string_match);
 	xt_unregister_match(&string6_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_string_init);
+module_exit(xt_string_fini);
diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c
index 70a8858..cf7d335 100644
--- a/net/netfilter/xt_tcpmss.c
+++ b/net/netfilter/xt_tcpmss.c
@@ -112,7 +112,7 @@
 };
 
 
-static int __init init(void)
+static int __init xt_tcpmss_init(void)
 {
 	int ret;
 	ret = xt_register_match(&tcpmss_match);
@@ -126,11 +126,11 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_tcpmss_fini(void)
 {
 	xt_unregister_match(&tcpmss6_match);
 	xt_unregister_match(&tcpmss_match);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_tcpmss_init);
+module_exit(xt_tcpmss_fini);
diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c
index 14a990e..1b61dac 100644
--- a/net/netfilter/xt_tcpudp.c
+++ b/net/netfilter/xt_tcpudp.c
@@ -238,7 +238,7 @@
 	.me		= THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init xt_tcpudp_init(void)
 {
 	int ret;
 	ret = xt_register_match(&tcp_matchstruct);
@@ -268,7 +268,7 @@
 	return ret;
 }
 
-static void __exit fini(void)
+static void __exit xt_tcpudp_fini(void)
 {
 	xt_unregister_match(&udp6_matchstruct);
 	xt_unregister_match(&udp_matchstruct);
@@ -276,5 +276,5 @@
 	xt_unregister_match(&tcp_matchstruct);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(xt_tcpudp_init);
+module_exit(xt_tcpudp_fini);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index d00a903..2a233ff 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -123,7 +123,7 @@
 static DEFINE_RWLOCK(nl_table_lock);
 static atomic_t nl_table_users = ATOMIC_INIT(0);
 
-static struct notifier_block *netlink_chain;
+static ATOMIC_NOTIFIER_HEAD(netlink_chain);
 
 static u32 netlink_group_mask(u32 group)
 {
@@ -469,7 +469,8 @@
 						.protocol = sk->sk_protocol,
 						.pid = nlk->pid,
 					  };
-		notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n);
+		atomic_notifier_call_chain(&netlink_chain,
+				NETLINK_URELEASE, &n);
 	}	
 
 	if (nlk->module)
@@ -1695,12 +1696,12 @@
 
 int netlink_register_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_register(&netlink_chain, nb);
+	return atomic_notifier_chain_register(&netlink_chain, nb);
 }
 
 int netlink_unregister_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_unregister(&netlink_chain, nb);
+	return atomic_notifier_chain_unregister(&netlink_chain, nb);
 }
                 
 static const struct proto_ops netlink_ops = {
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 43e7241..f329b72 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -13,26 +13,27 @@
 #include <linux/socket.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
+#include <linux/mutex.h>
 #include <net/sock.h>
 #include <net/genetlink.h>
 
 struct sock *genl_sock = NULL;
 
-static DECLARE_MUTEX(genl_sem); /* serialization of message processing */
+static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
 
 static void genl_lock(void)
 {
-	down(&genl_sem);
+	mutex_lock(&genl_mutex);
 }
 
 static int genl_trylock(void)
 {
-	return down_trylock(&genl_sem);
+	return !mutex_trylock(&genl_mutex);
 }
 
 static void genl_unlock(void)
 {
-	up(&genl_sem);
+	mutex_unlock(&genl_mutex);
 
 	if (genl_sock && genl_sock->sk_receive_queue.qlen)
 		genl_sock->sk_data_ready(genl_sock, 0);
diff --git a/net/nonet.c b/net/nonet.c
index 1230f0a..92e7664 100644
--- a/net/nonet.c
+++ b/net/nonet.c
@@ -19,7 +19,7 @@
 	return -ENXIO;
 }
 
-struct file_operations bad_sock_fops = {
+const struct file_operations bad_sock_fops = {
 	.owner = THIS_MODULE,
 	.open = sock_no_open,
 };
diff --git a/net/socket.c b/net/socket.c
index 5211ba2..b13042f 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -119,6 +119,9 @@
 static ssize_t sock_sendpage(struct file *file, struct page *page,
 			     int offset, size_t size, loff_t *ppos, int more);
 
+extern ssize_t generic_splice_sendpage(struct inode *inode, struct file *out,
+				size_t len, unsigned int flags);
+
 
 /*
  *	Socket files have a set of 'special' operations as well as the generic file ones. These don't appear
@@ -141,7 +144,8 @@
 	.fasync =	sock_fasync,
 	.readv =	sock_readv,
 	.writev =	sock_writev,
-	.sendpage =	sock_sendpage
+	.sendpage =	sock_sendpage,
+	.splice_write = generic_splice_sendpage,
 };
 
 /*
@@ -539,7 +543,7 @@
 	return -ENXIO;
 }
 
-struct file_operations bad_sock_fops = {
+const struct file_operations bad_sock_fops = {
 	.owner = THIS_MODULE,
 	.open = sock_no_open,
 };
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 23632d8..4d7eb9e 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -78,7 +78,8 @@
 
 static struct cache_head *rsi_table[RSI_HASHMAX];
 static struct cache_detail rsi_cache;
-static struct rsi *rsi_lookup(struct rsi *item, int set);
+static struct rsi *rsi_update(struct rsi *new, struct rsi *old);
+static struct rsi *rsi_lookup(struct rsi *item);
 
 static void rsi_free(struct rsi *rsii)
 {
@@ -88,13 +89,11 @@
 	kfree(rsii->out_token.data);
 }
 
-static void rsi_put(struct cache_head *item, struct cache_detail *cd)
+static void rsi_put(struct kref *ref)
 {
-	struct rsi *rsii = container_of(item, struct rsi, h);
-	if (cache_put(item, cd)) {
-		rsi_free(rsii);
-		kfree(rsii);
-	}
+	struct rsi *rsii = container_of(ref, struct rsi, h.ref);
+	rsi_free(rsii);
+	kfree(rsii);
 }
 
 static inline int rsi_hash(struct rsi *item)
@@ -103,8 +102,10 @@
 	     ^ hash_mem(item->in_token.data, item->in_token.len, RSI_HASHBITS);
 }
 
-static inline int rsi_match(struct rsi *item, struct rsi *tmp)
+static int rsi_match(struct cache_head *a, struct cache_head *b)
 {
+	struct rsi *item = container_of(a, struct rsi, h);
+	struct rsi *tmp = container_of(b, struct rsi, h);
 	return netobj_equal(&item->in_handle, &tmp->in_handle)
 		&& netobj_equal(&item->in_token, &tmp->in_token);
 }
@@ -125,8 +126,11 @@
 	return dup_to_netobj(dst, src->data, src->len);
 }
 
-static inline void rsi_init(struct rsi *new, struct rsi *item)
+static void rsi_init(struct cache_head *cnew, struct cache_head *citem)
 {
+	struct rsi *new = container_of(cnew, struct rsi, h);
+	struct rsi *item = container_of(citem, struct rsi, h);
+
 	new->out_handle.data = NULL;
 	new->out_handle.len = 0;
 	new->out_token.data = NULL;
@@ -141,8 +145,11 @@
 	item->in_token.data = NULL;
 }
 
-static inline void rsi_update(struct rsi *new, struct rsi *item)
+static void update_rsi(struct cache_head *cnew, struct cache_head *citem)
 {
+	struct rsi *new = container_of(cnew, struct rsi, h);
+	struct rsi *item = container_of(citem, struct rsi, h);
+
 	BUG_ON(new->out_handle.data || new->out_token.data);
 	new->out_handle.len = item->out_handle.len;
 	item->out_handle.len = 0;
@@ -157,6 +164,15 @@
 	new->minor_status = item->minor_status;
 }
 
+static struct cache_head *rsi_alloc(void)
+{
+	struct rsi *rsii = kmalloc(sizeof(*rsii), GFP_KERNEL);
+	if (rsii)
+		return &rsii->h;
+	else
+		return NULL;
+}
+
 static void rsi_request(struct cache_detail *cd,
                        struct cache_head *h,
                        char **bpp, int *blen)
@@ -198,6 +214,10 @@
 	if (dup_to_netobj(&rsii.in_token, buf, len))
 		goto out;
 
+	rsip = rsi_lookup(&rsii);
+	if (!rsip)
+		goto out;
+
 	rsii.h.flags = 0;
 	/* expiry */
 	expiry = get_expiry(&mesg);
@@ -240,12 +260,14 @@
 			goto out;
 	}
 	rsii.h.expiry_time = expiry;
-	rsip = rsi_lookup(&rsii, 1);
+	rsip = rsi_update(&rsii, rsip);
 	status = 0;
 out:
 	rsi_free(&rsii);
 	if (rsip)
-		rsi_put(&rsip->h, &rsi_cache);
+		cache_put(&rsip->h, &rsi_cache);
+	else
+		status = -ENOMEM;
 	return status;
 }
 
@@ -257,9 +279,37 @@
 	.cache_put      = rsi_put,
 	.cache_request  = rsi_request,
 	.cache_parse    = rsi_parse,
+	.match		= rsi_match,
+	.init		= rsi_init,
+	.update		= update_rsi,
+	.alloc		= rsi_alloc,
 };
 
-static DefineSimpleCacheLookup(rsi, 0)
+static struct rsi *rsi_lookup(struct rsi *item)
+{
+	struct cache_head *ch;
+	int hash = rsi_hash(item);
+
+	ch = sunrpc_cache_lookup(&rsi_cache, &item->h, hash);
+	if (ch)
+		return container_of(ch, struct rsi, h);
+	else
+		return NULL;
+}
+
+static struct rsi *rsi_update(struct rsi *new, struct rsi *old)
+{
+	struct cache_head *ch;
+	int hash = rsi_hash(new);
+
+	ch = sunrpc_cache_update(&rsi_cache, &new->h,
+				 &old->h, hash);
+	if (ch)
+		return container_of(ch, struct rsi, h);
+	else
+		return NULL;
+}
+
 
 /*
  * The rpcsec_context cache is used to store a context that is
@@ -293,7 +343,8 @@
 
 static struct cache_head *rsc_table[RSC_HASHMAX];
 static struct cache_detail rsc_cache;
-static struct rsc *rsc_lookup(struct rsc *item, int set);
+static struct rsc *rsc_update(struct rsc *new, struct rsc *old);
+static struct rsc *rsc_lookup(struct rsc *item);
 
 static void rsc_free(struct rsc *rsci)
 {
@@ -304,14 +355,12 @@
 		put_group_info(rsci->cred.cr_group_info);
 }
 
-static void rsc_put(struct cache_head *item, struct cache_detail *cd)
+static void rsc_put(struct kref *ref)
 {
-	struct rsc *rsci = container_of(item, struct rsc, h);
+	struct rsc *rsci = container_of(ref, struct rsc, h.ref);
 
-	if (cache_put(item, cd)) {
-		rsc_free(rsci);
-		kfree(rsci);
-	}
+	rsc_free(rsci);
+	kfree(rsci);
 }
 
 static inline int
@@ -320,15 +369,21 @@
 	return hash_mem(rsci->handle.data, rsci->handle.len, RSC_HASHBITS);
 }
 
-static inline int
-rsc_match(struct rsc *new, struct rsc *tmp)
+static int
+rsc_match(struct cache_head *a, struct cache_head *b)
 {
+	struct rsc *new = container_of(a, struct rsc, h);
+	struct rsc *tmp = container_of(b, struct rsc, h);
+
 	return netobj_equal(&new->handle, &tmp->handle);
 }
 
-static inline void
-rsc_init(struct rsc *new, struct rsc *tmp)
+static void
+rsc_init(struct cache_head *cnew, struct cache_head *ctmp)
 {
+	struct rsc *new = container_of(cnew, struct rsc, h);
+	struct rsc *tmp = container_of(ctmp, struct rsc, h);
+
 	new->handle.len = tmp->handle.len;
 	tmp->handle.len = 0;
 	new->handle.data = tmp->handle.data;
@@ -337,9 +392,12 @@
 	new->cred.cr_group_info = NULL;
 }
 
-static inline void
-rsc_update(struct rsc *new, struct rsc *tmp)
+static void
+update_rsc(struct cache_head *cnew, struct cache_head *ctmp)
 {
+	struct rsc *new = container_of(cnew, struct rsc, h);
+	struct rsc *tmp = container_of(ctmp, struct rsc, h);
+
 	new->mechctx = tmp->mechctx;
 	tmp->mechctx = NULL;
 	memset(&new->seqdata, 0, sizeof(new->seqdata));
@@ -348,6 +406,16 @@
 	tmp->cred.cr_group_info = NULL;
 }
 
+static struct cache_head *
+rsc_alloc(void)
+{
+	struct rsc *rsci = kmalloc(sizeof(*rsci), GFP_KERNEL);
+	if (rsci)
+		return &rsci->h;
+	else
+		return NULL;
+}
+
 static int rsc_parse(struct cache_detail *cd,
 		     char *mesg, int mlen)
 {
@@ -373,6 +441,10 @@
 	if (expiry == 0)
 		goto out;
 
+	rscp = rsc_lookup(&rsci);
+	if (!rscp)
+		goto out;
+
 	/* uid, or NEGATIVE */
 	rv = get_int(&mesg, &rsci.cred.cr_uid);
 	if (rv == -EINVAL)
@@ -428,12 +500,14 @@
 		gss_mech_put(gm);
 	}
 	rsci.h.expiry_time = expiry;
-	rscp = rsc_lookup(&rsci, 1);
+	rscp = rsc_update(&rsci, rscp);
 	status = 0;
 out:
 	rsc_free(&rsci);
 	if (rscp)
-		rsc_put(&rscp->h, &rsc_cache);
+		cache_put(&rscp->h, &rsc_cache);
+	else
+		status = -ENOMEM;
 	return status;
 }
 
@@ -444,9 +518,37 @@
 	.name		= "auth.rpcsec.context",
 	.cache_put	= rsc_put,
 	.cache_parse	= rsc_parse,
+	.match		= rsc_match,
+	.init		= rsc_init,
+	.update		= update_rsc,
+	.alloc		= rsc_alloc,
 };
 
-static DefineSimpleCacheLookup(rsc, 0);
+static struct rsc *rsc_lookup(struct rsc *item)
+{
+	struct cache_head *ch;
+	int hash = rsc_hash(item);
+
+	ch = sunrpc_cache_lookup(&rsc_cache, &item->h, hash);
+	if (ch)
+		return container_of(ch, struct rsc, h);
+	else
+		return NULL;
+}
+
+static struct rsc *rsc_update(struct rsc *new, struct rsc *old)
+{
+	struct cache_head *ch;
+	int hash = rsc_hash(new);
+
+	ch = sunrpc_cache_update(&rsc_cache, &new->h,
+				 &old->h, hash);
+	if (ch)
+		return container_of(ch, struct rsc, h);
+	else
+		return NULL;
+}
+
 
 static struct rsc *
 gss_svc_searchbyctx(struct xdr_netobj *handle)
@@ -457,7 +559,7 @@
 	memset(&rsci, 0, sizeof(rsci));
 	if (dup_to_netobj(&rsci.handle, handle->data, handle->len))
 		return NULL;
-	found = rsc_lookup(&rsci, 0);
+	found = rsc_lookup(&rsci);
 	rsc_free(&rsci);
 	if (!found)
 		return NULL;
@@ -645,6 +747,8 @@
 	return auth_domain_find(name);
 }
 
+static struct auth_ops svcauthops_gss;
+
 int
 svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
 {
@@ -655,20 +759,18 @@
 	new = kmalloc(sizeof(*new), GFP_KERNEL);
 	if (!new)
 		goto out;
-	cache_init(&new->h.h);
+	kref_init(&new->h.ref);
 	new->h.name = kmalloc(strlen(name) + 1, GFP_KERNEL);
 	if (!new->h.name)
 		goto out_free_dom;
 	strcpy(new->h.name, name);
-	new->h.flavour = RPC_AUTH_GSS;
+	new->h.flavour = &svcauthops_gss;
 	new->pseudoflavor = pseudoflavor;
-	new->h.h.expiry_time = NEVER;
 
-	test = auth_domain_lookup(&new->h, 1);
-	if (test == &new->h) {
-		BUG_ON(atomic_dec_and_test(&new->h.h.refcnt));
-	} else { /* XXX Duplicate registration? */
+	test = auth_domain_lookup(name, &new->h);
+	if (test != &new->h) { /* XXX Duplicate registration? */
 		auth_domain_put(&new->h);
+		/* dangling ref-count... */
 		goto out;
 	}
 	return 0;
@@ -895,7 +997,7 @@
 			goto drop;
 		}
 
-		rsip = rsi_lookup(&rsikey, 0);
+		rsip = rsi_lookup(&rsikey);
 		rsi_free(&rsikey);
 		if (!rsip) {
 			goto drop;
@@ -970,7 +1072,7 @@
 	ret = SVC_DROP;
 out:
 	if (rsci)
-		rsc_put(&rsci->h, &rsc_cache);
+		cache_put(&rsci->h, &rsc_cache);
 	return ret;
 }
 
@@ -1062,7 +1164,7 @@
 		put_group_info(rqstp->rq_cred.cr_group_info);
 	rqstp->rq_cred.cr_group_info = NULL;
 	if (gsd->rsci)
-		rsc_put(&gsd->rsci->h, &rsc_cache);
+		cache_put(&gsd->rsci->h, &rsc_cache);
 	gsd->rsci = NULL;
 
 	return stat;
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 0acccfe..3ac4193 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -37,16 +37,138 @@
 static void cache_defer_req(struct cache_req *req, struct cache_head *item);
 static void cache_revisit_request(struct cache_head *item);
 
-void cache_init(struct cache_head *h)
+static void cache_init(struct cache_head *h)
 {
 	time_t now = get_seconds();
 	h->next = NULL;
 	h->flags = 0;
-	atomic_set(&h->refcnt, 1);
+	kref_init(&h->ref);
 	h->expiry_time = now + CACHE_NEW_EXPIRY;
 	h->last_refresh = now;
 }
 
+struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
+				       struct cache_head *key, int hash)
+{
+	struct cache_head **head,  **hp;
+	struct cache_head *new = NULL;
+
+	head = &detail->hash_table[hash];
+
+	read_lock(&detail->hash_lock);
+
+	for (hp=head; *hp != NULL ; hp = &(*hp)->next) {
+		struct cache_head *tmp = *hp;
+		if (detail->match(tmp, key)) {
+			cache_get(tmp);
+			read_unlock(&detail->hash_lock);
+			return tmp;
+		}
+	}
+	read_unlock(&detail->hash_lock);
+	/* Didn't find anything, insert an empty entry */
+
+	new = detail->alloc();
+	if (!new)
+		return NULL;
+	cache_init(new);
+
+	write_lock(&detail->hash_lock);
+
+	/* check if entry appeared while we slept */
+	for (hp=head; *hp != NULL ; hp = &(*hp)->next) {
+		struct cache_head *tmp = *hp;
+		if (detail->match(tmp, key)) {
+			cache_get(tmp);
+			write_unlock(&detail->hash_lock);
+			cache_put(new, detail);
+			return tmp;
+		}
+	}
+	detail->init(new, key);
+	new->next = *head;
+	*head = new;
+	detail->entries++;
+	cache_get(new);
+	write_unlock(&detail->hash_lock);
+
+	return new;
+}
+EXPORT_SYMBOL(sunrpc_cache_lookup);
+
+
+static void queue_loose(struct cache_detail *detail, struct cache_head *ch);
+
+static int cache_fresh_locked(struct cache_head *head, time_t expiry)
+{
+	head->expiry_time = expiry;
+	head->last_refresh = get_seconds();
+	return !test_and_set_bit(CACHE_VALID, &head->flags);
+}
+
+static void cache_fresh_unlocked(struct cache_head *head,
+			struct cache_detail *detail, int new)
+{
+	if (new)
+		cache_revisit_request(head);
+	if (test_and_clear_bit(CACHE_PENDING, &head->flags)) {
+		cache_revisit_request(head);
+		queue_loose(detail, head);
+	}
+}
+
+struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
+				       struct cache_head *new, struct cache_head *old, int hash)
+{
+	/* The 'old' entry is to be replaced by 'new'.
+	 * If 'old' is not VALID, we update it directly,
+	 * otherwise we need to replace it
+	 */
+	struct cache_head **head;
+	struct cache_head *tmp;
+	int is_new;
+
+	if (!test_bit(CACHE_VALID, &old->flags)) {
+		write_lock(&detail->hash_lock);
+		if (!test_bit(CACHE_VALID, &old->flags)) {
+			if (test_bit(CACHE_NEGATIVE, &new->flags))
+				set_bit(CACHE_NEGATIVE, &old->flags);
+			else
+				detail->update(old, new);
+			is_new = cache_fresh_locked(old, new->expiry_time);
+			write_unlock(&detail->hash_lock);
+			cache_fresh_unlocked(old, detail, is_new);
+			return old;
+		}
+		write_unlock(&detail->hash_lock);
+	}
+	/* We need to insert a new entry */
+	tmp = detail->alloc();
+	if (!tmp) {
+		cache_put(old, detail);
+		return NULL;
+	}
+	cache_init(tmp);
+	detail->init(tmp, old);
+	head = &detail->hash_table[hash];
+
+	write_lock(&detail->hash_lock);
+	if (test_bit(CACHE_NEGATIVE, &new->flags))
+		set_bit(CACHE_NEGATIVE, &tmp->flags);
+	else
+		detail->update(tmp, new);
+	tmp->next = *head;
+	*head = tmp;
+	cache_get(tmp);
+	is_new = cache_fresh_locked(tmp, new->expiry_time);
+	cache_fresh_locked(old, 0);
+	write_unlock(&detail->hash_lock);
+	cache_fresh_unlocked(tmp, detail, is_new);
+	cache_fresh_unlocked(old, detail, 0);
+	cache_put(old, detail);
+	return tmp;
+}
+EXPORT_SYMBOL(sunrpc_cache_update);
 
 static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h);
 /*
@@ -94,7 +216,8 @@
 				clear_bit(CACHE_PENDING, &h->flags);
 				if (rv == -EAGAIN) {
 					set_bit(CACHE_NEGATIVE, &h->flags);
-					cache_fresh(detail, h, get_seconds()+CACHE_NEW_EXPIRY);
+					cache_fresh_unlocked(h, detail,
+					     cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY));
 					rv = -ENOENT;
 				}
 				break;
@@ -110,25 +233,11 @@
 	if (rv == -EAGAIN)
 		cache_defer_req(rqstp, h);
 
-	if (rv && h)
-		detail->cache_put(h, detail);
+	if (rv)
+		cache_put(h, detail);
 	return rv;
 }
 
-static void queue_loose(struct cache_detail *detail, struct cache_head *ch);
-
-void cache_fresh(struct cache_detail *detail,
-		 struct cache_head *head, time_t expiry)
-{
-
-	head->expiry_time = expiry;
-	head->last_refresh = get_seconds();
-	if (!test_and_set_bit(CACHE_VALID, &head->flags))
-		cache_revisit_request(head);
-	if (test_and_clear_bit(CACHE_PENDING, &head->flags))
-		queue_loose(detail, head);
-}
-
 /*
  * caches need to be periodically cleaned.
  * For this we maintain a list of cache_detail and
@@ -322,7 +431,7 @@
 			if (test_and_clear_bit(CACHE_PENDING, &ch->flags))
 				queue_loose(current_detail, ch);
 
-			if (atomic_read(&ch->refcnt) == 1)
+			if (atomic_read(&ch->ref.refcount) == 1)
 				break;
 		}
 		if (ch) {
@@ -337,7 +446,7 @@
 			current_index ++;
 		spin_unlock(&cache_list_lock);
 		if (ch)
-			d->cache_put(ch, d);
+			cache_put(ch, d);
 	} else
 		spin_unlock(&cache_list_lock);
 
@@ -453,7 +562,7 @@
 		/* there was one too many */
 		dreq->revisit(dreq, 1);
 	}
-	if (test_bit(CACHE_VALID, &item->flags)) {
+	if (!test_bit(CACHE_PENDING, &item->flags)) {
 		/* must have just been validated... */
 		cache_revisit_request(item);
 	}
@@ -614,7 +723,7 @@
 		    !test_bit(CACHE_PENDING, &rq->item->flags)) {
 			list_del(&rq->q.list);
 			spin_unlock(&queue_lock);
-			cd->cache_put(rq->item, cd);
+			cache_put(rq->item, cd);
 			kfree(rq->buf);
 			kfree(rq);
 		} else
@@ -794,10 +903,10 @@
 			if (cr->item != ch)
 				continue;
 			if (cr->readers != 0)
-				break;
+				continue;
 			list_del(&cr->q.list);
 			spin_unlock(&queue_lock);
-			detail->cache_put(cr->item, detail);
+			cache_put(cr->item, detail);
 			kfree(cr->buf);
 			kfree(cr);
 			return;
@@ -1082,8 +1191,8 @@
 		return cd->cache_show(m, cd, NULL);
 
 	ifdebug(CACHE)
-		seq_printf(m, "# expiry=%ld refcnt=%d\n",
-			   cp->expiry_time, atomic_read(&cp->refcnt));
+		seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n",
+			   cp->expiry_time, atomic_read(&cp->ref.refcount), cp->flags);
 	cache_get(cp);
 	if (cache_check(cd, cp, NULL))
 		/* cache_check does a cache_put on failure */
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index aa4158b..cc673dd 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -395,7 +395,7 @@
  */
 struct rpc_filelist {
 	char *name;
-	struct file_operations *i_fop;
+	const struct file_operations *i_fop;
 	int mode;
 };
 
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index b9969b9..5c3eee76 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -1167,16 +1167,12 @@
 					     NULL, NULL);
 	if (!rpc_buffer_slabp)
 		goto err_nomem;
-	rpc_task_mempool = mempool_create(RPC_TASK_POOLSIZE,
-					    mempool_alloc_slab,
-					    mempool_free_slab,
-					    rpc_task_slabp);
+	rpc_task_mempool = mempool_create_slab_pool(RPC_TASK_POOLSIZE,
+						    rpc_task_slabp);
 	if (!rpc_task_mempool)
 		goto err_nomem;
-	rpc_buffer_mempool = mempool_create(RPC_BUFFER_POOLSIZE,
-					    mempool_alloc_slab,
-					    mempool_free_slab,
-					    rpc_buffer_slabp);
+	rpc_buffer_mempool = mempool_create_slab_pool(RPC_BUFFER_POOLSIZE,
+						      rpc_buffer_slabp);
 	if (!rpc_buffer_mempool)
 		goto err_nomem;
 	return 0;
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
index 790941e..dea5296 100644
--- a/net/sunrpc/stats.c
+++ b/net/sunrpc/stats.c
@@ -225,7 +225,7 @@
  * Register/unregister RPC proc files
  */
 static inline struct proc_dir_entry *
-do_register(const char *name, void *data, struct file_operations *fops)
+do_register(const char *name, void *data, const struct file_operations *fops)
 {
 	struct proc_dir_entry *ent;
 
@@ -253,7 +253,7 @@
 }
 
 struct proc_dir_entry *
-svc_proc_register(struct svc_stat *statp, struct file_operations *fops)
+svc_proc_register(struct svc_stat *statp, const struct file_operations *fops)
 {
 	return do_register(statp->program->pg_name, statp, fops);
 }
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 9f73732..769114f 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -105,8 +105,6 @@
 EXPORT_SYMBOL(cache_check);
 EXPORT_SYMBOL(cache_flush);
 EXPORT_SYMBOL(cache_purge);
-EXPORT_SYMBOL(cache_fresh);
-EXPORT_SYMBOL(cache_init);
 EXPORT_SYMBOL(cache_register);
 EXPORT_SYMBOL(cache_unregister);
 EXPORT_SYMBOL(qword_add);
@@ -142,6 +140,7 @@
 
 extern int register_rpc_pipefs(void);
 extern void unregister_rpc_pipefs(void);
+extern struct cache_detail ip_map_cache;
 
 static int __init
 init_sunrpc(void)
@@ -158,7 +157,6 @@
 #ifdef CONFIG_PROC_FS
 	rpc_proc_init();
 #endif
-	cache_register(&auth_domain_cache);
 	cache_register(&ip_map_cache);
 out:
 	return err;
@@ -169,8 +167,6 @@
 {
 	unregister_rpc_pipefs();
 	rpc_destroy_mempool();
-	if (cache_unregister(&auth_domain_cache))
-		printk(KERN_ERR "sunrpc: failed to unregister auth_domain cache\n");
 	if (cache_unregister(&ip_map_cache))
 		printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n");
 #ifdef RPC_DEBUG
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index dda4f0c..5b28c61 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -106,112 +106,56 @@
 EXPORT_SYMBOL(svc_auth_unregister);
 
 /**************************************************
- * cache for domain name to auth_domain
- * Entries are only added by flavours which will normally
- * have a structure that 'inherits' from auth_domain.
- * e.g. when an IP -> domainname is given to  auth_unix,
- * and the domain name doesn't exist, it will create a
- * auth_unix_domain and add it to this hash table.
- * If it finds the name does exist, but isn't AUTH_UNIX,
- * it will complain.
+ * 'auth_domains' are stored in a hash table indexed by name.
+ * When the last reference to an 'auth_domain' is dropped,
+ * the object is unhashed and freed.
+ * If auth_domain_lookup fails to find an entry, it will return
+ * it's second argument 'new'.  If this is non-null, it will
+ * have been atomically linked into the table.
  */
 
-/*
- * Auth auth_domain cache is somewhat different to other caches,
- * largely because the entries are possibly of different types:
- * each auth flavour has it's own type.
- * One consequence of this that DefineCacheLookup cannot
- * allocate a new structure as it cannot know the size.
- * Notice that the "INIT" code fragment is quite different
- * from other caches.  When auth_domain_lookup might be
- * creating a new domain, the new domain is passed in
- * complete and it is used as-is rather than being copied into
- * another structure.
- */
 #define	DN_HASHBITS	6
 #define	DN_HASHMAX	(1<<DN_HASHBITS)
 #define	DN_HASHMASK	(DN_HASHMAX-1)
 
-static struct cache_head	*auth_domain_table[DN_HASHMAX];
-
-static void auth_domain_drop(struct cache_head *item, struct cache_detail *cd)
-{
-	struct auth_domain *dom = container_of(item, struct auth_domain, h);
-	if (cache_put(item,cd))
-		authtab[dom->flavour]->domain_release(dom);
-}
-
-
-struct cache_detail auth_domain_cache = {
-	.owner		= THIS_MODULE,
-	.hash_size	= DN_HASHMAX,
-	.hash_table	= auth_domain_table,
-	.name		= "auth.domain",
-	.cache_put	= auth_domain_drop,
-};
+static struct hlist_head	auth_domain_table[DN_HASHMAX];
+static spinlock_t	auth_domain_lock = SPIN_LOCK_UNLOCKED;
 
 void auth_domain_put(struct auth_domain *dom)
 {
-	auth_domain_drop(&dom->h, &auth_domain_cache);
-}
-
-static inline int auth_domain_hash(struct auth_domain *item)
-{
-	return hash_str(item->name, DN_HASHBITS);
-}
-static inline int auth_domain_match(struct auth_domain *tmp, struct auth_domain *item)
-{
-	return strcmp(tmp->name, item->name) == 0;
+	if (atomic_dec_and_lock(&dom->ref.refcount, &auth_domain_lock)) {
+		hlist_del(&dom->hash);
+		dom->flavour->domain_release(dom);
+	}
 }
 
 struct auth_domain *
-auth_domain_lookup(struct auth_domain *item, int set)
+auth_domain_lookup(char *name, struct auth_domain *new)
 {
-	struct auth_domain *tmp = NULL;
-	struct cache_head **hp, **head;
-	head = &auth_domain_cache.hash_table[auth_domain_hash(item)];
+	struct auth_domain *hp;
+	struct hlist_head *head;
+	struct hlist_node *np;
 
-	if (set)
-		write_lock(&auth_domain_cache.hash_lock);
-	else
-		read_lock(&auth_domain_cache.hash_lock);
-	for (hp=head; *hp != NULL; hp = &tmp->h.next) {
-		tmp = container_of(*hp, struct auth_domain, h);
-		if (!auth_domain_match(tmp, item))
-			continue;
-		if (!set) {
-			cache_get(&tmp->h);
-			goto out_noset;
+	head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
+
+	spin_lock(&auth_domain_lock);
+
+	hlist_for_each_entry(hp, np, head, hash) {
+		if (strcmp(hp->name, name)==0) {
+			kref_get(&hp->ref);
+			spin_unlock(&auth_domain_lock);
+			return hp;
 		}
-		*hp = tmp->h.next;
-		tmp->h.next = NULL;
-		auth_domain_drop(&tmp->h, &auth_domain_cache);
-		goto out_set;
 	}
-	/* Didn't find anything */
-	if (!set)
-		goto out_nada;
-	auth_domain_cache.entries++;
-out_set:
-	item->h.next = *head;
-	*head = &item->h;
-	cache_get(&item->h);
-	write_unlock(&auth_domain_cache.hash_lock);
-	cache_fresh(&auth_domain_cache, &item->h, item->h.expiry_time);
-	cache_get(&item->h);
-	return item;
-out_nada:
-	tmp = NULL;
-out_noset:
-	read_unlock(&auth_domain_cache.hash_lock);
-	return tmp;
+	if (new) {
+		hlist_add_head(&new->hash, head);
+		kref_get(&new->ref);
+	}
+	spin_unlock(&auth_domain_lock);
+	return new;
 }
 
 struct auth_domain *auth_domain_find(char *name)
 {
-	struct auth_domain *rv, ad;
-
-	ad.name = name;
-	rv = auth_domain_lookup(&ad, 0);
-	return rv;
+	return auth_domain_lookup(name, NULL);
 }
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 3e6c694..7e5707e 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -27,41 +27,35 @@
 	/* other stuff later */
 };
 
+extern struct auth_ops svcauth_unix;
+
 struct auth_domain *unix_domain_find(char *name)
 {
-	struct auth_domain *rv, ud;
-	struct unix_domain *new;
+	struct auth_domain *rv;
+	struct unix_domain *new = NULL;
 
-	ud.name = name;
-	
-	rv = auth_domain_lookup(&ud, 0);
+	rv = auth_domain_lookup(name, NULL);
+	while(1) {
+		if (rv) {
+			if (new && rv != &new->h)
+				auth_domain_put(&new->h);
 
- foundit:
-	if (rv && rv->flavour != RPC_AUTH_UNIX) {
-		auth_domain_put(rv);
-		return NULL;
+			if (rv->flavour != &svcauth_unix) {
+				auth_domain_put(rv);
+				return NULL;
+			}
+			return rv;
+		}
+
+		new = kmalloc(sizeof(*new), GFP_KERNEL);
+		if (new == NULL)
+			return NULL;
+		kref_init(&new->h.ref);
+		new->h.name = kstrdup(name, GFP_KERNEL);
+		new->h.flavour = &svcauth_unix;
+		new->addr_changes = 0;
+		rv = auth_domain_lookup(name, &new->h);
 	}
-	if (rv)
-		return rv;
-
-	new = kmalloc(sizeof(*new), GFP_KERNEL);
-	if (new == NULL)
-		return NULL;
-	cache_init(&new->h.h);
-	new->h.name = kstrdup(name, GFP_KERNEL);
-	new->h.flavour = RPC_AUTH_UNIX;
-	new->addr_changes = 0;
-	new->h.h.expiry_time = NEVER;
-
-	rv = auth_domain_lookup(&new->h, 2);
-	if (rv == &new->h) {
-		if (atomic_dec_and_test(&new->h.h.refcnt)) BUG();
-	} else {
-		auth_domain_put(&new->h);
-		goto foundit;
-	}
-
-	return rv;
 }
 
 static void svcauth_unix_domain_release(struct auth_domain *dom)
@@ -90,15 +84,15 @@
 };
 static struct cache_head	*ip_table[IP_HASHMAX];
 
-static void ip_map_put(struct cache_head *item, struct cache_detail *cd)
+static void ip_map_put(struct kref *kref)
 {
+	struct cache_head *item = container_of(kref, struct cache_head, ref);
 	struct ip_map *im = container_of(item, struct ip_map,h);
-	if (cache_put(item, cd)) {
-		if (test_bit(CACHE_VALID, &item->flags) &&
-		    !test_bit(CACHE_NEGATIVE, &item->flags))
-			auth_domain_put(&im->m_client->h);
-		kfree(im);
-	}
+
+	if (test_bit(CACHE_VALID, &item->flags) &&
+	    !test_bit(CACHE_NEGATIVE, &item->flags))
+		auth_domain_put(&im->m_client->h);
+	kfree(im);
 }
 
 #if IP_HASHBITS == 8
@@ -112,28 +106,38 @@
 	return (hash ^ (hash>>8)) & 0xff;
 }
 #endif
+static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
+{
+	struct ip_map *orig = container_of(corig, struct ip_map, h);
+	struct ip_map *new = container_of(cnew, struct ip_map, h);
+	return strcmp(orig->m_class, new->m_class) == 0
+		&& orig->m_addr.s_addr == new->m_addr.s_addr;
+}
+static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
+{
+	struct ip_map *new = container_of(cnew, struct ip_map, h);
+	struct ip_map *item = container_of(citem, struct ip_map, h);
 
-static inline int ip_map_hash(struct ip_map *item)
-{
-	return hash_str(item->m_class, IP_HASHBITS) ^ 
-		hash_ip((unsigned long)item->m_addr.s_addr);
-}
-static inline int ip_map_match(struct ip_map *item, struct ip_map *tmp)
-{
-	return strcmp(tmp->m_class, item->m_class) == 0
-		&& tmp->m_addr.s_addr == item->m_addr.s_addr;
-}
-static inline void ip_map_init(struct ip_map *new, struct ip_map *item)
-{
 	strcpy(new->m_class, item->m_class);
 	new->m_addr.s_addr = item->m_addr.s_addr;
 }
-static inline void ip_map_update(struct ip_map *new, struct ip_map *item)
+static void update(struct cache_head *cnew, struct cache_head *citem)
 {
-	cache_get(&item->m_client->h.h);
+	struct ip_map *new = container_of(cnew, struct ip_map, h);
+	struct ip_map *item = container_of(citem, struct ip_map, h);
+
+	kref_get(&item->m_client->h.ref);
 	new->m_client = item->m_client;
 	new->m_add_change = item->m_add_change;
 }
+static struct cache_head *ip_map_alloc(void)
+{
+	struct ip_map *i = kmalloc(sizeof(*i), GFP_KERNEL);
+	if (i)
+		return &i->h;
+	else
+		return NULL;
+}
 
 static void ip_map_request(struct cache_detail *cd,
 				  struct cache_head *h,
@@ -154,7 +158,8 @@
 	(*bpp)[-1] = '\n';
 }
 
-static struct ip_map *ip_map_lookup(struct ip_map *, int);
+static struct ip_map *ip_map_lookup(char *class, struct in_addr addr);
+static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
 
 static int ip_map_parse(struct cache_detail *cd,
 			  char *mesg, int mlen)
@@ -166,7 +171,11 @@
 	int len;
 	int b1,b2,b3,b4;
 	char c;
-	struct ip_map ipm, *ipmp;
+	char class[8];
+	struct in_addr addr;
+	int err;
+
+	struct ip_map *ipmp;
 	struct auth_domain *dom;
 	time_t expiry;
 
@@ -175,7 +184,7 @@
 	mesg[mlen-1] = 0;
 
 	/* class */
-	len = qword_get(&mesg, ipm.m_class, sizeof(ipm.m_class));
+	len = qword_get(&mesg, class, sizeof(class));
 	if (len <= 0) return -EINVAL;
 
 	/* ip address */
@@ -200,25 +209,22 @@
 	} else
 		dom = NULL;
 
-	ipm.m_addr.s_addr =
+	addr.s_addr =
 		htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
-	ipm.h.flags = 0;
-	if (dom) {
-		ipm.m_client = container_of(dom, struct unix_domain, h);
-		ipm.m_add_change = ipm.m_client->addr_changes;
-	} else
-		set_bit(CACHE_NEGATIVE, &ipm.h.flags);
-	ipm.h.expiry_time = expiry;
 
-	ipmp = ip_map_lookup(&ipm, 1);
-	if (ipmp)
-		ip_map_put(&ipmp->h, &ip_map_cache);
+	ipmp = ip_map_lookup(class,addr);
+	if (ipmp) {
+		err = ip_map_update(ipmp,
+			     container_of(dom, struct unix_domain, h),
+			     expiry);
+	} else
+		err = -ENOMEM;
+
 	if (dom)
 		auth_domain_put(dom);
-	if (!ipmp)
-		return -ENOMEM;
+
 	cache_flush();
-	return 0;
+	return err;
 }
 
 static int ip_map_show(struct seq_file *m,
@@ -262,32 +268,70 @@
 	.cache_request	= ip_map_request,
 	.cache_parse	= ip_map_parse,
 	.cache_show	= ip_map_show,
+	.match		= ip_map_match,
+	.init		= ip_map_init,
+	.update		= update,
+	.alloc		= ip_map_alloc,
 };
 
-static DefineSimpleCacheLookup(ip_map, 0)
+static struct ip_map *ip_map_lookup(char *class, struct in_addr addr)
+{
+	struct ip_map ip;
+	struct cache_head *ch;
 
+	strcpy(ip.m_class, class);
+	ip.m_addr = addr;
+	ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
+				 hash_str(class, IP_HASHBITS) ^
+				 hash_ip((unsigned long)addr.s_addr));
+
+	if (ch)
+		return container_of(ch, struct ip_map, h);
+	else
+		return NULL;
+}
+
+static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry)
+{
+	struct ip_map ip;
+	struct cache_head *ch;
+
+	ip.m_client = udom;
+	ip.h.flags = 0;
+	if (!udom)
+		set_bit(CACHE_NEGATIVE, &ip.h.flags);
+	else {
+		ip.m_add_change = udom->addr_changes;
+		/* if this is from the legacy set_client system call,
+		 * we need m_add_change to be one higher
+		 */
+		if (expiry == NEVER)
+			ip.m_add_change++;
+	}
+	ip.h.expiry_time = expiry;
+	ch = sunrpc_cache_update(&ip_map_cache,
+				 &ip.h, &ipm->h,
+				 hash_str(ipm->m_class, IP_HASHBITS) ^
+				 hash_ip((unsigned long)ipm->m_addr.s_addr));
+	if (!ch)
+		return -ENOMEM;
+	cache_put(ch, &ip_map_cache);
+	return 0;
+}
 
 int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
 {
 	struct unix_domain *udom;
-	struct ip_map ip, *ipmp;
+	struct ip_map *ipmp;
 
-	if (dom->flavour != RPC_AUTH_UNIX)
+	if (dom->flavour != &svcauth_unix)
 		return -EINVAL;
 	udom = container_of(dom, struct unix_domain, h);
-	strcpy(ip.m_class, "nfsd");
-	ip.m_addr = addr;
-	ip.m_client = udom;
-	ip.m_add_change = udom->addr_changes+1;
-	ip.h.flags = 0;
-	ip.h.expiry_time = NEVER;
-	
-	ipmp = ip_map_lookup(&ip, 1);
+	ipmp = ip_map_lookup("nfsd", addr);
 
-	if (ipmp) {
-		ip_map_put(&ipmp->h, &ip_map_cache);
-		return 0;
-	} else
+	if (ipmp)
+		return ip_map_update(ipmp, udom, NEVER);
+	else
 		return -ENOMEM;
 }
 
@@ -295,7 +339,7 @@
 {
 	struct unix_domain *udom;
 	
-	if (dom->flavour != RPC_AUTH_UNIX)
+	if (dom->flavour != &svcauth_unix)
 		return -EINVAL;
 	udom = container_of(dom, struct unix_domain, h);
 	udom->addr_changes++;
@@ -310,7 +354,7 @@
 	strcpy(key.m_class, "nfsd");
 	key.m_addr = addr;
 
-	ipm = ip_map_lookup(&key, 0);
+	ipm = ip_map_lookup("nfsd", addr);
 
 	if (!ipm)
 		return NULL;
@@ -323,31 +367,28 @@
 		rv = NULL;
 	} else {
 		rv = &ipm->m_client->h;
-		cache_get(&rv->h);
+		kref_get(&rv->ref);
 	}
-	ip_map_put(&ipm->h, &ip_map_cache);
+	cache_put(&ipm->h, &ip_map_cache);
 	return rv;
 }
 
 void svcauth_unix_purge(void)
 {
 	cache_purge(&ip_map_cache);
-	cache_purge(&auth_domain_cache);
 }
 
 static int
 svcauth_unix_set_client(struct svc_rqst *rqstp)
 {
-	struct ip_map key, *ipm;
+	struct ip_map *ipm;
 
 	rqstp->rq_client = NULL;
 	if (rqstp->rq_proc == 0)
 		return SVC_OK;
 
-	strcpy(key.m_class, rqstp->rq_server->sv_program->pg_class);
-	key.m_addr = rqstp->rq_addr.sin_addr;
-
-	ipm = ip_map_lookup(&key, 0);
+	ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
+			    rqstp->rq_addr.sin_addr);
 
 	if (ipm == NULL)
 		return SVC_DENIED;
@@ -361,8 +402,8 @@
 			return SVC_DENIED;
 		case 0:
 			rqstp->rq_client = &ipm->m_client->h;
-			cache_get(&rqstp->rq_client->h);
-			ip_map_put(&ipm->h, &ip_map_cache);
+			kref_get(&rqstp->rq_client->ref);
+			cache_put(&ipm->h, &ip_map_cache);
 			break;
 	}
 	return SVC_OK;
diff --git a/sound/core/init.c b/sound/core/init.c
index ad68761..5bb8a8b 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -223,7 +223,8 @@
 	struct snd_monitor_file *mfile;
 	struct file *file;
 	struct snd_shutdown_f_ops *s_f_ops;
-	struct file_operations *f_ops, *old_f_ops;
+	struct file_operations *f_ops;
+	const struct file_operations *old_f_ops;
 	int err;
 
 	spin_lock(&card->files_lock);
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 6b7a367..87b47c9 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -631,7 +631,8 @@
 		return -EINVAL;
 	}
 	if (params->buffer_size != runtime->buffer_size) {
-		if ((newbuf = (char *) kmalloc(params->buffer_size, GFP_KERNEL)) == NULL)
+		newbuf = kmalloc(params->buffer_size, GFP_KERNEL);
+		if (!newbuf)
 			return -ENOMEM;
 		kfree(runtime->buffer);
 		runtime->buffer = newbuf;
@@ -657,7 +658,8 @@
 		return -EINVAL;
 	}
 	if (params->buffer_size != runtime->buffer_size) {
-		if ((newbuf = (char *) kmalloc(params->buffer_size, GFP_KERNEL)) == NULL)
+		newbuf = kmalloc(params->buffer_size, GFP_KERNEL);
+		if (!newbuf)
 			return -ENOMEM;
 		kfree(runtime->buffer);
 		runtime->buffer = newbuf;
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 4d28e52..108e430 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -137,7 +137,7 @@
 {
 	unsigned int minor = iminor(inode);
 	struct snd_minor *mptr = NULL;
-	struct file_operations *old_fops;
+	const struct file_operations *old_fops;
 	int err = 0;
 
 	if (minor >= ARRAY_SIZE(snd_minors))
@@ -240,7 +240,7 @@
  * Retrurns zero if successful, or a negative error code on failure.
  */
 int snd_register_device(int type, struct snd_card *card, int dev,
-			struct file_operations *f_ops, void *private_data,
+			const struct file_operations *f_ops, void *private_data,
 			const char *name)
 {
 	int minor;
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index 4023d3b..9055c6d 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -95,7 +95,7 @@
 }
 
 int snd_register_oss_device(int type, struct snd_card *card, int dev,
-			    struct file_operations *f_ops, void *private_data,
+			    const struct file_operations *f_ops, void *private_data,
 			    const char *name)
 {
 	int minor = snd_oss_kernel_minor(type, card, dev);
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
index 9d10d79..9ea3059 100644
--- a/sound/drivers/mpu401/mpu401.c
+++ b/sound/drivers/mpu401/mpu401.c
@@ -59,7 +59,8 @@
 MODULE_PARM_DESC(irq, "IRQ # for MPU-401 device.");
 
 static struct platform_device *platform_devices[SNDRV_CARDS];
-static int pnp_registered = 0;
+static int pnp_registered;
+static unsigned int snd_mpu401_devices;
 
 static int snd_mpu401_create(int dev, struct snd_card **rcard)
 {
@@ -197,6 +198,7 @@
 		}
 		snd_card_set_dev(card, &pnp_dev->dev);
 		pnp_set_drvdata(pnp_dev, card);
+		snd_mpu401_devices++;
 		++dev;
 		return 0;
 	}
@@ -234,12 +236,11 @@
 
 static int __init alsa_card_mpu401_init(void)
 {
-	int i, err, devices;
+	int i, err;
 
 	if ((err = platform_driver_register(&snd_mpu401_driver)) < 0)
 		return err;
 
-	devices = 0;
 	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
 		if (! enable[i])
@@ -255,14 +256,13 @@
 			goto errout;
 		}
 		platform_devices[i] = device;
-		devices++;
+		snd_mpu401_devices++;
 	}
-	if ((err = pnp_register_driver(&snd_mpu401_pnp_driver)) >= 0) {
+	err = pnp_register_driver(&snd_mpu401_pnp_driver);
+	if (!err)
 		pnp_registered = 1;
-		devices += err;
-	}
 
-	if (!devices) {
+	if (!snd_mpu401_devices) {
 #ifdef MODULE
 		printk(KERN_ERR "MPU-401 device not found or device busy\n");
 #endif
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index 7051f77..31f299a 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -262,6 +262,8 @@
 	return 0;
 }
 
+static unsigned int __devinitdata ad1816a_devices;
+
 static int __devinit snd_ad1816a_pnp_detect(struct pnp_card_link *card,
 					    const struct pnp_card_device_id *id)
 {
@@ -275,6 +277,7 @@
 		if (res < 0)
 			return res;
 		dev++;
+		ad1816a_devices++;
 		return 0;
 	}
         return -ENODEV;
@@ -297,10 +300,13 @@
 
 static int __init alsa_card_ad1816a_init(void)
 {
-	int cards;
+	int err;
 
-	cards = pnp_register_card_driver(&ad1816a_pnpc_driver);
-	if (cards <= 0) {
+	err = pnp_register_card_driver(&ad1816a_pnpc_driver);
+	if (err)
+		return err;
+
+	if (!ad1816a_devices) {
 		pnp_unregister_card_driver(&ad1816a_pnpc_driver);
 #ifdef MODULE
 		printk(KERN_ERR "no AD1816A based soundcards found.\n");
diff --git a/sound/isa/als100.c b/sound/isa/als100.c
index 9b77c17..a52bd8a 100644
--- a/sound/isa/als100.c
+++ b/sound/isa/als100.c
@@ -199,7 +199,7 @@
 	return 0;
 }
 
-static int __init snd_card_als100_probe(int dev,
+static int __devinit snd_card_als100_probe(int dev,
 					struct pnp_card_link *pcard,
 					const struct pnp_card_device_id *pid)
 {
@@ -281,6 +281,8 @@
 	return 0;
 }
 
+static unsigned int __devinitdata als100_devices;
+
 static int __devinit snd_als100_pnp_detect(struct pnp_card_link *card,
 					   const struct pnp_card_device_id *id)
 {
@@ -294,6 +296,7 @@
 		if (res < 0)
 			return res;
 		dev++;
+		als100_devices++;
 		return 0;
 	}
 	return -ENODEV;
@@ -345,10 +348,13 @@
 
 static int __init alsa_card_als100_init(void)
 {
-	int cards;
+	int err;
 
-	cards = pnp_register_card_driver(&als100_pnpc_driver);
-	if (cards <= 0) {
+	err = pnp_register_card_driver(&als100_pnpc_driver);
+	if (err)
+		return err;
+
+	if (!als100_devices) {
 		pnp_unregister_card_driver(&als100_pnpc_driver);
 #ifdef MODULE
 		snd_printk(KERN_ERR "no ALS100 based soundcards found\n");
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c
index a530691..15e5928 100644
--- a/sound/isa/azt2320.c
+++ b/sound/isa/azt2320.c
@@ -310,6 +310,8 @@
 	return 0;
 }
 
+static unsigned int __devinitdata azt2320_devices;
+
 static int __devinit snd_azt2320_pnp_detect(struct pnp_card_link *card,
 					    const struct pnp_card_device_id *id)
 {
@@ -323,6 +325,7 @@
 		if (res < 0)
 			return res;
 		dev++;
+		azt2320_devices++;
 		return 0;
 	}
         return -ENODEV;
@@ -372,10 +375,13 @@
 
 static int __init alsa_card_azt2320_init(void)
 {
-	int cards;
+	int err;
 
-	cards = pnp_register_card_driver(&azt2320_pnpc_driver);
-	if (cards <= 0) {
+	err = pnp_register_card_driver(&azt2320_pnpc_driver);
+	if (err)
+		return err;
+
+	if (!azt2320_devices) {
 		pnp_unregister_card_driver(&azt2320_pnpc_driver);
 #ifdef MODULE
 		snd_printk(KERN_ERR "no AZT2320 based soundcards found\n");
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index fd9bb25..fa63048 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -175,7 +175,7 @@
 #endif
 
 
-static struct ad1848_mix_elem snd_cmi8330_controls[] __initdata = {
+static struct ad1848_mix_elem snd_cmi8330_controls[] __devinitdata = {
 AD1848_DOUBLE("Master Playback Volume", 0, CMI8330_MASTVOL, CMI8330_MASTVOL, 4, 0, 15, 0),
 AD1848_SINGLE("Loud Playback Switch", 0, CMI8330_MUTEMUX, 6, 1, 1),
 AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
@@ -204,7 +204,7 @@
 };
 
 #ifdef ENABLE_SB_MIXER
-static struct sbmix_elem cmi8330_sb_mixers[] __initdata = {
+static struct sbmix_elem cmi8330_sb_mixers[] __devinitdata = {
 SB_DOUBLE("SB Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31),
 SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15),
 SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15),
@@ -222,7 +222,7 @@
 SB_SINGLE("SB Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1),
 };
 
-static unsigned char cmi8330_sb_init_values[][2] __initdata = {
+static unsigned char cmi8330_sb_init_values[][2] __devinitdata = {
 	{ SB_DSP4_MASTER_DEV + 0, 0 },
 	{ SB_DSP4_MASTER_DEV + 1, 0 },
 	{ SB_DSP4_PCM_DEV + 0, 0 },
@@ -545,7 +545,7 @@
 	return snd_card_register(card);
 }
 
-static int __init snd_cmi8330_nonpnp_probe(struct platform_device *pdev)
+static int __devinit snd_cmi8330_nonpnp_probe(struct platform_device *pdev)
 {
 	struct snd_card *card;
 	int err;
@@ -607,6 +607,8 @@
 
 
 #ifdef CONFIG_PNP
+static unsigned int __devinitdata cmi8330_pnp_devices;
+
 static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *pcard,
 					    const struct pnp_card_device_id *pid)
 {
@@ -636,6 +638,7 @@
 	}
 	pnp_set_card_drvdata(pcard, card);
 	dev++;
+	cmi8330_pnp_devices++;
 	return 0;
 }
 
@@ -706,9 +709,9 @@
 
 #ifdef CONFIG_PNP
 	err = pnp_register_card_driver(&cmi8330_pnpc_driver);
-	if (err >= 0) {
+	if (!err) {
 		pnp_registered = 1;
-		cards += err;
+		cards += cmi8330_pnp_devices;
 	}
 #endif
 
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index 4060918..382bb17 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -133,6 +133,7 @@
 static int pnp_registered;
 #endif
 #endif /* CONFIG_PNP */
+static unsigned int snd_cs423x_devices;
 
 struct snd_card_cs4236 {
 	struct snd_cs4231 *chip;
@@ -564,7 +565,7 @@
 		snd_card_free(card);
 		return err;
 	}
-	
+
 	platform_set_drvdata(pdev, card);
 	return 0;
 }
@@ -650,6 +651,7 @@
 	}
 	pnp_set_drvdata(pdev, card);
 	dev++;
+	snd_cs423x_devices++;
 	return 0;
 }
 
@@ -713,6 +715,7 @@
 	}
 	pnp_set_card_drvdata(pcard, card);
 	dev++;
+	snd_cs423x_devices++;
 	return 0;
 }
 
@@ -721,7 +724,7 @@
 	snd_card_free(pnp_get_card_drvdata(pcard));
 	pnp_set_card_drvdata(pcard, NULL);
 }
-                        
+
 #ifdef CONFIG_PM
 static int snd_cs423x_pnpc_suspend(struct pnp_card_link *pcard, pm_message_t state)
 {
@@ -766,7 +769,7 @@
 
 static int __init alsa_card_cs423x_init(void)
 {
-	int i, err, cards = 0;
+	int i, err;
 
 	if ((err = platform_driver_register(&cs423x_nonpnp_driver)) < 0)
 		return err;
@@ -782,24 +785,20 @@
 			goto errout;
 		}
 		platform_devices[i] = device;
-		cards++;
+		snd_cs423x_devices++;
 	}
 #ifdef CONFIG_PNP
 #ifdef CS4232
-	i = pnp_register_driver(&cs4232_pnp_driver);
-	if (i >= 0) {
+	err = pnp_register_driver(&cs4232_pnp_driver);
+	if (!err)
 		pnp_registered = 1;
-		cards += i;
-	}
 #endif
-	i = pnp_register_card_driver(&cs423x_pnpc_driver);
-	if (i >= 0) {
+	err = pnp_register_card_driver(&cs423x_pnpc_driver);
+	if (!err)
 		pnpc_registered = 1;
-		cards += i;
-	}
 #endif /* CONFIG_PNP */
 
-	if (!cards) {
+	if (!snd_cs423x_devices) {
 #ifdef MODULE
 		printk(KERN_ERR IDENT " soundcard not found or device busy\n");
 #endif
diff --git a/sound/isa/dt019x.c b/sound/isa/dt019x.c
index 50e7bc5..0acb4e5 100644
--- a/sound/isa/dt019x.c
+++ b/sound/isa/dt019x.c
@@ -272,6 +272,8 @@
 	return 0;
 }
 
+static unsigned int __devinitdata dt019x_devices;
+
 static int __devinit snd_dt019x_pnp_probe(struct pnp_card_link *card,
 					  const struct pnp_card_device_id *pid)
 {
@@ -285,6 +287,7 @@
 		if (res < 0)
 			return res;
 		dev++;
+		dt019x_devices++;
 		return 0;
 	}
 	return -ENODEV;
@@ -336,10 +339,13 @@
 
 static int __init alsa_card_dt019x_init(void)
 {
-	int cards = 0;
+	int err;
 
-	cards = pnp_register_card_driver(&dt019x_pnpc_driver);
-	if (cards <= 0) {
+	err = pnp_register_card_driver(&dt019x_pnpc_driver);
+	if (err)
+		return err;
+
+	if (!dt019x_devices) {
 		pnp_unregister_card_driver(&dt019x_pnpc_driver);
 #ifdef MODULE
 		snd_printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n");
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 721955d..9fbc185 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -2204,7 +2204,7 @@
 	return snd_card_register(card);
 }
 
-static int __init snd_es18xx_nonpnp_probe1(int dev, struct platform_device *devptr)
+static int __devinit snd_es18xx_nonpnp_probe1(int dev, struct platform_device *devptr)
 {
 	struct snd_card *card;
 	int err;
@@ -2221,7 +2221,7 @@
 	return 0;
 }
 
-static int __init snd_es18xx_nonpnp_probe(struct platform_device *pdev)
+static int __devinit snd_es18xx_nonpnp_probe(struct platform_device *pdev)
 {
 	int dev = pdev->id;
 	int err;
@@ -2297,6 +2297,8 @@
 
 
 #ifdef CONFIG_PNP
+static unsigned int __devinitdata es18xx_pnp_devices;
+
 static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard,
 					       const struct pnp_card_device_id *pid)
 {
@@ -2327,6 +2329,7 @@
 
 	pnp_set_card_drvdata(pcard, card);
 	dev++;
+	es18xx_pnp_devices++;
 	return 0;
 }
 
@@ -2397,10 +2400,10 @@
 	}
 
 #ifdef CONFIG_PNP
-	i = pnp_register_card_driver(&es18xx_pnpc_driver);
-	if (i >= 0) {
+	err = pnp_register_card_driver(&es18xx_pnpc_driver);
+	if (!err) {
 		pnp_registered = 1;
-		cards += i;
+		cards += es18xx_pnp_devices;
 	}
 #endif
 
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index 2cacd0f..de71b7a 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -791,7 +791,7 @@
 	return 0;
 }
 
-static int __init snd_interwave_nonpnp_probe1(int dev, struct platform_device *devptr)
+static int __devinit snd_interwave_nonpnp_probe1(int dev, struct platform_device *devptr)
 {
 	struct snd_card *card;
 	int err;
@@ -809,7 +809,7 @@
 	return 0;
 }
 
-static int __init snd_interwave_nonpnp_probe(struct platform_device *pdev)
+static int __devinit snd_interwave_nonpnp_probe(struct platform_device *pdev)
 {
 	int dev = pdev->id;
 	int err;
@@ -867,6 +867,7 @@
 };
 
 #ifdef CONFIG_PNP
+static unsigned int __devinitdata interwave_pnp_devices;
 
 static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *pcard,
 					      const struct pnp_card_device_id *pid)
@@ -897,6 +898,7 @@
 	}
 	pnp_set_card_drvdata(pcard, card);
 	dev++;
+	interwave_pnp_devices++;
 	return 0;
 }
 
@@ -954,10 +956,10 @@
 	}
 
 	/* ISA PnP cards */
-	i = pnp_register_card_driver(&interwave_pnpc_driver);
-	if (i >= 0) {
+	err = pnp_register_card_driver(&interwave_pnpc_driver);
+	if (!err) {
 		pnp_registered = 1;
-		cards += i;
+		cards += interwave_pnp_devices;;
 	}
 
 	if (!cards) {
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 56fcd8a..c906e20 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -95,6 +95,7 @@
 static int pnp_registered;
 static int pnpc_registered;
 #endif
+static unsigned int snd_opl3sa2_devices;
 
 /* control ports */
 #define OPL3SA2_PM_CTRL		0x01
@@ -760,6 +761,7 @@
 	}
 	pnp_set_drvdata(pdev, card);
 	dev++;
+	snd_opl3sa2_devices++;
 	return 0;
 }
 
@@ -826,6 +828,7 @@
 	}
 	pnp_set_card_drvdata(pcard, card);
 	dev++;
+	snd_opl3sa2_devices++;
 	return 0;
 }
 
@@ -944,7 +947,7 @@
 
 static int __init alsa_card_opl3sa2_init(void)
 {
-	int i, err, cards = 0;
+	int i, err;
 
 	if ((err = platform_driver_register(&snd_opl3sa2_nonpnp_driver)) < 0)
 		return err;
@@ -964,23 +967,19 @@
 			goto errout;
 		}
 		platform_devices[i] = device;
-		cards++;
+		snd_opl3sa2_devices++;
 	}
 
 #ifdef CONFIG_PNP
 	err = pnp_register_driver(&opl3sa2_pnp_driver);
-	if (err >= 0) {
+	if (!err)
 		pnp_registered = 1;
-		cards += err;
-	}
 	err = pnp_register_card_driver(&opl3sa2_pnpc_driver);
-	if (err >= 0) {
+	if (!err)
 		pnpc_registered = 1;
-		cards += err;
-	}
 #endif
 
-	if (!cards) {
+	if (!snd_opl3sa2_devices) {
 #ifdef MODULE
 		snd_printk(KERN_ERR "Yamaha OPL3-SA soundcard not found or device busy\n");
 #endif
diff --git a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c
index 9da80bf..d4d65b8 100644
--- a/sound/isa/sb/es968.c
+++ b/sound/isa/sb/es968.c
@@ -124,7 +124,7 @@
 	return 0;
 }
 
-static int __init snd_card_es968_probe(int dev,
+static int __devinit snd_card_es968_probe(int dev,
 					struct pnp_card_link *pcard,
 					const struct pnp_card_device_id *pid)
 {
@@ -182,6 +182,8 @@
 	return 0;
 }
 
+static unsigned int __devinitdata es968_devices;
+
 static int __devinit snd_es968_pnp_detect(struct pnp_card_link *card,
                                           const struct pnp_card_device_id *id)
 {
@@ -195,6 +197,7 @@
 		if (res < 0)
 			return res;
 		dev++;
+		es968_devices++;
 		return 0;
 	}
 	return -ENODEV;
@@ -246,8 +249,11 @@
 
 static int __init alsa_card_es968_init(void)
 {
-	int cards = pnp_register_card_driver(&es968_pnpc_driver);
-	if (cards <= 0) {
+	int err = pnp_register_card_driver(&es968_pnpc_driver);
+	if (err)
+		return err;
+
+	if (!es968_devices) {
 		pnp_unregister_card_driver(&es968_pnpc_driver);
 #ifdef MODULE
 		snd_printk(KERN_ERR "no ES968 based soundcards found\n");
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
index 5737ab7..21ea659 100644
--- a/sound/isa/sb/sb16.c
+++ b/sound/isa/sb/sb16.c
@@ -369,7 +369,7 @@
 	return card;
 }
 
-static int __init snd_sb16_probe(struct snd_card *card, int dev)
+static int __devinit snd_sb16_probe(struct snd_card *card, int dev)
 {
 	int xirq, xdma8, xdma16;
 	struct snd_sb *chip;
@@ -518,7 +518,7 @@
 }
 #endif
 
-static int __init snd_sb16_nonpnp_probe1(int dev, struct platform_device *devptr)
+static int __devinit snd_sb16_nonpnp_probe1(int dev, struct platform_device *devptr)
 {
 	struct snd_card_sb16 *acard;
 	struct snd_card *card;
@@ -548,7 +548,7 @@
 }
 
 
-static int __init snd_sb16_nonpnp_probe(struct platform_device *pdev)
+static int __devinit snd_sb16_nonpnp_probe(struct platform_device *pdev)
 {
 	int dev = pdev->id;
 	int err;
@@ -629,6 +629,7 @@
 
 
 #ifdef CONFIG_PNP
+static unsigned int __devinitdata sb16_pnp_devices;
 
 static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *pcard,
 					 const struct pnp_card_device_id *pid)
@@ -651,6 +652,7 @@
 		}
 		pnp_set_card_drvdata(pcard, card);
 		dev++;
+		sb16_pnp_devices++;
 		return 0;
 	}
 
@@ -727,10 +729,10 @@
 	}
 #ifdef CONFIG_PNP
 	/* PnP cards at last */
-	i = pnp_register_card_driver(&sb16_pnpc_driver);
-	if (i >= 0) {
+	err = pnp_register_card_driver(&sb16_pnpc_driver);
+	if (!err) {
 		pnp_registered = 1;
-		cards += i;
+		cards += sb16_pnp_devices;
 	}
 #endif
 
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 29bba8c..48e5552 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -1255,7 +1255,7 @@
 }
 
 
-static int __init snd_sscape_probe(struct platform_device *pdev)
+static int __devinit snd_sscape_probe(struct platform_device *pdev)
 {
 	int dev = pdev->id;
 	struct snd_card *card;
@@ -1469,7 +1469,7 @@
 	if (ret < 0)
 		return ret;
 #ifdef CONFIG_PNP
-	if (pnp_register_card_driver(&sscape_pnpc_driver) >= 0)
+	if (pnp_register_card_driver(&sscape_pnpc_driver) == 0)
 		pnp_registered = 1;
 #endif
 	return 0;
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index c0115bf..2f13cd5 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -589,7 +589,7 @@
 	return snd_card_register(card);
 }	
 
-static int __init snd_wavefront_nonpnp_probe(struct platform_device *pdev)
+static int __devinit snd_wavefront_nonpnp_probe(struct platform_device *pdev)
 {
 	int dev = pdev->id;
 	struct snd_card *card;
@@ -637,6 +637,7 @@
 
 
 #ifdef CONFIG_PNP
+static unsigned int __devinitdata wavefront_pnp_devices;
 
 static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
                                               const struct pnp_card_device_id *pid)
@@ -670,6 +671,7 @@
 
 	pnp_set_card_drvdata(pcard, card);
 	dev++;
+	wavefront_pnp_devices++;
 	return 0;
 }
 
@@ -729,10 +731,10 @@
 	}
 
 #ifdef CONFIG_PNP
-	i = pnp_register_card_driver(&wavefront_pnpc_driver);
-	if (i >= 0) {
+	err = pnp_register_card_driver(&wavefront_pnpc_driver);
+	if (!err) {
 		pnp_registered = 1;
-		cards += i;
+		cards += wavefront_pnp_devices;
 	}
 #endif
 
diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c
index 1fbd513..de60a05 100644
--- a/sound/oss/cmpci.c
+++ b/sound/oss/cmpci.c
@@ -1713,7 +1713,7 @@
 	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
 		if (get_user(val, p))
 			return -EFAULT;
-		i = generic_hweight32(val);
+		i = hweight32(val);
 		for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
 			if (!(val & (1 << i)))
 				continue;
diff --git a/sound/oss/cs4232.c b/sound/oss/cs4232.c
index 7c59e2d..c7f86f0 100644
--- a/sound/oss/cs4232.c
+++ b/sound/oss/cs4232.c
@@ -360,6 +360,8 @@
 static int __initdata synthirq	= -1;
 static int __initdata isapnp	= 1;
 
+static unsigned int cs4232_devices;
+
 MODULE_DESCRIPTION("CS4232 based soundcard driver"); 
 MODULE_AUTHOR("Hannu Savolainen, Paul Barton-Davis"); 
 MODULE_LICENSE("GPL");
@@ -421,6 +423,7 @@
 		return -ENODEV;
 	}
 	pnp_set_drvdata(dev,isapnpcfg);
+	cs4232_devices++;
 	return 0;
 }
 
@@ -455,10 +458,11 @@
 #endif
 	cfg.irq = -1;
 
-	if (isapnp &&
-	    (pnp_register_driver(&cs4232_driver) > 0)
-	)
-		return 0;
+	if (isapnp) {
+		pnp_register_driver(&cs4232_driver);
+		if (cs4232_devices)
+			return 0;
+	}
 
 	if(io==-1||irq==-1||dma==-1)
 	{
@@ -503,7 +507,8 @@
 	int ints[7];
 
 	/* If we have isapnp cards, no need for options */
-	if (pnp_register_driver(&cs4232_driver) > 0)
+	pnp_register_driver(&cs4232_driver);
+	if (cs4232_devices)
 		return 1;
 	
 	str = get_options(str, ARRAY_SIZE(ints), ints);
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
index 6ba8d6f..c8e2103 100644
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ b/sound/oss/dmasound/dmasound_awacs.c
@@ -2798,7 +2798,7 @@
 			DBDMA_ALIGN(beep_dbdma_cmd_space);
 	/* set up emergency dbdma cmd */
 	emergency_dbdma_cmd = beep_dbdma_cmd+1 ;
-	beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
+	beep_buf = kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
 	if (beep_buf == NULL) {
 		printk(KERN_ERR "dmasound_pmac: no memory for beep buffer\n");
 		kfree(beep_dbdma_cmd_space) ;
@@ -2814,7 +2814,7 @@
 	struct device_node *io = NULL, *info = NULL;
 	int vol, res;
 
-	if (_machine != _MACH_Pmac)
+	if (!machine_is(powermac))
 		return -ENODEV;
 
 	awacs_subframe = 0;
diff --git a/sound/oss/emu10k1/midi.c b/sound/oss/emu10k1/midi.c
index 959a967..25ae8e4 100644
--- a/sound/oss/emu10k1/midi.c
+++ b/sound/oss/emu10k1/midi.c
@@ -65,7 +65,8 @@
 
 	init_midi_hdr(midihdr);
 
-	if ((midihdr->data = (u8 *) kmalloc(MIDIIN_BUFLEN, GFP_KERNEL)) == NULL) {
+	midihdr->data = kmalloc(MIDIIN_BUFLEN, GFP_KERNEL);
+	if (!midihdr->data) {
 		ERROR();
 		kfree(midihdr);
 		return -1;
@@ -334,7 +335,8 @@
 	midihdr->bytesrecorded = 0;
 	midihdr->flags = 0;
 
-	if ((midihdr->data = (u8 *) kmalloc(count, GFP_KERNEL)) == NULL) {
+	midihdr->data = kmalloc(count, GFP_KERNEL);
+	if (!midihdr->data) {
 		ERROR();
 		kfree(midihdr);
 		return -EINVAL;
@@ -545,7 +547,8 @@
 	midihdr->bytesrecorded = 0;
 	midihdr->flags = 0;
 
-	if ((midihdr->data = (u8 *) kmalloc(1, GFP_KERNEL)) == NULL) {
+	midihdr->data = kmalloc(1, GFP_KERNEL);
+	if (!midihdr->data) {
 		ERROR();
 		kfree(midihdr);
 		return -EINVAL;
diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c
index 78d3e29..6861563 100644
--- a/sound/oss/esssolo1.c
+++ b/sound/oss/esssolo1.c
@@ -2348,7 +2348,7 @@
 	/* Recording requires 24-bit DMA, so attempt to set dma mask
 	 * to 24 bits first, then 32 bits (playback only) if that fails.
 	 */
-	if (pci_set_dma_mask(pcidev, 0x00ffffff) &&
+	if (pci_set_dma_mask(pcidev, DMA_24BIT_MASK) &&
 	    pci_set_dma_mask(pcidev, DMA_32BIT_MASK)) {
 		printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n");
 		return -ENODEV;
diff --git a/sound/oss/maestro3.c b/sound/oss/maestro3.c
index 66044af..4a5e423 100644
--- a/sound/oss/maestro3.c
+++ b/sound/oss/maestro3.c
@@ -2582,15 +2582,9 @@
 
     return 0;
 }
-static void free_dsp_suspendmem(struct m3_card *card)
-{
-   if(card->suspend_mem)
-       vfree(card->suspend_mem);
-}
 
 #else
 #define alloc_dsp_suspendmem(args...) 0
-#define free_dsp_suspendmem(args...) 
 #endif
 
 /*
@@ -2717,7 +2711,7 @@
     if(ret) {
         if(card->iobase)
             release_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0));
-        free_dsp_suspendmem(card);
+        vfree(card->suspend_mem);
         if(card->ac97) {
             unregister_sound_mixer(card->ac97->dev_mixer);
             kfree(card->ac97);
@@ -2760,7 +2754,7 @@
         }
 
         release_region(card->iobase, 256);
-        free_dsp_suspendmem(card);
+        vfree(card->suspend_mem);
         kfree(card);
     }
     devs = NULL;
diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c
index a7ad2b0..5dbfc0f 100644
--- a/sound/oss/msnd.c
+++ b/sound/oss/msnd.c
@@ -95,10 +95,8 @@
 
 void msnd_fifo_free(msnd_fifo *f)
 {
-	if (f->data) {
-		vfree(f->data);
-		f->data = NULL;
-	}
+	vfree(f->data);
+	f->data = NULL;
 }
 
 int msnd_fifo_alloc(msnd_fifo *f, size_t n)
diff --git a/sound/oss/sb_card.c b/sound/oss/sb_card.c
index 680b82e..4708cbd 100644
--- a/sound/oss/sb_card.c
+++ b/sound/oss/sb_card.c
@@ -52,6 +52,7 @@
 static struct sb_card_config *legacy = NULL;
 
 #ifdef CONFIG_PNP
+static int pnp_registered;
 static int __initdata pnp       = 1;
 /*
 static int __initdata uart401	= 0;
@@ -133,7 +134,7 @@
 }
 
 /* Register legacy card with OSS subsystem */
-static int sb_init_legacy(void)
+static int __init sb_init_legacy(void)
 {
 	struct sb_module_options sbmo = {0};
 
@@ -234,6 +235,8 @@
 	}
 }
 
+static unsigned int sb_pnp_devices;
+
 /* Probe callback function for the PnP API */
 static int sb_pnp_probe(struct pnp_card_link *card, const struct pnp_card_device_id *card_id)
 {
@@ -264,6 +267,7 @@
 	       scc->conf.dma, scc->conf.dma2);
 
 	pnp_set_card_drvdata(card, scc);
+	sb_pnp_devices++;
 
 	return sb_register_oss(scc, &sbmo);
 }
@@ -289,6 +293,14 @@
 MODULE_DEVICE_TABLE(pnp_card, sb_pnp_card_table);
 #endif /* CONFIG_PNP */
 
+static void __init_or_module sb_unregister_all(void)
+{
+#ifdef CONFIG_PNP
+	if (pnp_registered)
+		pnp_unregister_card_driver(&sb_pnp_driver);
+#endif
+}
+
 static int __init sb_init(void)
 {
 	int lres = 0;
@@ -307,17 +319,18 @@
 
 #ifdef CONFIG_PNP
 	if(pnp) {
-		pres = pnp_register_card_driver(&sb_pnp_driver);
+		int err = pnp_register_card_driver(&sb_pnp_driver);
+		if (!err)
+			pnp_registered = 1;
+		pres = sb_pnp_devices;
 	}
 #endif
 	printk(KERN_INFO "sb: Init: Done\n");
 
 	/* If either PnP or Legacy registered a card then return
 	 * success */
-	if (pres <= 0 && lres <= 0) {
-#ifdef CONFIG_PNP
-		pnp_unregister_card_driver(&sb_pnp_driver);
-#endif
+	if (pres == 0 && lres <= 0) {
+		sb_unregister_all();
 		return -ENODEV;
 	}
 	return 0;
@@ -333,14 +346,10 @@
 		sb_unload(legacy);
 	}
 
-#ifdef CONFIG_PNP
-	pnp_unregister_card_driver(&sb_pnp_driver);
-#endif
+	sb_unregister_all();
 
-	if (smw_free) {
-		vfree(smw_free);
-		smw_free = NULL;
-	}
+	vfree(smw_free);
+	smw_free = NULL;
 }
 
 module_init(sb_init);
diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c
index 347cd79..6815c30 100644
--- a/sound/oss/sequencer.c
+++ b/sound/oss/sequencer.c
@@ -1671,14 +1671,7 @@
 
 void sequencer_unload(void)
 {
-	if(queue)
-	{
-		vfree(queue);
-		queue=NULL;
-	}
-	if(iqueue)
-	{
-		vfree(iqueue);
-		iqueue=NULL;
-	}
+	vfree(queue);
+	vfree(iqueue);
+	queue = iqueue = NULL;
 }
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c
index 8a9917c..3f7427c 100644
--- a/sound/oss/sh_dac_audio.c
+++ b/sound/oss/sh_dac_audio.c
@@ -289,7 +289,7 @@
 
 	in_use = 0;
 
-	data_buffer = (char *)kmalloc(BUFFER_SIZE, GFP_KERNEL);
+	data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
 	if (data_buffer == NULL)
 		return -ENOMEM;
 
diff --git a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c
index 69a4b87..42bd276 100644
--- a/sound/oss/sonicvibes.c
+++ b/sound/oss/sonicvibes.c
@@ -116,6 +116,7 @@
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
 #include <linux/gameport.h>
+#include <linux/dma-mapping.h>
 #include <linux/mutex.h>
 
 
@@ -407,24 +408,6 @@
 	return r;
 }
 
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#ifdef hweight32
-#undef hweight32
-#endif
-
-static inline unsigned int hweight32(unsigned int w)
-{
-        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
-        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
-        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
-        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
-        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
-}
-
 /* --------------------------------------------------------------------- */
 
 /*
@@ -2553,7 +2536,7 @@
 		return -ENODEV;
 	if (pcidev->irq == 0)
 		return -ENODEV;
-	if (pci_set_dma_mask(pcidev, 0x00ffffff)) {
+	if (pci_set_dma_mask(pcidev, DMA_24BIT_MASK)) {
 		printk(KERN_WARNING "sonicvibes: architecture does not support 24bit PCI busmaster DMA\n");
 		return -ENODEV;
 	}
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c
index b372e88..5f140c7 100644
--- a/sound/oss/vwsnd.c
+++ b/sound/oss/vwsnd.c
@@ -248,27 +248,6 @@
 } lithium_t;
 
 /*
- * li_create initializes the lithium_t structure and sets up vm mappings
- * to access the registers.
- * Returns 0 on success, -errno on failure.
- */
-
-static int __init li_create(lithium_t *lith, unsigned long baseaddr)
-{
-	static void li_destroy(lithium_t *);
-
-	spin_lock_init(&lith->lock);
-	lith->page0 = ioremap_nocache(baseaddr + LI_PAGE0_OFFSET, PAGE_SIZE);
-	lith->page1 = ioremap_nocache(baseaddr + LI_PAGE1_OFFSET, PAGE_SIZE);
-	lith->page2 = ioremap_nocache(baseaddr + LI_PAGE2_OFFSET, PAGE_SIZE);
-	if (!lith->page0 || !lith->page1 || !lith->page2) {
-		li_destroy(lith);
-		return -ENOMEM;
-	}
-	return 0;
-}
-
-/*
  * li_destroy destroys the lithium_t structure and vm mappings.
  */
 
@@ -289,6 +268,25 @@
 }
 
 /*
+ * li_create initializes the lithium_t structure and sets up vm mappings
+ * to access the registers.
+ * Returns 0 on success, -errno on failure.
+ */
+
+static int __init li_create(lithium_t *lith, unsigned long baseaddr)
+{
+	spin_lock_init(&lith->lock);
+	lith->page0 = ioremap_nocache(baseaddr + LI_PAGE0_OFFSET, PAGE_SIZE);
+	lith->page1 = ioremap_nocache(baseaddr + LI_PAGE1_OFFSET, PAGE_SIZE);
+	lith->page2 = ioremap_nocache(baseaddr + LI_PAGE2_OFFSET, PAGE_SIZE);
+	if (!lith->page0 || !lith->page1 || !lith->page2) {
+		li_destroy(lith);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+/*
  * basic register accessors - read/write long/byte
  */
 
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index 2aa5a7f..c6c8333 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -39,6 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/compiler.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 
 #include <sound/driver.h>
 #include <sound/core.h>
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index e264136..fc92b68 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -33,6 +33,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/info.h>
@@ -2220,8 +2221,8 @@
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
 	/* check, if we can restrict PCI DMA transfers to 31 bits */
-	if (pci_set_dma_mask(pci, 0x7fffffff) < 0 ||
-	    pci_set_consistent_dma_mask(pci, 0x7fffffff) < 0) {
+	if (pci_set_dma_mask(pci, DMA_31BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_31BIT_MASK) < 0) {
 		snd_printk(KERN_ERR "architecture does not support 31bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
 		return -ENXIO;
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 7b2ff5f..100d812 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -70,6 +70,7 @@
 #include <linux/slab.h>
 #include <linux/gameport.h>
 #include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/rawmidi.h>
@@ -688,8 +689,8 @@
 		return err;
 	}
 	/* check, if we can restrict PCI DMA transfers to 24 bits */
-	if (pci_set_dma_mask(pci, 0x00ffffff) < 0 ||
-	    pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) {
+	if (pci_set_dma_mask(pci, DMA_24BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_24BIT_MASK) < 0) {
 		snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
 		return -ENXIO;
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index e077eb3..680077e 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -104,6 +104,7 @@
 #include <linux/slab.h>
 #include <linux/gameport.h>
 #include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -1669,8 +1670,8 @@
 	chip->irq = -1;
 
 	/* check if we can restrict PCI DMA transfers to 24 bits */
-	if (pci_set_dma_mask(pci, 0x00ffffff) < 0 ||
-	    pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) {
+	if (pci_set_dma_mask(pci, DMA_24BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_24BIT_MASK) < 0) {
 		snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n");
 		err = -ENXIO;
 		goto out_err;
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 2208dbd..3e332f3 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -36,6 +36,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 0d556b0..4d62fe4 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -55,6 +55,7 @@
 #include <linux/gameport.h>
 #include <linux/moduleparam.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -1517,8 +1518,8 @@
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
         /* check, if we can restrict PCI DMA transfers to 24 bits */
-	if (pci_set_dma_mask(pci, 0x00ffffff) < 0 ||
-	    pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) {
+	if (pci_set_dma_mask(pci, DMA_24BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_24BIT_MASK) < 0) {
 		snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
                 return -ENXIO;
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index dd465a1..e3ad17f 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -104,6 +104,7 @@
 #include <linux/slab.h>
 #include <linux/gameport.h>
 #include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
 #include <linux/mutex.h>
 
 #include <sound/core.h>
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 672e198..b88eeba 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -56,7 +56,9 @@
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
 #include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/cs8427.h>
 #include <sound/info.h>
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 8bc0849..44393e1 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -41,6 +41,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 43ee3b2..b5a0950 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -28,6 +28,8 @@
 #include <linux/dma-mapping.h>
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
+#include <linux/dma-mapping.h>
+
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/info.h>
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index f679779..35875c8 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -30,6 +30,7 @@
 #include <linux/delay.h>
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
+#include <linux/dma-mapping.h>
 
 #include <sound/core.h>
 #include <sound/initval.h>
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index 0cbef5f..ab78544 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -313,7 +313,7 @@
 }
 
 /*
- * SPDIF I/O capabilites (half-duplex mode)
+ * SPDIF I/O capabilities (half-duplex mode)
  */
 static struct snd_pcm_hardware snd_rme32_spdif_info = {
 	.info =		(SNDRV_PCM_INFO_MMAP_IOMEM |
@@ -339,7 +339,7 @@
 };
 
 /*
- * ADAT I/O capabilites (half-duplex mode)
+ * ADAT I/O capabilities (half-duplex mode)
  */
 static struct snd_pcm_hardware snd_rme32_adat_info =
 {
@@ -364,7 +364,7 @@
 };
 
 /*
- * SPDIF I/O capabilites (full-duplex mode)
+ * SPDIF I/O capabilities (full-duplex mode)
  */
 static struct snd_pcm_hardware snd_rme32_spdif_fd_info = {
 	.info =		(SNDRV_PCM_INFO_MMAP |
@@ -390,7 +390,7 @@
 };
 
 /*
- * ADAT I/O capabilites (full-duplex mode)
+ * ADAT I/O capabilities (full-duplex mode)
  */
 static struct snd_pcm_hardware snd_rme32_adat_fd_info =
 {
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 0e694b0..6c2a9f4 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -359,7 +359,7 @@
 }
 
 /*
- * Digital output capabilites (S/PDIF)
+ * Digital output capabilities (S/PDIF)
  */
 static struct snd_pcm_hardware snd_rme96_playback_spdif_info =
 {
@@ -388,7 +388,7 @@
 };
 
 /*
- * Digital input capabilites (S/PDIF)
+ * Digital input capabilities (S/PDIF)
  */
 static struct snd_pcm_hardware snd_rme96_capture_spdif_info =
 {
@@ -417,7 +417,7 @@
 };
 
 /*
- * Digital output capabilites (ADAT)
+ * Digital output capabilities (ADAT)
  */
 static struct snd_pcm_hardware snd_rme96_playback_adat_info =
 {
@@ -442,7 +442,7 @@
 };
 
 /*
- * Digital input capabilites (ADAT)
+ * Digital input capabilities (ADAT)
  */
 static struct snd_pcm_hardware snd_rme96_capture_adat_info =
 {
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 980b9cd..b5538ef 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -2256,7 +2256,7 @@
 	}
 
 	/* Channel playback mixer as default control 
-	   Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats to big for any alsamixer 
+	   Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer
 	   they are accesible via special IOCTL on hwdep
 	   and the mixer 2dimensional mixer control */
 
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 7bbea37..2d66a09 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/gameport.h>
 #include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -1227,8 +1228,8 @@
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
 	/* check, if we can restrict PCI DMA transfers to 24 bits */
-        if (pci_set_dma_mask(pci, 0x00ffffff) < 0 ||
-	    pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) {
+        if (pci_set_dma_mask(pci, DMA_24BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_24BIT_MASK) < 0) {
 		snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
                 return -ENXIO;
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 83b7d8a..52178b8 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/gameport.h>
+#include <linux/dma-mapping.h>
 
 #include <sound/core.h>
 #include <sound/info.h>
@@ -3554,8 +3555,8 @@
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
 	/* check, if we can restrict PCI DMA transfers to 30 bits */
-	if (pci_set_dma_mask(pci, 0x3fffffff) < 0 ||
-	    pci_set_consistent_dma_mask(pci, 0x3fffffff) < 0) {
+	if (pci_set_dma_mask(pci, DMA_30BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_30BIT_MASK) < 0) {
 		snd_printk(KERN_ERR "architecture does not support 30bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
 		return -ENXIO;
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index aa57170..f0794ef 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -869,7 +869,7 @@
 
 	u32 layout_id = 0;
 
-	if (_machine != _MACH_Pmac)
+	if (!machine_is(powermac))
 		return -ENODEV;
 
 	chip->subframe = 0;
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 394b53e..6f84972 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -53,7 +53,7 @@
 struct sound_unit
 {
 	int unit_minor;
-	struct file_operations *unit_fops;
+	const struct file_operations *unit_fops;
 	struct sound_unit *next;
 	char name[32];
 };
@@ -73,7 +73,7 @@
  *	join into it. Called with the lock asserted
  */
 
-static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, struct file_operations *fops, int index, int low, int top)
+static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, const struct file_operations *fops, int index, int low, int top)
 {
 	int n=low;
 
@@ -153,7 +153,7 @@
  *	list. Acquires locks as needed
  */
 
-static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode, struct device *dev)
+static int sound_insert_unit(struct sound_unit **list, const struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode, struct device *dev)
 {
 	struct sound_unit *s = kmalloc(sizeof(*s), GFP_KERNEL);
 	int r;
@@ -237,7 +237,7 @@
  *	a negative error code is returned.
  */
  
-int register_sound_special_device(struct file_operations *fops, int unit,
+int register_sound_special_device(const struct file_operations *fops, int unit,
 				  struct device *dev)
 {
 	const int chain = unit % SOUND_STEP;
@@ -301,7 +301,7 @@
  
 EXPORT_SYMBOL(register_sound_special_device);
 
-int register_sound_special(struct file_operations *fops, int unit)
+int register_sound_special(const struct file_operations *fops, int unit)
 {
 	return register_sound_special_device(fops, unit, NULL);
 }
@@ -318,7 +318,7 @@
  *	number is returned, on failure a negative error code is returned.
  */
 
-int register_sound_mixer(struct file_operations *fops, int dev)
+int register_sound_mixer(const struct file_operations *fops, int dev)
 {
 	return sound_insert_unit(&chains[0], fops, dev, 0, 128,
 				 "mixer", S_IRUSR | S_IWUSR, NULL);
@@ -336,7 +336,7 @@
  *	number is returned, on failure a negative error code is returned.
  */
 
-int register_sound_midi(struct file_operations *fops, int dev)
+int register_sound_midi(const struct file_operations *fops, int dev)
 {
 	return sound_insert_unit(&chains[2], fops, dev, 2, 130,
 				 "midi", S_IRUSR | S_IWUSR, NULL);
@@ -362,7 +362,7 @@
  *	and will always allocate them as a matching pair - eg dsp3/audio3
  */
 
-int register_sound_dsp(struct file_operations *fops, int dev)
+int register_sound_dsp(const struct file_operations *fops, int dev)
 {
 	return sound_insert_unit(&chains[3], fops, dev, 3, 131,
 				 "dsp", S_IWUSR | S_IRUSR, NULL);
@@ -381,7 +381,7 @@
  */
 
 
-int register_sound_synth(struct file_operations *fops, int dev)
+int register_sound_synth(const struct file_operations *fops, int dev)
 {
 	return sound_insert_unit(&chains[9], fops, dev, 9, 137,
 				 "synth", S_IRUSR | S_IWUSR, NULL);
@@ -501,7 +501,7 @@
 	int chain;
 	int unit = iminor(inode);
 	struct sound_unit *s;
-	struct file_operations *new_fops = NULL;
+	const struct file_operations *new_fops = NULL;
 
 	chain=unit&0x0F;
 	if(chain==4 || chain==5)	/* dsp/audio/dsp16 */
@@ -540,7 +540,7 @@
 		 * switching ->f_op in the first place.
 		 */
 		int err = 0;
-		struct file_operations *old_fops = file->f_op;
+		const struct file_operations *old_fops = file->f_op;
 		file->f_op = new_fops;
 		spin_unlock(&sound_loader_lock);
 		if(file->f_op->open)
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index 3158550..fe67a92 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -404,7 +404,7 @@
 	struct usX2Ydev * usX2Y = subs->usX2Y;
 	usX2Y->prepare_subs = subs;
 	subs->urb[0]->start_frame = -1;
-	smp_wmb();	// Make shure above modifications are seen by i_usX2Y_subs_startup()
+	smp_wmb();	// Make sure above modifications are seen by i_usX2Y_subs_startup()
 	usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
 }